Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:04:57

0001 //
0002 //
0003 
0004 #include "DataFormats/PatCandidates/interface/Jet.h"
0005 #include "DataFormats/RecoCandidate/interface/RecoCaloTowerCandidate.h"
0006 #include "DataFormats/ParticleFlowCandidate/interface/PFCandidate.h"
0007 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0008 
0009 using namespace pat;
0010 
0011 /// default constructor
0012 Jet::Jet()
0013     : PATObject<reco::Jet>(reco::Jet()), embeddedCaloTowers_(false), embeddedPFCandidates_(false), jetCharge_(0.) {}
0014 
0015 /// constructor from a reco::Jet
0016 Jet::Jet(const reco::Jet& aJet)
0017     : PATObject<reco::Jet>(aJet), embeddedCaloTowers_(false), embeddedPFCandidates_(false), jetCharge_(0.0) {
0018   tryImportSpecific(aJet);
0019 }
0020 
0021 /// constructor from ref to reco::Jet
0022 Jet::Jet(const edm::Ptr<reco::Jet>& aJetRef)
0023     : PATObject<reco::Jet>(aJetRef), embeddedCaloTowers_(false), embeddedPFCandidates_(false), jetCharge_(0.0) {
0024   tryImportSpecific(*aJetRef);
0025 }
0026 
0027 /// constructor from ref to reco::Jet
0028 Jet::Jet(const edm::RefToBase<reco::Jet>& aJetRef)
0029     : PATObject<reco::Jet>(aJetRef), embeddedCaloTowers_(false), embeddedPFCandidates_(false), jetCharge_(0.0) {
0030   tryImportSpecific(*aJetRef);
0031 }
0032 
0033 /// constructure from ref to pat::Jet
0034 Jet::Jet(const edm::RefToBase<pat::Jet>& aJetRef) : Jet(*aJetRef) {
0035   refToOrig_ = edm::Ptr<reco::Candidate>(aJetRef.id(), aJetRef.get(), aJetRef.key());
0036 }
0037 
0038 /// constructure from ref to pat::Jet
0039 Jet::Jet(const edm::Ptr<pat::Jet>& aJetRef) : Jet(*aJetRef) { refToOrig_ = aJetRef; }
0040 
0041 std::ostream& reco::operator<<(std::ostream& out, const pat::Jet& obj) {
0042   if (!out)
0043     return out;
0044 
0045   out << "\tpat::Jet: ";
0046   out << std::setiosflags(std::ios::right);
0047   out << std::setiosflags(std::ios::fixed);
0048   out << std::setprecision(3);
0049   out << " E/pT/eta/phi " << obj.energy() << "/" << obj.pt() << "/" << obj.eta() << "/" << obj.phi();
0050   return out;
0051 }
0052 
0053 /// constructor helper that tries to import the specific info from the source jet
0054 void Jet::tryImportSpecific(const reco::Jet& source) {
0055   const std::type_info& type = typeid(source);
0056   if (type == typeid(reco::CaloJet)) {
0057     specificCalo_.push_back((static_cast<const reco::CaloJet&>(source)).getSpecific());
0058   } else if (type == typeid(reco::JPTJet)) {
0059     reco::JPTJet const& jptJet = static_cast<reco::JPTJet const&>(source);
0060     specificJPT_.push_back(jptJet.getSpecific());
0061     reco::CaloJet const* caloJet = nullptr;
0062     if (jptJet.getCaloJetRef().isNonnull() && jptJet.getCaloJetRef().isAvailable()) {
0063       caloJet = dynamic_cast<reco::CaloJet const*>(jptJet.getCaloJetRef().get());
0064     }
0065     if (caloJet != nullptr) {
0066       specificCalo_.push_back(caloJet->getSpecific());
0067     } else {
0068       edm::LogWarning("OptionalProductNotFound")
0069           << " in pat::Jet, Attempted to add Calo Specifics to JPT Jets, but failed."
0070           << " Jet ID for JPT Jets will not be available for you." << std::endl;
0071     }
0072   } else if (type == typeid(reco::PFJet)) {
0073     specificPF_.push_back((static_cast<const reco::PFJet&>(source)).getSpecific());
0074   }
0075 }
0076 
0077 /// destructor
0078 Jet::~Jet() {}
0079 
0080 /// ============= CaloJet methods ============
0081 
0082 CaloTowerPtr Jet::getCaloConstituent(unsigned fIndex) const {
0083   if (embeddedCaloTowers_) {
0084     // Refactorized PAT access
0085     if (!caloTowersFwdPtr_.empty()) {
0086       return (fIndex < caloTowersFwdPtr_.size() ? caloTowersFwdPtr_[fIndex].ptr() : CaloTowerPtr());
0087     }
0088     // Compatibility PAT access
0089     else {
0090       if (!caloTowers_.empty()) {
0091         return (fIndex < caloTowers_.size() ? CaloTowerPtr(&caloTowers_, fIndex) : CaloTowerPtr());
0092       }
0093     }
0094   }
0095   // Non-embedded access
0096   else {
0097     Constituent dau = daughterPtr(fIndex);
0098     const CaloTower* caloTower = dynamic_cast<const CaloTower*>(dau.get());
0099     if (caloTower != nullptr) {
0100       return CaloTowerPtr(dau.id(), caloTower, dau.key());
0101     } else {
0102       throw cms::Exception("Invalid Constituent") << "CaloJet constituent is not of CaloTower type";
0103     }
0104   }
0105 
0106   return CaloTowerPtr();
0107 }
0108 
0109 std::vector<CaloTowerPtr> const& Jet::getCaloConstituents() const {
0110   if (!caloTowersTemp_.isSet() || !caloTowers_.empty())
0111     cacheCaloTowers();
0112   return *caloTowersTemp_;
0113 }
0114 
0115 /// ============= PFJet methods ============
0116 
0117 reco::PFCandidatePtr Jet::getPFConstituent(unsigned fIndex) const {
0118   if (embeddedPFCandidates_) {
0119     // Refactorized PAT access
0120     if (!pfCandidatesFwdPtr_.empty()) {
0121       return (fIndex < pfCandidatesFwdPtr_.size() ? pfCandidatesFwdPtr_[fIndex].ptr() : reco::PFCandidatePtr());
0122     }
0123     // Compatibility PAT access
0124     else {
0125       if (!pfCandidates_.empty()) {
0126         return (fIndex < pfCandidates_.size() ? reco::PFCandidatePtr(&pfCandidates_, fIndex) : reco::PFCandidatePtr());
0127       }
0128     }
0129   }
0130   // Non-embedded access
0131   else {
0132     Constituent dau = daughterPtr(fIndex);
0133     const reco::PFCandidate* pfCandidate = dynamic_cast<const reco::PFCandidate*>(dau.get());
0134     if (pfCandidate) {
0135       return reco::PFCandidatePtr(dau.id(), pfCandidate, dau.key());
0136     } else {
0137       throw cms::Exception("Invalid Constituent") << "PFJet constituent is not of PFCandidate type";
0138     }
0139   }
0140 
0141   return reco::PFCandidatePtr();
0142 }
0143 
0144 std::vector<reco::PFCandidatePtr> const& Jet::getPFConstituents() const {
0145   if (!pfCandidatesTemp_.isSet() || !pfCandidates_.empty())
0146     cachePFCandidates();
0147   return *pfCandidatesTemp_;
0148 }
0149 
0150 const reco::Candidate* Jet::daughter(size_t i) const {
0151   if (isCaloJet() || isJPTJet()) {
0152     if (embeddedCaloTowers_) {
0153       if (!caloTowersFwdPtr_.empty())
0154         return caloTowersFwdPtr_[i].get();
0155       else if (!caloTowers_.empty())
0156         return &caloTowers_[i];
0157       else
0158         return reco::Jet::daughter(i);
0159     }
0160   }
0161   if (isPFJet()) {
0162     if (embeddedPFCandidates_) {
0163       if (!pfCandidatesFwdPtr_.empty())
0164         return pfCandidatesFwdPtr_[i].get();
0165       else if (!pfCandidates_.empty())
0166         return &pfCandidates_[i];
0167       else
0168         return reco::Jet::daughter(i);
0169     }
0170   }
0171   if (!subjetCollections_.empty()) {
0172     if (!daughtersTemp_.isSet())
0173       cacheDaughters();
0174     return daughtersTemp_->at(i).get();
0175   }
0176   return reco::Jet::daughter(i);
0177 }
0178 
0179 reco::CandidatePtr Jet::daughterPtr(size_t i) const {
0180   if (!subjetCollections_.empty()) {
0181     if (!daughtersTemp_.isSet())
0182       cacheDaughters();
0183     return daughtersTemp_->at(i);
0184   }
0185   return reco::Jet::daughterPtr(i);
0186 }
0187 
0188 const reco::CompositePtrCandidate::daughters& Jet::daughterPtrVector() const {
0189   if (!subjetCollections_.empty()) {
0190     if (!daughtersTemp_.isSet())
0191       cacheDaughters();
0192     return *daughtersTemp_;
0193   }
0194   return reco::Jet::daughterPtrVector();
0195 }
0196 
0197 size_t Jet::numberOfDaughters() const {
0198   if (isCaloJet() || isJPTJet()) {
0199     if (embeddedCaloTowers_) {
0200       if (!caloTowersFwdPtr_.empty())
0201         return caloTowersFwdPtr_.size();
0202       else if (!caloTowers_.empty())
0203         return caloTowers_.size();
0204       else
0205         return reco::Jet::numberOfDaughters();
0206     }
0207   }
0208   if (isPFJet()) {
0209     if (embeddedPFCandidates_) {
0210       if (!pfCandidatesFwdPtr_.empty())
0211         return pfCandidatesFwdPtr_.size();
0212       else if (!pfCandidates_.empty())
0213         return pfCandidates_.size();
0214       else
0215         return reco::Jet::numberOfDaughters();
0216     }
0217   }
0218   if (!subjetCollections_.empty()) {
0219     if (!daughtersTemp_.isSet())
0220       cacheDaughters();
0221     return daughtersTemp_->size();
0222   }
0223   return reco::Jet::numberOfDaughters();
0224 }
0225 
0226 /// return the matched generated jet
0227 const reco::GenJet* Jet::genJet() const {
0228   if (!genJet_.empty())
0229     return &(genJet_.front());
0230   else if (!genJetRef_.empty())
0231     return genJetRef_[0].get();
0232   else
0233     return genJetFwdRef_.get();
0234 }
0235 
0236 /// return the parton-based flavour of the jet
0237 int Jet::partonFlavour() const { return jetFlavourInfo_.getPartonFlavour(); }
0238 
0239 /// return the hadron-based flavour of the jet
0240 int Jet::hadronFlavour() const { return jetFlavourInfo_.getHadronFlavour(); }
0241 
0242 /// return the JetFlavourInfo of the jet
0243 const reco::JetFlavourInfo& Jet::jetFlavourInfo() const { return jetFlavourInfo_; }
0244 
0245 /// ============= Jet Energy Correction methods ============
0246 
0247 /// Scale energy and correspondingly add jec factor
0248 void Jet::scaleEnergy(double fScale, const std::string& level) {
0249   if (jecSetsAvailable()) {
0250     std::vector<float> factors = {float(jec_[0].correction(0, JetCorrFactors::NONE) / fScale)};
0251     jec_[0].insertFactor(0, std::make_pair(level, factors));
0252     ++currentJECLevel_;
0253   }
0254   setP4(p4() * fScale);
0255 }
0256 
0257 // initialize the jet to a given JEC level during creation starting from Uncorrected
0258 void Jet::initializeJEC(unsigned int level, const JetCorrFactors::Flavor& flavor, unsigned int set) {
0259   currentJECSet(set);
0260   currentJECLevel(level);
0261   currentJECFlavor(flavor);
0262   setP4(jec_[set].correction(level, flavor) * p4());
0263 }
0264 
0265 /// return true if this jet carries the jet correction factors of a different set, for systematic studies
0266 int Jet::jecSet(const std::string& set) const {
0267   for (std::vector<pat::JetCorrFactors>::const_iterator corrFactor = jec_.begin(); corrFactor != jec_.end();
0268        ++corrFactor)
0269     if (corrFactor->jecSet() == set) {
0270       return (corrFactor - jec_.begin());
0271     }
0272   return -1;
0273 }
0274 
0275 /// all available label-names of all sets of jet energy corrections
0276 const std::vector<std::string> Jet::availableJECSets() const {
0277   std::vector<std::string> sets;
0278   for (std::vector<pat::JetCorrFactors>::const_iterator corrFactor = jec_.begin(); corrFactor != jec_.end();
0279        ++corrFactor)
0280     sets.push_back(corrFactor->jecSet());
0281   return sets;
0282 }
0283 
0284 const std::vector<std::string> Jet::availableJECLevels(const int& set) const {
0285   return set >= 0 ? jec_.at(set).correctionLabels() : std::vector<std::string>();
0286 }
0287 
0288 /// correction factor to the given level for a specific set
0289 /// of correction factors, starting from the current level
0290 float Jet::jecFactor(const std::string& level, const std::string& flavor, const std::string& set) const {
0291   for (unsigned int idx = 0; idx < jec_.size(); ++idx) {
0292     if (set.empty() || jec_.at(idx).jecSet() == set) {
0293       if (jec_[idx].jecLevel(level) >= 0) {
0294         return jecFactor(jec_[idx].jecLevel(level), jec_[idx].jecFlavor(flavor), idx);
0295       } else {
0296         throw cms::Exception("InvalidRequest") << "This JEC level " << level << " does not exist. \n";
0297       }
0298     }
0299   }
0300   throw cms::Exception("InvalidRequest") << "This jet does not carry any jet energy correction factor information \n"
0301                                          << "for a jet energy correction set with label " << set << "\n";
0302 }
0303 
0304 /// correction factor to the given level for a specific set
0305 /// of correction factors, starting from the current level
0306 float Jet::jecFactor(const unsigned int& level, const JetCorrFactors::Flavor& flavor, const unsigned int& set) const {
0307   if (!jecSetsAvailable()) {
0308     throw cms::Exception("InvalidRequest") << "This jet does not carry any jet energy correction factor information \n";
0309   }
0310   if (!jecSetAvailable(set)) {
0311     throw cms::Exception("InvalidRequest") << "This jet does not carry any jet energy correction factor information \n"
0312                                            << "for a jet energy correction set with index " << set << "\n";
0313   }
0314   return jec_.at(set).correction(level, flavor) /
0315          jec_.at(currentJECSet_).correction(currentJECLevel_, currentJECFlavor_);
0316 }
0317 
0318 /// copy of the jet with correction factor to target step for
0319 /// the set of correction factors, which is currently in use
0320 Jet Jet::correctedJet(const std::string& level, const std::string& flavor, const std::string& set) const {
0321   // rescale p4 of the jet; the update of current values is
0322   // done within the called jecFactor function
0323   for (unsigned int idx = 0; idx < jec_.size(); ++idx) {
0324     if (set.empty() || jec_.at(idx).jecSet() == set) {
0325       if (jec_[idx].jecLevel(level) >= 0) {
0326         return correctedJet(jec_[idx].jecLevel(level), jec_[idx].jecFlavor(flavor), idx);
0327       } else {
0328         throw cms::Exception("InvalidRequest") << "This JEC level " << level << " does not exist. \n";
0329       }
0330     }
0331   }
0332   throw cms::Exception("InvalidRequest") << "This JEC set " << set << " does not exist. \n";
0333 }
0334 
0335 /// copy of the jet with correction factor to target step for
0336 /// the set of correction factors, which is currently in use
0337 Jet Jet::correctedJet(const unsigned int& level, const JetCorrFactors::Flavor& flavor, const unsigned int& set) const {
0338   Jet correctedJet(*this);
0339   //rescale p4 of the jet
0340   correctedJet.setP4(jecFactor(level, flavor, set) * p4());
0341   // update current level, flavor and set
0342   correctedJet.currentJECSet(set);
0343   correctedJet.currentJECLevel(level);
0344   correctedJet.currentJECFlavor(flavor);
0345   return correctedJet;
0346 }
0347 
0348 /// ============= BTag information methods ============
0349 
0350 const std::vector<std::pair<std::string, float>>& Jet::getPairDiscri() const { return pairDiscriVector_; }
0351 
0352 /// get b discriminant from label name
0353 float Jet::bDiscriminator(const std::string& aLabel) const {
0354   float discriminator = -1000.;
0355   for (int i = (int(pairDiscriVector_.size()) - 1); i >= 0; i--) {
0356     if (pairDiscriVector_[i].first == aLabel) {
0357       discriminator = pairDiscriVector_[i].second;
0358       break;
0359     }
0360   }
0361   return discriminator;
0362 }
0363 
0364 const reco::BaseTagInfo* Jet::tagInfo(const std::string& label) const {
0365   for (int i = (int(tagInfoLabels_.size()) - 1); i >= 0; i--) {
0366     if (tagInfoLabels_[i] == label) {
0367       if (!tagInfosFwdPtr_.empty())
0368         return tagInfosFwdPtr_[i].get();
0369       else if (!tagInfos_.empty())
0370         return &tagInfos_[i];
0371       return nullptr;
0372     }
0373   }
0374   return nullptr;
0375 }
0376 
0377 const reco::CandIPTagInfo* Jet::tagInfoCandIP(const std::string& label) const {
0378   return tagInfoByTypeOrLabel<reco::CandIPTagInfo>(label);
0379 }
0380 
0381 const reco::TrackIPTagInfo* Jet::tagInfoTrackIP(const std::string& label) const {
0382   return tagInfoByTypeOrLabel<reco::TrackIPTagInfo>(label);
0383 }
0384 
0385 const reco::CandSoftLeptonTagInfo* Jet::tagInfoCandSoftLepton(const std::string& label) const {
0386   return tagInfoByTypeOrLabel<reco::CandSoftLeptonTagInfo>(label);
0387 }
0388 
0389 const reco::SoftLeptonTagInfo* Jet::tagInfoSoftLepton(const std::string& label) const {
0390   return tagInfoByTypeOrLabel<reco::SoftLeptonTagInfo>(label);
0391 }
0392 
0393 const reco::CandSecondaryVertexTagInfo* Jet::tagInfoCandSecondaryVertex(const std::string& label) const {
0394   return tagInfoByTypeOrLabel<reco::CandSecondaryVertexTagInfo>(label);
0395 }
0396 
0397 const reco::SecondaryVertexTagInfo* Jet::tagInfoSecondaryVertex(const std::string& label) const {
0398   return tagInfoByTypeOrLabel<reco::SecondaryVertexTagInfo>(label);
0399 }
0400 
0401 const reco::BoostedDoubleSVTagInfo* Jet::tagInfoBoostedDoubleSV(const std::string& label) const {
0402   return tagInfoByTypeOrLabel<reco::BoostedDoubleSVTagInfo>(label);
0403 }
0404 
0405 const reco::PixelClusterTagInfo* Jet::tagInfoPixelCluster(const std::string& label) const {
0406   return tagInfoByTypeOrLabel<reco::PixelClusterTagInfo>(label);
0407 }
0408 
0409 void Jet::addTagInfo(const std::string& label, const TagInfoFwdPtrCollection::value_type& info) {
0410   std::string::size_type idx = label.find("TagInfos");
0411   if (idx == std::string::npos) {
0412     tagInfoLabels_.push_back(label);
0413   } else {
0414     tagInfoLabels_.push_back(label.substr(0, idx));
0415   }
0416   tagInfosFwdPtr_.push_back(info);
0417 }
0418 
0419 /// method to return the JetCharge computed when creating the Jet
0420 float Jet::jetCharge() const { return jetCharge_; }
0421 
0422 /// method to return a vector of refs to the tracks associated to this jet
0423 const reco::TrackRefVector& Jet::associatedTracks() const { return associatedTracks_; }
0424 
0425 /// method to set the vector of refs to the tracks associated to this jet
0426 void Jet::setAssociatedTracks(const reco::TrackRefVector& tracks) { associatedTracks_ = tracks; }
0427 
0428 /// method to store the CaloJet constituents internally
0429 void Jet::setCaloTowers(const CaloTowerFwdPtrCollection& caloTowers) {
0430   caloTowersFwdPtr_.reserve(caloTowers.size());
0431   for (auto const& tower : caloTowers) {
0432     caloTowersFwdPtr_.push_back(tower);
0433   }
0434   embeddedCaloTowers_ = true;
0435   caloTowersTemp_.reset();
0436 }
0437 
0438 /// method to store the CaloJet constituents internally
0439 void Jet::setPFCandidates(const PFCandidateFwdPtrCollection& pfCandidates) {
0440   pfCandidatesFwdPtr_.reserve(pfCandidates.size());
0441   for (auto const& cand : pfCandidates) {
0442     pfCandidatesFwdPtr_.push_back(cand);
0443   }
0444   embeddedPFCandidates_ = true;
0445   pfCandidatesTemp_.reset();
0446 }
0447 
0448 /// method to set the matched generated jet reference, embedding if requested
0449 void Jet::setGenJetRef(const edm::FwdRef<reco::GenJetCollection>& gj) { genJetFwdRef_ = gj; }
0450 
0451 /// method to set the parton-based flavour of the jet
0452 void Jet::setPartonFlavour(int partonFl) { jetFlavourInfo_.setPartonFlavour(partonFl); }
0453 
0454 /// method to set the hadron-based flavour of the jet
0455 void Jet::setHadronFlavour(int hadronFl) { jetFlavourInfo_.setHadronFlavour(hadronFl); }
0456 
0457 /// method to set the JetFlavourInfo of the jet
0458 void Jet::setJetFlavourInfo(const reco::JetFlavourInfo& jetFlavourInfo) { jetFlavourInfo_ = jetFlavourInfo; }
0459 
0460 /// method to add a algolabel-discriminator pair
0461 void Jet::addBDiscriminatorPair(const std::pair<std::string, float>& thePair) { pairDiscriVector_.push_back(thePair); }
0462 
0463 /// method to set the jet charge
0464 void Jet::setJetCharge(float jetCharge) { jetCharge_ = jetCharge; }
0465 
0466 /// method to cache the constituents to allow "user-friendly" access
0467 void Jet::cacheCaloTowers() const {
0468   // Clear the cache
0469   // Here is where we've embedded constituents
0470   std::unique_ptr<std::vector<CaloTowerPtr>> caloTowersTemp{new std::vector<CaloTowerPtr>{}};
0471   if (embeddedCaloTowers_) {
0472     // Refactorized PAT access
0473     if (!caloTowersFwdPtr_.empty()) {
0474       caloTowersTemp->reserve(caloTowersFwdPtr_.size());
0475       for (CaloTowerFwdPtrVector::const_iterator ibegin = caloTowersFwdPtr_.begin(),
0476                                                  iend = caloTowersFwdPtr_.end(),
0477                                                  icalo = ibegin;
0478            icalo != iend;
0479            ++icalo) {
0480         caloTowersTemp->emplace_back(icalo->ptr());
0481       }
0482     }
0483     // Compatibility access
0484     else if (!caloTowers_.empty()) {
0485       caloTowersTemp->reserve(caloTowers_.size());
0486       for (CaloTowerCollection::const_iterator ibegin = caloTowers_.begin(), iend = caloTowers_.end(), icalo = ibegin;
0487            icalo != iend;
0488            ++icalo) {
0489         caloTowersTemp->emplace_back(&caloTowers_, icalo - ibegin);
0490       }
0491     }
0492   }
0493   // Non-embedded access
0494   else {
0495     const auto nDaughters = numberOfDaughters();
0496     caloTowersTemp->reserve(nDaughters);
0497     for (unsigned fIndex = 0; fIndex < nDaughters; ++fIndex) {
0498       Constituent const& dau = daughterPtr(fIndex);
0499       const CaloTower* caloTower = dynamic_cast<const CaloTower*>(dau.get());
0500       if (caloTower) {
0501         caloTowersTemp->emplace_back(dau.id(), caloTower, dau.key());
0502       } else {
0503         throw cms::Exception("Invalid Constituent") << "CaloJet constituent is not of CaloTower type";
0504       }
0505     }
0506   }
0507   caloTowersTemp_.set(std::move(caloTowersTemp));
0508 }
0509 
0510 /// method to cache the constituents to allow "user-friendly" access
0511 void Jet::cachePFCandidates() const {
0512   std::unique_ptr<std::vector<reco::PFCandidatePtr>> pfCandidatesTemp{new std::vector<reco::PFCandidatePtr>{}};
0513   // Here is where we've embedded constituents
0514   if (embeddedPFCandidates_) {
0515     // Refactorized PAT access
0516     if (!pfCandidatesFwdPtr_.empty()) {
0517       pfCandidatesTemp->reserve(pfCandidatesFwdPtr_.size());
0518       for (PFCandidateFwdPtrCollection::const_iterator ibegin = pfCandidatesFwdPtr_.begin(),
0519                                                        iend = pfCandidatesFwdPtr_.end(),
0520                                                        ipf = ibegin;
0521            ipf != iend;
0522            ++ipf) {
0523         pfCandidatesTemp->emplace_back(ipf->ptr());
0524       }
0525     }
0526     // Compatibility access
0527     else if (!pfCandidates_.empty()) {
0528       pfCandidatesTemp->reserve(pfCandidates_.size());
0529       for (reco::PFCandidateCollection::const_iterator ibegin = pfCandidates_.begin(),
0530                                                        iend = pfCandidates_.end(),
0531                                                        ipf = ibegin;
0532            ipf != iend;
0533            ++ipf) {
0534         pfCandidatesTemp->emplace_back(&pfCandidates_, ipf - ibegin);
0535       }
0536     }
0537   }
0538   // Non-embedded access
0539   else {
0540     const auto nDaughters = numberOfDaughters();
0541     pfCandidatesTemp->reserve(nDaughters);
0542     for (unsigned fIndex = 0; fIndex < nDaughters; ++fIndex) {
0543       Constituent const& dau = daughterPtr(fIndex);
0544       const reco::PFCandidate* pfCandidate = dynamic_cast<const reco::PFCandidate*>(dau.get());
0545       if (pfCandidate) {
0546         pfCandidatesTemp->emplace_back(dau.id(), pfCandidate, dau.key());
0547       } else {
0548         throw cms::Exception("Invalid Constituent") << "PFJet constituent is not of PFCandidate type";
0549       }
0550     }
0551   }
0552   // Set the cache
0553   pfCandidatesTemp_.set(std::move(pfCandidatesTemp));
0554 }
0555 
0556 /// method to cache the daughters to allow "user-friendly" access
0557 void Jet::cacheDaughters() const {
0558   // Jets in MiniAOD produced via JetSubstructurePacker contain a mixture of subjets and particles as daughters
0559   std::unique_ptr<std::vector<reco::CandidatePtr>> daughtersTemp{new std::vector<reco::CandidatePtr>{}};
0560   const std::vector<reco::CandidatePtr>& jdaus = reco::Jet::daughterPtrVector();
0561   for (const reco::CandidatePtr& dau : jdaus) {
0562     if (dau->isJet()) {
0563       const reco::Jet* subjet = dynamic_cast<const reco::Jet*>(&*dau);
0564       if (subjet) {
0565         const std::vector<reco::CandidatePtr>& sjdaus = subjet->daughterPtrVector();
0566         daughtersTemp->insert(daughtersTemp->end(), sjdaus.begin(), sjdaus.end());
0567       }
0568     } else
0569       daughtersTemp->push_back(dau);
0570   }
0571   daughtersTemp_.set(std::move(daughtersTemp));
0572 }
0573 
0574 /// Access to subjet list
0575 pat::JetPtrCollection const& Jet::subjets(unsigned int index) const {
0576   if (index < subjetCollections_.size())
0577     return subjetCollections_[index];
0578   else {
0579     throw cms::Exception("OutOfRange") << "Index " << index << " is out of range" << std::endl;
0580   }
0581 }
0582 
0583 /// String access to subjet list
0584 pat::JetPtrCollection const& Jet::subjets(std::string const& label) const {
0585   auto found = find(subjetLabels_.begin(), subjetLabels_.end(), label);
0586   if (found != subjetLabels_.end()) {
0587     auto index = std::distance(subjetLabels_.begin(), found);
0588     return subjetCollections_[index];
0589   } else {
0590     throw cms::Exception("SubjetsNotFound")
0591         << "Label " << label << " does not match any subjet collection" << std::endl;
0592   }
0593 }
0594 
0595 /// Add new set of subjets
0596 void Jet::addSubjets(pat::JetPtrCollection const& pieces, std::string const& label) {
0597   subjetCollections_.push_back(pieces);
0598   subjetLabels_.push_back(label);
0599 }