Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-05-18 03:27:03

0001 //
0002 //
0003 
0004 #include "DataFormats/PatCandidates/interface/Tau.h"
0005 #include "DataFormats/JetReco/interface/GenJet.h"
0006 #include "DataFormats/PatCandidates/interface/PackedCandidate.h"
0007 #include <algorithm>
0008 #include <functional>
0009 
0010 using namespace pat;
0011 using namespace std::placeholders;
0012 
0013 /// default constructor
0014 Tau::Tau()
0015     : Lepton<reco::BaseTau>(),
0016       embeddedIsolationTracks_(false),
0017       embeddedLeadTrack_(false),
0018       embeddedSignalTracks_(false),
0019       embeddedLeadPFCand_(false),
0020       embeddedLeadPFChargedHadrCand_(false),
0021       embeddedLeadPFNeutralCand_(false),
0022       embeddedSignalPFCands_(false),
0023       embeddedSignalPFChargedHadrCands_(false),
0024       embeddedSignalPFNeutralHadrCands_(false),
0025       embeddedSignalPFGammaCands_(false),
0026       embeddedIsolationPFCands_(false),
0027       embeddedIsolationPFChargedHadrCands_(false),
0028       embeddedIsolationPFNeutralHadrCands_(false),
0029       embeddedIsolationPFGammaCands_(false) {}
0030 
0031 /// constructor from reco::BaseTau
0032 Tau::Tau(const reco::BaseTau& aTau)
0033     : Lepton<reco::BaseTau>(aTau),
0034       embeddedIsolationTracks_(false),
0035       embeddedLeadTrack_(false),
0036       embeddedSignalTracks_(false),
0037       embeddedLeadPFCand_(false),
0038       embeddedLeadPFChargedHadrCand_(false),
0039       embeddedLeadPFNeutralCand_(false),
0040       embeddedSignalPFCands_(false),
0041       embeddedSignalPFChargedHadrCands_(false),
0042       embeddedSignalPFNeutralHadrCands_(false),
0043       embeddedSignalPFGammaCands_(false),
0044       embeddedIsolationPFCands_(false),
0045       embeddedIsolationPFChargedHadrCands_(false),
0046       embeddedIsolationPFNeutralHadrCands_(false),
0047       embeddedIsolationPFGammaCands_(false) {
0048   initFromBaseTau(aTau);
0049 }
0050 
0051 /// constructor from ref to reco::BaseTau
0052 Tau::Tau(const edm::RefToBase<reco::BaseTau>& aTauRef)
0053     : Lepton<reco::BaseTau>(aTauRef),
0054       embeddedIsolationTracks_(false),
0055       embeddedLeadTrack_(false),
0056       embeddedSignalTracks_(false),
0057       embeddedLeadPFCand_(false),
0058       embeddedLeadPFChargedHadrCand_(false),
0059       embeddedLeadPFNeutralCand_(false),
0060       embeddedSignalPFCands_(false),
0061       embeddedSignalPFChargedHadrCands_(false),
0062       embeddedSignalPFNeutralHadrCands_(false),
0063       embeddedSignalPFGammaCands_(false),
0064       embeddedIsolationPFCands_(false),
0065       embeddedIsolationPFChargedHadrCands_(false),
0066       embeddedIsolationPFNeutralHadrCands_(false),
0067       embeddedIsolationPFGammaCands_(false) {
0068   initFromBaseTau(*aTauRef);
0069 }
0070 
0071 /// constructor from ref to reco::BaseTau
0072 Tau::Tau(const edm::Ptr<reco::BaseTau>& aTauRef)
0073     : Lepton<reco::BaseTau>(aTauRef),
0074       embeddedIsolationTracks_(false),
0075       embeddedLeadTrack_(false),
0076       embeddedSignalTracks_(false),
0077       embeddedLeadPFCand_(false),
0078       embeddedLeadPFChargedHadrCand_(false),
0079       embeddedLeadPFNeutralCand_(false),
0080       embeddedSignalPFCands_(false),
0081       embeddedSignalPFChargedHadrCands_(false),
0082       embeddedSignalPFNeutralHadrCands_(false),
0083       embeddedSignalPFGammaCands_(false),
0084       embeddedIsolationPFCands_(false),
0085       embeddedIsolationPFChargedHadrCands_(false),
0086       embeddedIsolationPFNeutralHadrCands_(false),
0087       embeddedIsolationPFGammaCands_(false) {
0088   initFromBaseTau(*aTauRef);
0089 }
0090 
0091 void Tau::initFromBaseTau(const reco::BaseTau& aTau) {
0092   const reco::PFTau* pfTau = dynamic_cast<const reco::PFTau*>(&aTau);
0093   if (pfTau != nullptr) {
0094     // If PFTau is made from PackedCandidates, directly fill slimmed version
0095     // without PFSpecific
0096     const pat::PackedCandidate* pc = dynamic_cast<const pat::PackedCandidate*>(pfTau->leadChargedHadrCand().get());
0097     if (pc != nullptr) {
0098       for (const auto& ptr : pfTau->signalChargedHadrCands())
0099         signalChargedHadrCandPtrs_.push_back(ptr);
0100 
0101       for (const auto& ptr : pfTau->signalNeutrHadrCands())
0102         signalNeutralHadrCandPtrs_.push_back(ptr);
0103 
0104       for (const auto& ptr : pfTau->signalGammaCands())
0105         signalGammaCandPtrs_.push_back(ptr);
0106 
0107       for (const auto& ptr : pfTau->isolationChargedHadrCands())
0108         isolationChargedHadrCandPtrs_.push_back(ptr);
0109 
0110       for (const auto& ptr : pfTau->isolationNeutrHadrCands())
0111         isolationNeutralHadrCandPtrs_.push_back(ptr);
0112 
0113       for (const auto& ptr : pfTau->isolationGammaCands())
0114         isolationGammaCandPtrs_.push_back(ptr);
0115 
0116       std::vector<reco::CandidatePtr> signalLostTracks;
0117       for (const auto& chargedHadron : pfTau->signalTauChargedHadronCandidates()) {
0118         if (chargedHadron.algoIs(reco::PFRecoTauChargedHadron::kTrack) &&
0119             chargedHadron.getLostTrackCandidate().isNonnull()) {
0120           signalLostTracks.push_back(chargedHadron.getLostTrackCandidate());
0121         }
0122       }
0123       this->setSignalLostTracks(signalLostTracks);
0124     } else {
0125       pfSpecific_.push_back(pat::tau::TauPFSpecific(*pfTau));
0126     }
0127     pfEssential_.push_back(pat::tau::TauPFEssential(*pfTau));
0128   }
0129 }
0130 
0131 /// destructor
0132 Tau::~Tau() {}
0133 
0134 std::ostream& reco::operator<<(std::ostream& out, const pat::Tau& obj) {
0135   if (!out)
0136     return out;
0137 
0138   out << "\tpat::Tau: ";
0139   out << std::setiosflags(std::ios::right);
0140   out << std::setiosflags(std::ios::fixed);
0141   out << std::setprecision(3);
0142   out << " E/pT/eta/phi " << obj.energy() << "/" << obj.pt() << "/" << obj.eta() << "/" << obj.phi();
0143   return out;
0144 }
0145 
0146 /// override the reco::BaseTau::isolationTracks method, to access the internal storage of the track
0147 const reco::TrackRefVector& Tau::isolationTracks() const {
0148   if (embeddedIsolationTracks_) {
0149     if (!isolationTracksTransientRefVector_.isSet()) {
0150       std::unique_ptr<reco::TrackRefVector> trackRefVec{new reco::TrackRefVector{}};
0151       trackRefVec->reserve(isolationTracks_.size());
0152       for (unsigned int i = 0; i < isolationTracks_.size(); i++) {
0153         trackRefVec->push_back(reco::TrackRef(&isolationTracks_, i));
0154       }
0155       isolationTracksTransientRefVector_.set(std::move(trackRefVec));
0156     }
0157     return *isolationTracksTransientRefVector_;
0158   } else {
0159     return reco::BaseTau::isolationTracks();
0160   }
0161 }
0162 
0163 /// override the reco::BaseTau::track method, to access the internal storage of the track
0164 reco::TrackRef Tau::leadTrack() const {
0165   if (embeddedLeadTrack_) {
0166     return reco::TrackRef(&leadTrack_, 0);
0167   } else {
0168     return reco::BaseTau::leadTrack();
0169   }
0170 }
0171 
0172 /// override the reco::BaseTau::track method, to access the internal storage of the track
0173 const reco::TrackRefVector& Tau::signalTracks() const {
0174   if (embeddedSignalTracks_) {
0175     if (!signalTracksTransientRefVector_.isSet()) {
0176       std::unique_ptr<reco::TrackRefVector> trackRefVec{new reco::TrackRefVector{}};
0177       trackRefVec->reserve(signalTracks_.size());
0178       for (unsigned int i = 0; i < signalTracks_.size(); i++) {
0179         trackRefVec->push_back(reco::TrackRef(&signalTracks_, i));
0180       }
0181       signalTracksTransientRefVector_.set(std::move(trackRefVec));
0182     }
0183     return *signalTracksTransientRefVector_;
0184   } else {
0185     return reco::BaseTau::signalTracks();
0186   }
0187 }
0188 
0189 /// method to store the isolation tracks internally
0190 void Tau::embedIsolationTracks() {
0191   isolationTracks_.clear();
0192   reco::TrackRefVector trackRefVec = reco::BaseTau::isolationTracks();
0193   for (unsigned int i = 0; i < trackRefVec.size(); i++) {
0194     isolationTracks_.push_back(*trackRefVec.at(i));
0195   }
0196   embeddedIsolationTracks_ = true;
0197 }
0198 
0199 /// method to store the isolation tracks internally
0200 void Tau::embedLeadTrack() {
0201   leadTrack_.clear();
0202   if (reco::BaseTau::leadTrack().isNonnull()) {
0203     leadTrack_.push_back(*reco::BaseTau::leadTrack());
0204     embeddedLeadTrack_ = true;
0205   }
0206 }
0207 
0208 /// method to store the isolation tracks internally
0209 void Tau::embedSignalTracks() {
0210   signalTracks_.clear();
0211   reco::TrackRefVector trackRefVec = reco::BaseTau::signalTracks();
0212   for (unsigned int i = 0; i < trackRefVec.size(); i++) {
0213     signalTracks_.push_back(*trackRefVec.at(i));
0214   }
0215   embeddedSignalTracks_ = true;
0216 }
0217 
0218 /// method to set the matched generated jet
0219 void Tau::setGenJet(const reco::GenJetRef& gj) {
0220   genJet_.clear();
0221   genJet_.push_back(*gj);
0222 }
0223 
0224 /// return the matched generated jet
0225 const reco::GenJet* Tau::genJet() const { return (!genJet_.empty() ? &genJet_.front() : nullptr); }
0226 
0227 // method to retrieve a tau ID (or throw)
0228 float Tau::tauID(const std::string& name) const {
0229   for (std::vector<IdPair>::const_iterator it = tauIDs_.begin(), ed = tauIDs_.end(); it != ed; ++it) {
0230     if (it->first == name)
0231       return it->second;
0232   }
0233   cms::Exception ex("Key not found");
0234   ex << "pat::Tau: the ID " << name << " can't be found in this pat::Tau.\n";
0235   ex << "The available IDs are: ";
0236   for (std::vector<IdPair>::const_iterator it = tauIDs_.begin(), ed = tauIDs_.end(); it != ed; ++it) {
0237     ex << "'" << it->first << "' ";
0238   }
0239   ex << ".\n";
0240   throw ex;
0241 }
0242 // check if an ID is there
0243 bool Tau::isTauIDAvailable(const std::string& name) const {
0244   for (std::vector<IdPair>::const_iterator it = tauIDs_.begin(), ed = tauIDs_.end(); it != ed; ++it) {
0245     if (it->first == name)
0246       return true;
0247   }
0248   return false;
0249 }
0250 
0251 const pat::tau::TauPFSpecific& Tau::pfSpecific() const {
0252   if (!isPFTau())
0253     throw cms::Exception("Type Error")
0254         << "Requesting a PFTau-specific information from a pat::Tau which wasn't made from a PFTau.\n";
0255   return pfSpecific_[0];
0256 }
0257 
0258 const pat::tau::TauPFEssential& Tau::pfEssential() const {
0259   if (pfEssential_.empty())
0260     throw cms::Exception("Type Error")
0261         << "Requesting a PFTau-specific information from a pat::Tau which wasn't made from a PFTau.\n";
0262   return pfEssential_[0];
0263 }
0264 
0265 reco::Candidate::LorentzVector Tau::p4Jet() const {
0266   if (isPFTau())
0267     return reco::Candidate::LorentzVector(pfEssential().p4Jet_);
0268   throw cms::Exception("Type Error") << "Requesting a PFTau-specific information from a pat::Tau which wasn't "
0269                                         "made from a PFTau.\n";
0270 }
0271 
0272 float Tau::dxy_Sig() const {
0273   if (pfEssential().dxy_error_ != 0)
0274     return (pfEssential().dxy_ / pfEssential().dxy_error_);
0275   else
0276     return 0.;
0277 }
0278 
0279 pat::tau::TauPFEssential::CovMatrix Tau::flightLengthCov() const {
0280   pat::tau::TauPFEssential::CovMatrix cov;
0281   const pat::tau::TauPFEssential::CovMatrix& sv = secondaryVertexCov();
0282   const pat::tau::TauPFEssential::CovMatrix& pv = primaryVertexCov();
0283   for (int i = 0; i < dimension; ++i) {
0284     for (int j = 0; j < dimension; ++j) {
0285       cov(i, j) = sv(i, j) + pv(i, j);
0286     }
0287   }
0288   return cov;
0289 }
0290 
0291 float Tau::ip3d_Sig() const {
0292   if (pfEssential().ip3d_error_ != 0)
0293     return (pfEssential().ip3d_ / pfEssential().ip3d_error_);
0294   else
0295     return 0.;
0296 }
0297 
0298 float Tau::etaetaMoment() const {
0299   if (isPFTau())
0300     return pfSpecific().etaetaMoment_;
0301   throw cms::Exception("Type Error") << "Requesting a PFTau-specific information from a pat::Tau which wasn't "
0302                                         "made from a PFTau.\n";
0303 }
0304 
0305 float Tau::phiphiMoment() const {
0306   if (isPFTau())
0307     return pfSpecific().phiphiMoment_;
0308   throw cms::Exception("Type Error") << "Requesting a PFTau-specific information from a pat::Tau which wasn't "
0309                                         "made from a PFTau.\n";
0310 }
0311 
0312 float Tau::etaphiMoment() const {
0313   if (isPFTau())
0314     return pfSpecific().etaphiMoment_;
0315   throw cms::Exception("Type Error") << "Requesting a PFTau-specific information from a pat::Tau which wasn't "
0316                                         "made from a PFTau.\n";
0317 }
0318 
0319 void Tau::setDecayMode(int decayMode) {
0320   if (!isPFTau())
0321     throw cms::Exception("Type Error")
0322         << "Requesting a PFTau-specific information from a pat::Tau which wasn't made from a PFTau.\n";
0323   pfEssential_[0].decayMode_ = decayMode;
0324 }
0325 
0326 /// method to store the leading candidate internally
0327 void Tau::embedLeadPFCand() {
0328   if (!isPFTau()) {  //additional check with warning in pat::tau producer
0329     return;
0330   }
0331   leadPFCand_.clear();
0332   if (pfSpecific_[0].leadPFCand_.isNonnull()) {
0333     leadPFCand_.push_back(*static_cast<const reco::PFCandidate*>(&*pfSpecific_[0].leadPFCand_));  //already set in C-tor
0334     embeddedLeadPFCand_ = true;
0335   }
0336 }
0337 /// method to store the leading candidate internally
0338 void Tau::embedLeadPFChargedHadrCand() {
0339   if (!isPFTau()) {  //additional check with warning in pat::tau producer
0340     return;
0341   }
0342   leadPFChargedHadrCand_.clear();
0343   if (pfSpecific_[0].leadPFChargedHadrCand_.isNonnull()) {
0344     leadPFChargedHadrCand_.push_back(
0345         *static_cast<const reco::PFCandidate*>(&*pfSpecific_[0].leadPFChargedHadrCand_));  //already set in C-tor
0346     embeddedLeadPFChargedHadrCand_ = true;
0347   }
0348 }
0349 /// method to store the leading candidate internally
0350 void Tau::embedLeadPFNeutralCand() {
0351   if (!isPFTau()) {  //additional check with warning in pat::tau producer
0352     return;
0353   }
0354   leadPFNeutralCand_.clear();
0355   if (pfSpecific_[0].leadPFNeutralCand_.isNonnull()) {
0356     leadPFNeutralCand_.push_back(
0357         *static_cast<const reco::PFCandidate*>(&*pfSpecific_[0].leadPFNeutralCand_));  //already set in C-tor
0358     embeddedLeadPFNeutralCand_ = true;
0359   }
0360 }
0361 
0362 void Tau::embedSignalPFCands() {
0363   if (!isPFTau()) {  //additional check with warning in pat::tau producer
0364     return;
0365   }
0366   std::vector<reco::PFCandidatePtr> candPtrs = pfSpecific_[0].selectedSignalPFCands_;
0367   for (unsigned int i = 0; i < candPtrs.size(); i++) {
0368     signalPFCands_.push_back(candPtrs.at(i));
0369   }
0370   embeddedSignalPFCands_ = true;
0371 }
0372 void Tau::embedSignalPFChargedHadrCands() {
0373   if (!isPFTau()) {  //additional check with warning in pat::tau producer
0374     return;
0375   }
0376   std::vector<reco::PFCandidatePtr> candPtrs = pfSpecific_[0].selectedSignalPFChargedHadrCands_;
0377   for (unsigned int i = 0; i < candPtrs.size(); i++) {
0378     signalPFChargedHadrCands_.push_back(candPtrs.at(i));
0379   }
0380   embeddedSignalPFChargedHadrCands_ = true;
0381 }
0382 void Tau::embedSignalPFNeutralHadrCands() {
0383   if (!isPFTau()) {  //additional check with warning in pat::tau producer
0384     return;
0385   }
0386   std::vector<reco::PFCandidatePtr> candPtrs = pfSpecific_[0].selectedSignalPFNeutrHadrCands_;
0387   for (unsigned int i = 0; i < candPtrs.size(); i++) {
0388     signalPFNeutralHadrCands_.push_back(candPtrs.at(i));
0389   }
0390   embeddedSignalPFNeutralHadrCands_ = true;
0391 }
0392 void Tau::embedSignalPFGammaCands() {
0393   if (!isPFTau()) {  //additional check with warning in pat::tau producer
0394     return;
0395   }
0396   std::vector<reco::PFCandidatePtr> candPtrs = pfSpecific_[0].selectedSignalPFGammaCands_;
0397   for (unsigned int i = 0; i < candPtrs.size(); i++) {
0398     signalPFGammaCands_.push_back(candPtrs.at(i));
0399   }
0400   embeddedSignalPFGammaCands_ = true;
0401 }
0402 
0403 void Tau::embedIsolationPFCands() {
0404   if (!isPFTau()) {  //additional check with warning in pat::tau producer
0405     return;
0406   }
0407   std::vector<reco::PFCandidatePtr> candPtrs = pfSpecific_[0].selectedIsolationPFCands_;
0408   for (unsigned int i = 0; i < candPtrs.size(); i++) {
0409     isolationPFCands_.push_back(candPtrs.at(i));
0410   }
0411   embeddedIsolationPFCands_ = true;
0412 }
0413 
0414 void Tau::embedIsolationPFChargedHadrCands() {
0415   if (!isPFTau()) {  //additional check with warning in pat::tau producer
0416     return;
0417   }
0418   std::vector<reco::PFCandidatePtr> candPtrs = pfSpecific_[0].selectedIsolationPFChargedHadrCands_;
0419   for (unsigned int i = 0; i < candPtrs.size(); i++) {
0420     isolationPFChargedHadrCands_.push_back(candPtrs.at(i));
0421   }
0422   embeddedIsolationPFChargedHadrCands_ = true;
0423 }
0424 void Tau::embedIsolationPFNeutralHadrCands() {
0425   if (!isPFTau()) {  //additional check with warning in pat::tau producer
0426     return;
0427   }
0428   std::vector<reco::PFCandidatePtr> candPtrs = pfSpecific_[0].selectedIsolationPFNeutrHadrCands_;
0429   for (unsigned int i = 0; i < candPtrs.size(); i++) {
0430     isolationPFNeutralHadrCands_.push_back(candPtrs.at(i));
0431   }
0432   embeddedIsolationPFNeutralHadrCands_ = true;
0433 }
0434 void Tau::embedIsolationPFGammaCands() {
0435   if (!isPFTau()) {  //additional check with warning in pat::tau producer
0436     return;
0437   }
0438   std::vector<reco::PFCandidatePtr> candPtrs = pfSpecific_[0].selectedIsolationPFGammaCands_;
0439   for (unsigned int i = 0; i < candPtrs.size(); i++) {
0440     isolationPFGammaCands_.push_back(candPtrs.at(i));
0441   }
0442   embeddedIsolationPFGammaCands_ = true;
0443 }
0444 
0445 reco::PFRecoTauChargedHadronRef Tau::leadTauChargedHadronCandidate() const {
0446   if (!isPFTau())
0447     throw cms::Exception("Type Error") << "Requesting content that is not stored in miniAOD.\n";
0448   if (!pfSpecific().signalTauChargedHadronCandidates_.empty()) {
0449     return reco::PFRecoTauChargedHadronRef(&pfSpecific().signalTauChargedHadronCandidates_, 0);
0450   } else {
0451     return reco::PFRecoTauChargedHadronRef();
0452   }
0453 }
0454 
0455 const reco::PFCandidatePtr convertToPFCandidatePtr(const reco::CandidatePtr& ptr) {
0456   const reco::PFCandidate* pf_cand = dynamic_cast<const reco::PFCandidate*>(&*ptr);
0457   if (pf_cand)
0458     return edm::Ptr<reco::PFCandidate>(ptr);
0459   return reco::PFCandidatePtr();
0460 }
0461 
0462 const reco::PFCandidatePtr Tau::leadPFChargedHadrCand() const {
0463   if (!embeddedLeadPFChargedHadrCand_) {
0464     if (pfSpecific_.empty())
0465       return reco::PFCandidatePtr();
0466     else
0467       return convertToPFCandidatePtr(pfSpecific().leadPFChargedHadrCand_);
0468   } else
0469     return reco::PFCandidatePtr(&leadPFChargedHadrCand_, 0);
0470 }
0471 
0472 const reco::PFCandidatePtr Tau::leadPFNeutralCand() const {
0473   if (!embeddedLeadPFNeutralCand_) {
0474     if (pfSpecific_.empty())
0475       return reco::PFCandidatePtr();
0476     else
0477       return convertToPFCandidatePtr(pfSpecific().leadPFNeutralCand_);
0478   } else
0479     return reco::PFCandidatePtr(&leadPFNeutralCand_, 0);
0480 }
0481 
0482 const reco::PFCandidatePtr Tau::leadPFCand() const {
0483   if (!embeddedLeadPFCand_) {
0484     if (pfSpecific_.empty())
0485       return reco::PFCandidatePtr();
0486     return convertToPFCandidatePtr(pfSpecific().leadPFCand_);
0487   } else
0488     return reco::PFCandidatePtr(&leadPFCand_, 0);
0489 }
0490 
0491 const std::vector<reco::PFCandidatePtr>& Tau::signalPFCands() const {
0492   if (embeddedSignalPFCands_) {
0493     if (!signalPFCandsTransientPtrs_.isSet()) {
0494       std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0495       aPtrs->reserve(signalPFCands_.size());
0496       for (unsigned int i = 0; i < signalPFCands_.size(); i++) {
0497         aPtrs->push_back(reco::PFCandidatePtr(&signalPFCands_, i));
0498       }
0499       signalPFCandsTransientPtrs_.set(std::move(aPtrs));
0500     }
0501     return *signalPFCandsTransientPtrs_;
0502   } else {
0503     if (pfSpecific_.empty() || pfSpecific().selectedSignalPFCands_.empty() ||
0504         !pfSpecific().selectedSignalPFCands_.front().isAvailable()) {
0505       // this part of code is called when reading from patTuple or miniAOD
0506       // it returns empty collection in correct format so it can be substituted by reco::Candidates if available
0507       if (!signalPFCandsTransientPtrs_.isSet()) {
0508         std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0509         signalPFCandsTransientPtrs_.set(std::move(aPtrs));
0510       }
0511       return *signalPFCandsTransientPtrs_;
0512     } else
0513       return pfSpecific().selectedSignalPFCands_;
0514   }
0515 }
0516 
0517 const std::vector<reco::PFCandidatePtr>& Tau::signalPFChargedHadrCands() const {
0518   if (embeddedSignalPFChargedHadrCands_) {
0519     if (!signalPFChargedHadrCandsTransientPtrs_.isSet()) {
0520       std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0521       aPtrs->reserve(signalPFChargedHadrCands_.size());
0522       for (unsigned int i = 0; i < signalPFChargedHadrCands_.size(); i++) {
0523         aPtrs->push_back(reco::PFCandidatePtr(&signalPFChargedHadrCands_, i));
0524       }
0525       signalPFChargedHadrCandsTransientPtrs_.set(std::move(aPtrs));
0526     }
0527     return *signalPFChargedHadrCandsTransientPtrs_;
0528   } else {
0529     if (pfSpecific_.empty() || pfSpecific().selectedSignalPFChargedHadrCands_.empty() ||
0530         !pfSpecific().selectedSignalPFChargedHadrCands_.front().isAvailable()) {
0531       // this part of code is called when reading from patTuple or miniAOD
0532       // it returns empty collection in correct format so it can be substituted by reco::Candidates if available
0533       if (!signalPFChargedHadrCandsTransientPtrs_.isSet()) {
0534         std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0535         signalPFChargedHadrCandsTransientPtrs_.set(std::move(aPtrs));
0536       }
0537       return *signalPFChargedHadrCandsTransientPtrs_;
0538     } else
0539       return pfSpecific().selectedSignalPFChargedHadrCands_;
0540   }
0541 }
0542 
0543 const std::vector<reco::PFCandidatePtr>& Tau::signalPFNeutrHadrCands() const {
0544   if (embeddedSignalPFNeutralHadrCands_) {
0545     if (!signalPFNeutralHadrCandsTransientPtrs_.isSet()) {
0546       std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0547       aPtrs->reserve(signalPFNeutralHadrCands_.size());
0548       for (unsigned int i = 0; i < signalPFNeutralHadrCands_.size(); i++) {
0549         aPtrs->push_back(reco::PFCandidatePtr(&signalPFNeutralHadrCands_, i));
0550       }
0551       signalPFNeutralHadrCandsTransientPtrs_.set(std::move(aPtrs));
0552     }
0553     return *signalPFNeutralHadrCandsTransientPtrs_;
0554   } else {
0555     if (pfSpecific_.empty() || pfSpecific().selectedSignalPFNeutrHadrCands_.empty() ||
0556         !pfSpecific().selectedSignalPFNeutrHadrCands_.front().isAvailable()) {
0557       // this part of code is called when reading from patTuple or miniAOD
0558       // it returns empty collection in correct format so it can be substituted by reco::Candidates if available
0559       if (!signalPFNeutralHadrCandsTransientPtrs_.isSet()) {
0560         std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0561         signalPFNeutralHadrCandsTransientPtrs_.set(std::move(aPtrs));
0562       }
0563       return *signalPFNeutralHadrCandsTransientPtrs_;
0564     } else
0565       return pfSpecific().selectedSignalPFNeutrHadrCands_;
0566   }
0567 }
0568 
0569 const std::vector<reco::PFCandidatePtr>& Tau::signalPFGammaCands() const {
0570   if (embeddedSignalPFGammaCands_) {
0571     if (!signalPFGammaCandsTransientPtrs_.isSet()) {
0572       std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0573       aPtrs->reserve(signalPFGammaCands_.size());
0574       for (unsigned int i = 0; i < signalPFGammaCands_.size(); i++) {
0575         aPtrs->push_back(reco::PFCandidatePtr(&signalPFGammaCands_, i));
0576       }
0577       signalPFGammaCandsTransientPtrs_.set(std::move(aPtrs));
0578     }
0579     return *signalPFGammaCandsTransientPtrs_;
0580   } else {
0581     if (pfSpecific_.empty() || pfSpecific().selectedSignalPFGammaCands_.empty() ||
0582         !pfSpecific().selectedSignalPFGammaCands_.front().isAvailable()) {
0583       // this part of code is called when reading from patTuple or miniAOD
0584       // it returns empty collection in correct format so it can be substituted by reco::Candidates if available
0585       if (!signalPFGammaCandsTransientPtrs_.isSet()) {
0586         std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0587         signalPFGammaCandsTransientPtrs_.set(std::move(aPtrs));
0588       }
0589       return *signalPFGammaCandsTransientPtrs_;
0590     } else
0591       return pfSpecific().selectedSignalPFGammaCands_;
0592   }
0593 }
0594 
0595 const std::vector<reco::PFRecoTauChargedHadron>& Tau::signalTauChargedHadronCandidates() const {
0596   if (pfSpecific_.empty())
0597     throw cms::Exception("Type Error") << "Requesting content that is not stored in miniAOD.\n";
0598   return pfSpecific().signalTauChargedHadronCandidates_;
0599 }
0600 
0601 const std::vector<reco::RecoTauPiZero>& Tau::signalPiZeroCandidates() const {
0602   if (pfSpecific_.empty())
0603     throw cms::Exception("Type Error") << "Requesting content that is not stored in miniAOD.\n";
0604   return pfSpecific().signalPiZeroCandidates_;
0605 }
0606 
0607 const std::vector<reco::PFCandidatePtr>& Tau::isolationPFCands() const {
0608   if (embeddedIsolationPFCands_) {
0609     if (!isolationPFCandsTransientPtrs_.isSet()) {
0610       std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0611       aPtrs->reserve(isolationPFCands_.size());
0612       for (unsigned int i = 0; i < isolationPFCands_.size(); i++) {
0613         aPtrs->push_back(reco::PFCandidatePtr(&isolationPFCands_, i));
0614       }
0615       isolationPFCandsTransientPtrs_.set(std::move(aPtrs));
0616     }
0617     return *isolationPFCandsTransientPtrs_;
0618   } else {
0619     if (pfSpecific_.empty() || pfSpecific().selectedIsolationPFCands_.empty() ||
0620         !pfSpecific().selectedIsolationPFCands_.front().isAvailable()) {
0621       // this part of code is called when reading from patTuple or miniAOD
0622       // it returns empty collection in correct format so it can be substituted by reco::Candidates if available
0623       if (!isolationPFCandsTransientPtrs_.isSet()) {
0624         std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0625         isolationPFCandsTransientPtrs_.set(std::move(aPtrs));
0626       }
0627       return *isolationPFCandsTransientPtrs_;
0628     } else
0629       return pfSpecific().selectedIsolationPFCands_;
0630   }
0631 }
0632 
0633 const std::vector<reco::PFCandidatePtr>& Tau::isolationPFChargedHadrCands() const {
0634   if (embeddedIsolationPFChargedHadrCands_) {
0635     if (!isolationPFChargedHadrCandsTransientPtrs_.isSet()) {
0636       std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0637       aPtrs->reserve(isolationPFChargedHadrCands_.size());
0638       for (unsigned int i = 0; i < isolationPFChargedHadrCands_.size(); i++) {
0639         aPtrs->push_back(reco::PFCandidatePtr(&isolationPFChargedHadrCands_, i));
0640       }
0641       isolationPFChargedHadrCandsTransientPtrs_.set(std::move(aPtrs));
0642     }
0643     return *isolationPFChargedHadrCandsTransientPtrs_;
0644   } else {
0645     if (pfSpecific_.empty() || pfSpecific().selectedIsolationPFChargedHadrCands_.empty() ||
0646         !pfSpecific().selectedIsolationPFChargedHadrCands_.front().isAvailable()) {
0647       // this part of code is called when reading from patTuple or miniAOD
0648       // it returns empty collection in correct format so it can be substituted by reco::Candidates if available
0649       if (!isolationPFChargedHadrCandsTransientPtrs_.isSet()) {
0650         std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0651         isolationPFChargedHadrCandsTransientPtrs_.set(std::move(aPtrs));
0652       }
0653       return *isolationPFChargedHadrCandsTransientPtrs_;
0654     } else
0655       return pfSpecific().selectedIsolationPFChargedHadrCands_;
0656   }
0657 }
0658 
0659 const std::vector<reco::PFCandidatePtr>& Tau::isolationPFNeutrHadrCands() const {
0660   if (embeddedIsolationPFNeutralHadrCands_) {
0661     if (!isolationPFNeutralHadrCandsTransientPtrs_.isSet()) {
0662       std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0663       aPtrs->reserve(isolationPFNeutralHadrCands_.size());
0664       for (unsigned int i = 0; i < isolationPFNeutralHadrCands_.size(); i++) {
0665         aPtrs->push_back(reco::PFCandidatePtr(&isolationPFNeutralHadrCands_, i));
0666       }
0667       isolationPFNeutralHadrCandsTransientPtrs_.set(std::move(aPtrs));
0668     }
0669     return *isolationPFNeutralHadrCandsTransientPtrs_;
0670   } else {
0671     if (pfSpecific_.empty() || pfSpecific().selectedIsolationPFNeutrHadrCands_.empty() ||
0672         !pfSpecific().selectedIsolationPFNeutrHadrCands_.front().isAvailable()) {
0673       // this part of code is called when reading from patTuple or miniAOD
0674       // it returns empty collection in correct format so it can be substituted by reco::Candidates if available
0675       if (!isolationPFNeutralHadrCandsTransientPtrs_.isSet()) {
0676         std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0677         isolationPFNeutralHadrCandsTransientPtrs_.set(std::move(aPtrs));
0678       }
0679       return *isolationPFNeutralHadrCandsTransientPtrs_;
0680     } else
0681       return pfSpecific().selectedIsolationPFNeutrHadrCands_;
0682   }
0683 }
0684 
0685 const std::vector<reco::PFCandidatePtr>& Tau::isolationPFGammaCands() const {
0686   if (embeddedIsolationPFGammaCands_) {
0687     if (!isolationPFGammaCandsTransientPtrs_.isSet()) {
0688       std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0689       aPtrs->reserve(isolationPFGammaCands_.size());
0690       for (unsigned int i = 0; i < isolationPFGammaCands_.size(); i++) {
0691         aPtrs->push_back(reco::PFCandidatePtr(&isolationPFGammaCands_, i));
0692       }
0693       isolationPFGammaCandsTransientPtrs_.set(std::move(aPtrs));
0694     }
0695     return *isolationPFGammaCandsTransientPtrs_;
0696   } else {
0697     if (pfSpecific_.empty() || pfSpecific().selectedIsolationPFGammaCands_.empty() ||
0698         !pfSpecific().selectedIsolationPFGammaCands_.front().isAvailable()) {
0699       // this part of code is called when reading from patTuple or miniAOD
0700       // it returns empty collection in correct format so it can be substituted by reco::Candidates if available
0701       if (!isolationPFGammaCandsTransientPtrs_.isSet()) {
0702         std::unique_ptr<std::vector<reco::PFCandidatePtr> > aPtrs{new std::vector<reco::PFCandidatePtr>{}};
0703         isolationPFGammaCandsTransientPtrs_.set(std::move(aPtrs));
0704       }
0705       return *isolationPFGammaCandsTransientPtrs_;
0706     } else
0707       return pfSpecific().selectedIsolationPFGammaCands_;
0708   }
0709 }
0710 
0711 const std::vector<reco::PFRecoTauChargedHadron>& Tau::isolationTauChargedHadronCandidates() const {
0712   if (pfSpecific_.empty())
0713     throw cms::Exception("Type Error") << "Requesting content that is not stored in miniAOD.\n";
0714   return pfSpecific().isolationTauChargedHadronCandidates_;
0715 }
0716 
0717 const std::vector<reco::RecoTauPiZero>& Tau::isolationPiZeroCandidates() const {
0718   if (pfSpecific_.empty())
0719     throw cms::Exception("Type Error") << "Requesting content that is not stored in miniAOD.\n";
0720   return pfSpecific().isolationPiZeroCandidates_;
0721 }
0722 
0723 /// ============= -Tau-jet Energy Correction methods ============
0724 /// (copied from DataFormats/PatCandidates/src/Jet.cc)
0725 
0726 // initialize the jet to a given JEC level during creation starting from Uncorrected
0727 void Tau::initializeJEC(unsigned int level, unsigned int set) {
0728   currentJECSet(set);
0729   currentJECLevel(level);
0730   setP4(jec_[set].correction(level) * p4());
0731 }
0732 
0733 /// return true if this jet carries the jet correction factors of a different set, for systematic studies
0734 int Tau::jecSet(const std::string& set) const {
0735   for (std::vector<pat::TauJetCorrFactors>::const_iterator corrFactor = jec_.begin(); corrFactor != jec_.end();
0736        ++corrFactor) {
0737     if (corrFactor->jecSet() == set)
0738       return corrFactor - jec_.begin();
0739   }
0740   return -1;
0741 }
0742 
0743 /// all available label-names of all sets of jet energy corrections
0744 const std::vector<std::string> Tau::availableJECSets() const {
0745   std::vector<std::string> sets;
0746   for (std::vector<pat::TauJetCorrFactors>::const_iterator corrFactor = jec_.begin(); corrFactor != jec_.end();
0747        ++corrFactor) {
0748     sets.push_back(corrFactor->jecSet());
0749   }
0750   return sets;
0751 }
0752 
0753 const std::vector<std::string> Tau::availableJECLevels(const int& set) const {
0754   return set >= 0 ? jec_.at(set).correctionLabels() : std::vector<std::string>();
0755 }
0756 
0757 /// correction factor to the given level for a specific set
0758 /// of correction factors, starting from the current level
0759 float Tau::jecFactor(const std::string& level, const std::string& set) const {
0760   for (unsigned int idx = 0; idx < jec_.size(); ++idx) {
0761     if (set.empty() || jec_.at(idx).jecSet() == set) {
0762       if (jec_[idx].jecLevel(level) >= 0)
0763         return jecFactor(jec_[idx].jecLevel(level), idx);
0764       else
0765         throw cms::Exception("InvalidRequest") << "This JEC level " << level << " does not exist. \n";
0766     }
0767   }
0768   throw cms::Exception("InvalidRequest") << "This jet does not carry any jet energy correction factor information \n"
0769                                          << "for a jet energy correction set with label " << set << "\n";
0770 }
0771 
0772 /// correction factor to the given level for a specific set
0773 /// of correction factors, starting from the current level
0774 float Tau::jecFactor(const unsigned int& level, const unsigned int& set) const {
0775   if (!jecSetsAvailable())
0776     throw cms::Exception("InvalidRequest") << "This jet does not carry any jet energy correction factor information \n";
0777   if (!jecSetAvailable(set))
0778     throw cms::Exception("InvalidRequest") << "This jet does not carry any jet energy correction factor information \n"
0779                                            << "for a jet energy correction set with index " << set << "\n";
0780   return jec_.at(set).correction(level) / jec_.at(currentJECSet_).correction(currentJECLevel_);
0781 }
0782 
0783 /// copy of the jet with correction factor to target step for
0784 /// the set of correction factors, which is currently in use
0785 Tau Tau::correctedTauJet(const std::string& level, const std::string& set) const {
0786   // rescale p4 of the jet; the update of current values is
0787   // done within the called jecFactor function
0788   for (unsigned int idx = 0; idx < jec_.size(); ++idx) {
0789     if (set.empty() || jec_.at(idx).jecSet() == set) {
0790       if (jec_[idx].jecLevel(level) >= 0)
0791         return correctedTauJet(jec_[idx].jecLevel(level), idx);
0792       else
0793         throw cms::Exception("InvalidRequest") << "This JEC level " << level << " does not exist. \n";
0794     }
0795   }
0796   throw cms::Exception("InvalidRequest") << "This JEC set " << set << " does not exist. \n";
0797 }
0798 
0799 /// copy of the jet with correction factor to target step for
0800 /// the set of correction factors, which is currently in use
0801 Tau Tau::correctedTauJet(const unsigned int& level, const unsigned int& set) const {
0802   Tau correctedTauJet(*this);
0803   //rescale p4 of the jet
0804   correctedTauJet.setP4(jecFactor(level, set) * p4());
0805   // update current level and set
0806   correctedTauJet.currentJECSet(set);
0807   correctedTauJet.currentJECLevel(level);
0808   return correctedTauJet;
0809 }
0810 
0811 /// ----- Methods returning associated PFCandidates that work on PAT+AOD, PAT+embedding and miniAOD -----
0812 /// return the PFCandidate if available (reference or embedded), or the PackedPFCandidate on miniAOD
0813 // return the leading candidate from signal(PF)ChargedHadrCandPtrs_ collection
0814 const reco::CandidatePtr Tau::leadChargedHadrCand() const {
0815   const reco::PFCandidatePtr leadPF = leadPFChargedHadrCand();
0816   if (leadPF.isAvailable() || signalChargedHadrCandPtrs_.isNull())
0817     return leadPF;
0818   reco::CandidatePtr ret;
0819   for (const reco::CandidatePtr& p : signalChargedHadrCandPtrs_) {
0820     if (ret.isNull() || (p->pt() > ret->pt()))
0821       ret = p;
0822   }
0823   return ret;
0824 }
0825 
0826 /// return the PFCandidate if available (reference or embedded), or the PackedPFCandidate on miniAOD
0827 const reco::CandidatePtr Tau::leadNeutralCand() const {
0828   const reco::PFCandidatePtr leadPF = leadPFNeutralCand();
0829   if (leadPF.isAvailable() || signalNeutralHadrCandPtrs_.isNull())
0830     return leadPF;
0831   reco::CandidatePtr ret;
0832   for (const reco::CandidatePtr& p : signalNeutralHadrCandPtrs_) {
0833     if (ret.isNull() || (p->pt() > ret->pt()))
0834       ret = p;
0835   }
0836   return ret;
0837 }
0838 
0839 /// return the PFCandidate if available (reference or embedded), or the PackedPFCandidate on miniAOD
0840 const reco::CandidatePtr Tau::leadCand() const {
0841   const reco::PFCandidatePtr leadPF = leadPFCand();
0842   if (leadPF.isAvailable() || !Tau::ExistSignalCands())
0843     return leadPF;
0844   else
0845     return Tau::signalCands()[0];
0846 }
0847 
0848 /// check that there is at least one non-zero collection of candidate ptrs
0849 
0850 bool Tau::ExistSignalCands() const {
0851   return !(signalChargedHadrCandPtrs_.isNull() && signalNeutralHadrCandPtrs_.isNull() && signalGammaCandPtrs_.isNull());
0852 }
0853 
0854 bool Tau::ExistIsolationCands() const {
0855   return !(isolationChargedHadrCandPtrs_.isNull() && isolationNeutralHadrCandPtrs_.isNull() &&
0856            isolationGammaCandPtrs_.isNull());
0857 }
0858 
0859 /// return the PFCandidates if available (reference or embedded), or the PackedPFCandidate on miniAOD
0860 /// note that the vector is returned by value.
0861 
0862 reco::CandidatePtrVector Tau::signalCands() const {
0863   std::vector<reco::PFCandidatePtr> r0 = signalPFCands();
0864   reco::CandidatePtrVector ret;
0865   if (!Tau::ExistSignalCands() || (!r0.empty() && r0.front().isAvailable())) {
0866     for (const auto& p : r0)
0867       ret.push_back(p);
0868     return ret;
0869   } else {
0870     /// the isolationCands pointers are not saved in miniAOD, so the collection is created dynamically by glueing together 3 sub-collection and re-ordering
0871     reco::CandidatePtrVector ret2;
0872     std::vector<std::pair<float, size_t> > pt_index;
0873     size_t index = 0;
0874     ret2.reserve(signalChargedHadrCandPtrs_.size() + signalNeutralHadrCandPtrs_.size() + signalGammaCandPtrs_.size());
0875     pt_index.reserve(signalChargedHadrCandPtrs_.size() + signalNeutralHadrCandPtrs_.size() +
0876                      signalGammaCandPtrs_.size());
0877 
0878     for (const auto& p : signalChargedHadrCandPtrs_) {
0879       ret2.push_back(p);
0880       pt_index.push_back(std::make_pair(p->pt(), index));
0881       index++;
0882     }
0883     for (const auto& p : signalNeutralHadrCandPtrs_) {
0884       ret2.push_back(p);
0885       pt_index.push_back(std::make_pair(p->pt(), index));
0886       index++;
0887     }
0888     for (const auto& p : signalGammaCandPtrs_) {
0889       ret2.push_back(p);
0890       pt_index.push_back(std::make_pair(p->pt(), index));
0891       index++;
0892     }
0893     std::sort(pt_index.begin(), pt_index.end(), std::greater<>());
0894     ret.reserve(pt_index.size());
0895     for (const auto& p : pt_index) {
0896       ret.push_back(ret2[p.second]);
0897     }
0898     return ret;
0899   }
0900 }
0901 
0902 /// return the PFCandidates if available (reference or embedded), or the PackedPFCandidate on miniAOD
0903 /// note that the vector is returned by value.
0904 reco::CandidatePtrVector Tau::signalChargedHadrCands() const {
0905   std::vector<reco::PFCandidatePtr> r0 = signalPFChargedHadrCands();
0906   if (signalChargedHadrCandPtrs_.isNull() || (!r0.empty() && r0.front().isAvailable())) {
0907     reco::CandidatePtrVector ret;
0908     for (const auto& p : r0)
0909       ret.push_back(p);
0910     return ret;
0911   } else {
0912     return signalChargedHadrCandPtrs_;
0913   }
0914 }
0915 
0916 /// return the PFCandidates if available (reference or embedded), or the PackedPFCandidate on miniAOD
0917 /// note that the vector is returned by value.
0918 reco::CandidatePtrVector Tau::signalNeutrHadrCands() const {
0919   std::vector<reco::PFCandidatePtr> r0 = signalPFNeutrHadrCands();
0920   if (signalNeutralHadrCandPtrs_.isNull() || (!r0.empty() && r0.front().isAvailable())) {
0921     reco::CandidatePtrVector ret;
0922     for (const auto& p : r0)
0923       ret.push_back(p);
0924     return ret;
0925   } else {
0926     return signalNeutralHadrCandPtrs_;
0927   }
0928 }
0929 
0930 /// return the PFCandidates if available (reference or embedded), or the PackedPFCandidate on miniAOD
0931 /// note that the vector is returned by value.
0932 reco::CandidatePtrVector Tau::signalGammaCands() const {
0933   std::vector<reco::PFCandidatePtr> r0 = signalPFGammaCands();
0934   if (signalGammaCandPtrs_.isNull() || (!r0.empty() && r0.front().isAvailable())) {
0935     reco::CandidatePtrVector ret;
0936     for (const auto& p : r0)
0937       ret.push_back(p);
0938     return ret;
0939   } else {
0940     return signalGammaCandPtrs_;
0941   }
0942 }
0943 
0944 /// return the PFCandidates if available (reference or embedded), or the PackedPFCandidate on miniAOD
0945 /// note that the vector is returned by value.
0946 reco::CandidatePtrVector Tau::isolationCands() const {
0947   std::vector<reco::PFCandidatePtr> r0 = isolationPFCands();
0948   reco::CandidatePtrVector ret;
0949   if (!Tau::ExistIsolationCands() || (!r0.empty() && r0.front().isAvailable())) {
0950     for (const auto& p : r0)
0951       ret.push_back(p);
0952     return ret;
0953   } else {
0954     /// the isolationCands pointers are not saved in miniAOD, so the collection is created dynamically by glueing together 3 sub-collection and re-ordering
0955     reco::CandidatePtrVector ret2;
0956     std::vector<std::pair<float, size_t> > pt_index;
0957     ret2.reserve(isolationChargedHadrCandPtrs_.size() + isolationNeutralHadrCandPtrs_.size() +
0958                  isolationGammaCandPtrs_.size());
0959     pt_index.reserve(isolationChargedHadrCandPtrs_.size() + isolationNeutralHadrCandPtrs_.size() +
0960                      isolationGammaCandPtrs_.size());
0961     size_t index = 0;
0962     for (const auto& p : isolationChargedHadrCandPtrs_) {
0963       ret2.push_back(p);
0964       pt_index.push_back(std::make_pair(p->pt(), index));
0965       index++;
0966     }
0967     for (const auto& p : isolationNeutralHadrCandPtrs_) {
0968       ret2.push_back(p);
0969       pt_index.push_back(std::make_pair(p->pt(), index));
0970       index++;
0971     }
0972     for (const auto& p : isolationGammaCandPtrs_) {
0973       ret2.push_back(p);
0974       pt_index.push_back(std::make_pair(p->pt(), index));
0975       index++;
0976     }
0977     std::sort(pt_index.begin(), pt_index.end(), std::greater<>());
0978     ret.reserve(pt_index.size());
0979     for (const auto& p : pt_index) {
0980       ret.push_back(ret2[p.second]);
0981     }
0982     return ret;
0983   }
0984 }
0985 
0986 /// return the PFCandidates if available (reference or embedded), or the PackedPFCandidate on miniAOD
0987 /// note that the vector is returned by value.
0988 reco::CandidatePtrVector Tau::isolationChargedHadrCands() const {
0989   std::vector<reco::PFCandidatePtr> r0 = isolationPFChargedHadrCands();
0990   if (isolationChargedHadrCandPtrs_.isNull() || (!r0.empty() && r0.front().isAvailable())) {
0991     reco::CandidatePtrVector ret;
0992     for (const auto& p : r0)
0993       ret.push_back(p);
0994     return ret;
0995   } else {
0996     return isolationChargedHadrCandPtrs_;
0997   }
0998 }
0999 
1000 /// return the PFCandidates if available (reference or embedded), or the PackedPFCandidate on miniAOD
1001 /// note that the vector is returned by value.
1002 reco::CandidatePtrVector Tau::isolationNeutrHadrCands() const {
1003   reco::CandidatePtrVector ret;
1004   std::vector<reco::PFCandidatePtr> r0 = isolationPFNeutrHadrCands();
1005   if (isolationNeutralHadrCandPtrs_.isNull() || (!r0.empty() && r0.front().isAvailable())) {
1006     reco::CandidatePtrVector ret;
1007     for (const auto& p : r0)
1008       ret.push_back(p);
1009     return ret;
1010   } else {
1011     return isolationNeutralHadrCandPtrs_;
1012   }
1013 }
1014 
1015 /// return the PFCandidates if available (reference or embedded), or the PackedPFCandidate on miniAOD
1016 /// note that the vector is returned by value.
1017 reco::CandidatePtrVector Tau::isolationGammaCands() const {
1018   std::vector<reco::PFCandidatePtr> r0 = isolationPFGammaCands();
1019   if (isolationGammaCandPtrs_.isNull() || (!r0.empty() && r0.front().isAvailable())) {
1020     reco::CandidatePtrVector ret;
1021     for (const auto& p : r0)
1022       ret.push_back(p);
1023     return ret;
1024   } else {
1025     return isolationGammaCandPtrs_;
1026   }
1027 }
1028 
1029 std::vector<reco::CandidatePtr> Tau::signalLostTracks() const {
1030   std::vector<reco::CandidatePtr> ret;
1031   unsigned int i = 0;
1032   std::string label = "_lostTrack_" + std::to_string(i);
1033   while (this->hasUserCand(label)) {
1034     ret.push_back(userCand(label));
1035     i++;
1036     label = "_lostTrack_" + std::to_string(i);
1037   }
1038   return ret;
1039 }
1040 
1041 void Tau::setSignalLostTracks(const std::vector<reco::CandidatePtr>& ptrs) {
1042   unsigned int i = 0;
1043   for (const auto& ptr : ptrs) {
1044     std::string label = "_lostTrack_" + std::to_string(i);
1045     addUserCand(label, ptr);
1046     i++;
1047   }
1048 }
1049 
1050 /// ----- Top Projection business -------
1051 /// get the number of non-null PFCandidates
1052 size_t Tau::numberOfSourceCandidatePtrs() const {
1053   if (Tau::ExistSignalCands())
1054     return Tau::signalCands().size();
1055   else if (pfSpecific_.empty())
1056     return 0;
1057   else
1058     return pfSpecific().selectedSignalPFCands_.size();
1059 }
1060 /// get the source candidate pointer with index i
1061 reco::CandidatePtr Tau::sourceCandidatePtr(size_type i) const {
1062   if (Tau::ExistSignalCands())
1063     return Tau::signalCands()[i];
1064   else if (pfSpecific_.empty())
1065     return reco::CandidatePtr();
1066   else
1067     return pfSpecific().selectedSignalPFCands_[i];
1068 }