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
0012 Jet::Jet()
0013 : PATObject<reco::Jet>(reco::Jet()), embeddedCaloTowers_(false), embeddedPFCandidates_(false), jetCharge_(0.) {}
0014
0015
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
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
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
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
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
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
0078 Jet::~Jet() {}
0079
0080
0081
0082 CaloTowerPtr Jet::getCaloConstituent(unsigned fIndex) const {
0083 if (embeddedCaloTowers_) {
0084
0085 if (!caloTowersFwdPtr_.empty()) {
0086 return (fIndex < caloTowersFwdPtr_.size() ? caloTowersFwdPtr_[fIndex].ptr() : CaloTowerPtr());
0087 }
0088
0089 else {
0090 if (!caloTowers_.empty()) {
0091 return (fIndex < caloTowers_.size() ? CaloTowerPtr(&caloTowers_, fIndex) : CaloTowerPtr());
0092 }
0093 }
0094 }
0095
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
0116
0117 reco::PFCandidatePtr Jet::getPFConstituent(unsigned fIndex) const {
0118 if (embeddedPFCandidates_) {
0119
0120 if (!pfCandidatesFwdPtr_.empty()) {
0121 return (fIndex < pfCandidatesFwdPtr_.size() ? pfCandidatesFwdPtr_[fIndex].ptr() : reco::PFCandidatePtr());
0122 }
0123
0124 else {
0125 if (!pfCandidates_.empty()) {
0126 return (fIndex < pfCandidates_.size() ? reco::PFCandidatePtr(&pfCandidates_, fIndex) : reco::PFCandidatePtr());
0127 }
0128 }
0129 }
0130
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
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
0237 int Jet::partonFlavour() const { return jetFlavourInfo_.getPartonFlavour(); }
0238
0239
0240 int Jet::hadronFlavour() const { return jetFlavourInfo_.getHadronFlavour(); }
0241
0242
0243 const reco::JetFlavourInfo& Jet::jetFlavourInfo() const { return jetFlavourInfo_; }
0244
0245
0246
0247
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
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
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
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
0289
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
0305
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
0319
0320 Jet Jet::correctedJet(const std::string& level, const std::string& flavor, const std::string& set) const {
0321
0322
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
0336
0337 Jet Jet::correctedJet(const unsigned int& level, const JetCorrFactors::Flavor& flavor, const unsigned int& set) const {
0338 Jet correctedJet(*this);
0339
0340 correctedJet.setP4(jecFactor(level, flavor, set) * p4());
0341
0342 correctedJet.currentJECSet(set);
0343 correctedJet.currentJECLevel(level);
0344 correctedJet.currentJECFlavor(flavor);
0345 return correctedJet;
0346 }
0347
0348
0349
0350 const std::vector<std::pair<std::string, float>>& Jet::getPairDiscri() const { return pairDiscriVector_; }
0351
0352
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
0420 float Jet::jetCharge() const { return jetCharge_; }
0421
0422
0423 const reco::TrackRefVector& Jet::associatedTracks() const { return associatedTracks_; }
0424
0425
0426 void Jet::setAssociatedTracks(const reco::TrackRefVector& tracks) { associatedTracks_ = tracks; }
0427
0428
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
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
0449 void Jet::setGenJetRef(const edm::FwdRef<reco::GenJetCollection>& gj) { genJetFwdRef_ = gj; }
0450
0451
0452 void Jet::setPartonFlavour(int partonFl) { jetFlavourInfo_.setPartonFlavour(partonFl); }
0453
0454
0455 void Jet::setHadronFlavour(int hadronFl) { jetFlavourInfo_.setHadronFlavour(hadronFl); }
0456
0457
0458 void Jet::setJetFlavourInfo(const reco::JetFlavourInfo& jetFlavourInfo) { jetFlavourInfo_ = jetFlavourInfo; }
0459
0460
0461 void Jet::addBDiscriminatorPair(const std::pair<std::string, float>& thePair) { pairDiscriVector_.push_back(thePair); }
0462
0463
0464 void Jet::setJetCharge(float jetCharge) { jetCharge_ = jetCharge; }
0465
0466
0467 void Jet::cacheCaloTowers() const {
0468
0469
0470 std::unique_ptr<std::vector<CaloTowerPtr>> caloTowersTemp{new std::vector<CaloTowerPtr>{}};
0471 if (embeddedCaloTowers_) {
0472
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
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
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
0511 void Jet::cachePFCandidates() const {
0512 std::unique_ptr<std::vector<reco::PFCandidatePtr>> pfCandidatesTemp{new std::vector<reco::PFCandidatePtr>{}};
0513
0514 if (embeddedPFCandidates_) {
0515
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
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
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
0553 pfCandidatesTemp_.set(std::move(pfCandidatesTemp));
0554 }
0555
0556
0557 void Jet::cacheDaughters() const {
0558
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
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
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
0596 void Jet::addSubjets(pat::JetPtrCollection const& pieces, std::string const& label) {
0597 subjetCollections_.push_back(pieces);
0598 subjetLabels_.push_back(label);
0599 }