ATLAS Offline Software
Loading...
Searching...
No Matches
JetIRCSafeLabelTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
7#include "xAODJet/Jet.h"
14#include "AsgMessaging/Check.h"
15#include "AsgTools/ToolHandle.h"
16#include "fastjet/ClusterSequence.hh"
17#include "fastjet/PseudoJet.hh"
18#include "fastjet/JetDefinition.hh"
19#include "fastjet/contrib/FlavInfo.hh"
20#include "fastjet/contrib/IFNPlugin.hh"
21#include "fastjet/contrib/CMPPlugin.hh"
22#include "fastjet/contrib/GHSAlgo.hh"
23#include "fastjet/contrib/SDFPlugin.hh"
24
25#include <iostream>
26#include <fstream>
27#include <numbers>
28#include <array>
29#include <algorithm>
30#include <cctype>
31#include <unordered_set>
32#include <cmath> //std::abs
33
34using namespace xAOD;
35using namespace fastjet;
36using namespace fastjet::contrib;
37
38// Compile-time mapping of algorithm names (matches Algo enum)
39static constexpr std::array<const char*, JetIRCSafeLabelTool::N_ALGOS> ALGO_NAMES = {
40 "IFN", "CMP", "GHS", "SDF", "AKT"
41};
42
43// Helper function to convert string to lowercase
44static std::string toLower(const std::string& s) {
45 std::string result;
46 result.reserve(s.size());
47 std::transform(s.begin(), s.end(), std::back_inserter(result),
48 [](unsigned char c){ return std::tolower(c); });
49 return result;
50}
51
52// Helper function to make antiparticle hadron PIDs
53template <size_t N>
54constexpr std::array<int, N> negateID(const std::array<int, N>& in) {
55 std::array<int, N> out{};
56 for (size_t i = 0; i < N; ++i) {
57 out[i] = -in[i];
58 }
59 return out;
60}
61
62// Helper function to check whether PID is in list of hadrons
63template<typename Container>
64inline bool hit(const Container& ids, int pdgId) {
65 return std::ranges::any_of(ids, [pdgId](int id) {
66 return id == pdgId;
67 });
68}
69
70// Helper function to create JetDefinition that owns a plugin
71template <typename PluginT, typename... Args>
72std::unique_ptr<fastjet::JetDefinition> makeJetDefWithPlugin(Args&&... args) {
73 auto plugin = std::make_unique<PluginT>(std::forward<Args>(args)...);
74 auto jetDef = std::make_unique<fastjet::JetDefinition>(plugin.get());
75 jetDef->delete_plugin_when_unused();
76 //coverity[RESOURCE_LEAK]
77 plugin.release(); // FastJet now owns the plugin.
78 return jetDef;
79}
80
81// Helper function to extract tagged jets for jet algorithms
82static void extractTaggedJets(const std::vector<fastjet::PseudoJet>& pseudojets,
83 std::vector<fastjet::PseudoJet>& btagged,
84 std::vector<fastjet::PseudoJet>& ctagged) {
85 for (const auto& p : pseudojets) {
86 if (p.user_info<fastjet::contrib::FlavHistory>().current_flavour()[5] != 0)
87 btagged.push_back(p);
88 if (p.user_info<fastjet::contrib::FlavHistory>().current_flavour()[4] != 0)
89 ctagged.push_back(p);
90 }
91}
92
93FlavInfo HeavyFlavourContent(int pdgId) {
94 // Simply using the default FlavInfo-from-pdg_code constructor doesn't seem
95 // right as it gives way too many +c flavours. It might be because we remove the children
96 // and we might be left with quite exotic D hadrons with pdg codes of length larger than 4
97 // and that default constructor is unpredictable then.
98
99 // I'm tired of trying to be clever about this. The lists below should contain all
100 // hadrons containing a non-zero net b or c flavour, split into groups. The FlavInfo
101 // is then decided by checking whether the pdgId belongs to one of these groups.
102 // The codes are taken from https://pdg.lbl.gov/2007/reviews/montecarlorpp.pdf
103
104 static constexpr std::array<int, 33> one_b_Ids = {
105 // BOTTOM MESONS WITH NO C
106 -511, -521, -10511, -10521, -513, -523, -10513, -10523, -20513, -20523,
107 -515, -525, -531, -10531, -533, -10533, -20533,
108 -535,
109 // BOTTOM BARYONS WITH NO C
110 5122, 5112, 5212, 5222, 5114, 5214, 5224, 5132, 5232, 5312, 5322, 5314,
111 5324, 5332, 5334
112 };
113 static constexpr std::array<int,33> one_antib_Ids = negateID(one_b_Ids);
114 static constexpr std::array<int,6> one_b_one_antic_Ids = {
115 // BOTTOM MESONS WITH ONE B ONE ANTIC
116 -541, -10541, -543, -10543, -20543, -545
117 };
118 static constexpr std::array<int,6> one_antib_one_c_Ids = negateID(one_b_one_antic_Ids);
119 static constexpr std::array<int,9> one_b_one_c_Ids = {
120 // BOTTOM BARYONS WITH ONE B ONE C
121 5142, 5242, 5412, 5422, 5414, 5424, 5342, 5432, 5434
122 };
123 static constexpr std::array<int,9> one_antib_one_antic_Ids = negateID(one_b_one_c_Ids);
124 static constexpr std::array<int,2> one_b_two_cs_Ids = {
125 // BOTTOM BARYONS WITH ONE B TWO CS
126 5442, 5444
127 };
128 static constexpr std::array<int,2> one_antib_two_antics_Ids = negateID(one_b_two_cs_Ids);
129 static constexpr std::array<int,6> two_bs_Ids = {
130 // BOTTOM BARYONS WITH TWO BS AND NO C
131 5512, 5522, 5514, 5524, 5532, 5534
132 };
133 static constexpr std::array<int,6> two_antibs_Ids = negateID(two_bs_Ids);
134 static constexpr std::array<int,2> two_bs_one_c_Ids = {
135 // BOTTOM BARYONS WITH TWO BS AND ONE C
136 5542, 5544
137 };
138 static constexpr std::array<int,2> two_antibs_one_antic_Ids = negateID(two_bs_one_c_Ids);
139 static constexpr std::array<int,1> three_bs = {
140 // BOTTOM BARYON WITH THREE BS (OMEGA-)
141 5554
142 };
143 static constexpr std::array<int,1> three_antibs = negateID(three_bs);
144
145 static constexpr std::array<int,33> one_c_Ids = {
146 // CHARMED MESONS WITH NO B (all of them; if they have B they become bottom hadrons)
147 411, 421, 10411, 10421, 413, 423, 10413, 10423, 20413, 20423,
148 415, 425, 431, 10431, 433, 10433, 20433, 435,
149 // CHARMED BARYONS WITH ONE C AND NO B (all of them)
150 4122, 4222, 4212, 4112, 4224, 4214, 4114, 4232, 4132, 4322, 4312, 4324,
151 4314, 4332, 4334
152 };
153 static constexpr std::array<int,33> one_antic_Ids = negateID(one_c_Ids);
154 static constexpr std::array<int,6> two_c_Ids = {
155 // CHARMED BARYONS WITH TWO Cs
156 4412, 4422, 4414, 4424, 4432, 4434
157 };
158 static constexpr std::array<int,6> two_antic_Ids = negateID(two_c_Ids);
159 static constexpr std::array<int,1> three_c_Ids = {
160 4444
161 };
162 static constexpr std::array<int,1> three_antic_Ids = negateID(three_c_Ids);
163
164
165 int nb = 0, nc = 0;
166
167 // Check most specific categories first
168 if (hit(three_bs, pdgId)) { nb = 3; }
169 else if (hit(three_antibs, pdgId)) { nb = -3; }
170 else if (hit(two_bs_one_c_Ids, pdgId)) { nb = 2; nc = 1; }
171 else if (hit(two_antibs_one_antic_Ids, pdgId)) { nb = -2; nc = -1; }
172 else if (hit(two_bs_Ids, pdgId)) { nb = 2; }
173 else if (hit(two_antibs_Ids, pdgId)) { nb = -2; }
174 else if (hit(one_b_two_cs_Ids, pdgId)) { nb = 1; nc = 2; }
175 else if (hit(one_antib_two_antics_Ids, pdgId)) { nb = -1; nc = -2; }
176 else if (hit(one_b_one_c_Ids, pdgId)) { nb = 1; nc = 1; }
177 else if (hit(one_antib_one_antic_Ids, pdgId)) { nb = -1; nc = -1; }
178 else if (hit(one_b_one_antic_Ids, pdgId)) { nb = 1; nc = -1; }
179 else if (hit(one_antib_one_c_Ids, pdgId)) { nb = -1; nc = 1; }
180 // Then check more general categories
181 else if (hit(one_b_Ids, pdgId)) { nb = 1; }
182 else if (hit(one_antib_Ids, pdgId)) { nb = -1; }
183 else if (hit(three_c_Ids, pdgId)) { nc = 3; }
184 else if (hit(three_antic_Ids, pdgId)) { nc = -3; }
185 else if (hit(two_c_Ids, pdgId)) { nc = 2; }
186 else if (hit(two_antic_Ids, pdgId)) { nc = -2; }
187 else if (hit(one_c_Ids, pdgId)) { nc = 1; }
188 else if (hit(one_antic_Ids, pdgId)) { nc = -1; }
189
190 return FlavInfo(0,0,0,nc,nb,0,0);
191}
192
193
195
196std::vector< std::vector<PseudoJet> > JetIRCSafeLabelTool::getJetInputs(
197 const TruthParticleContainer& parts,
198 const TruthParticleContainer& label_bs,
199 const TruthParticleContainer& label_cs) const {
200
201 // Collect all particles needed
202 std::vector<const TruthParticle*> truthparts(parts.begin(), parts.end());
203 std::vector<const TruthParticle*> bs(label_bs.begin(), label_bs.end());
204 std::vector<const TruthParticle*> cs(label_cs.begin(), label_cs.end());
205
206 // Remove all children of B and D hadrons
208 childrenRemoved(bs, bs);
209 childrenRemoved(bs, cs);
210 childrenRemoved(bs, truthparts);
211 childrenRemoved(cs, cs);
212 childrenRemoved(cs, truthparts);
213
214 // Add original B and D hadrons to the truth particles
215 truthparts.insert(truthparts.end(), bs.begin(), bs.end());
216 truthparts.insert(truthparts.end(), cs.begin(), cs.end());
217
218 // Now, create the PseudoJet event from them
219 std::vector<PseudoJet> fullevent(truthparts.size());
220 for (unsigned int ip = 0; ip < truthparts.size(); ip++) {
221 const TruthParticle* part = truthparts[ip];
222 double px = part->px();
223 double py = part->py();
224 double pz = part->pz();
225 double E = part->e();
226 fullevent[ip] = PseudoJet(px,py,pz,E);
227 FlavInfo partFlavInfo = HeavyFlavourContent(part->pdgId());
228 // fastjet sets a weird example to take ownership.
229 // But we don't have a better option than using their interface the way it's designed.
230 fullevent[ip].set_user_info(new FlavInfo(partFlavInfo));
231 }
232
233 std::array< std::vector<PseudoJet>, N_ALGOS > all_pseudojets_array{};
234
235 bool doIFN = doAlgo(Algo::IFN);
236 bool doCMP = doAlgo(Algo::CMP);
237 bool doGHS = doAlgo(Algo::GHS);
238 bool doSDF = doAlgo(Algo::SDF);
239 bool doAKT = doAlgo(Algo::AKT);
240
241 // If no algorithms enabled, return empty vector
242 if (!(doIFN || doCMP || doGHS || doSDF || doAKT)) {
243 std::vector<std::vector<PseudoJet>> empty_result;
244 empty_result.resize(N_ALGOS);
245 return empty_result;
246 }
247
248 const Selector& selectpt = *m_selectPt;
249 const FlavRecombiner& flav_recombiner = *m_flavRecombiner;
250 const JetDefinition& akt_jet_def = *m_aktJetDef;
251
252 if (doIFN) {
253 const JetDefinition& ifn_jet_def = *m_ifnJetDef;
254 all_pseudojets_array[static_cast<std::size_t>(Algo::IFN)] = selectpt(ifn_jet_def(fullevent));
255 }
256
257 if (doCMP) {
258 const JetDefinition& cmp_jet_def = *m_cmpJetDef;
259 all_pseudojets_array[static_cast<std::size_t>(Algo::CMP)] = selectpt(cmp_jet_def(fullevent));
260 }
261
262 std::vector<PseudoJet> base_jets;
263 if (doAKT || doGHS || doSDF) {
264 base_jets = selectpt(akt_jet_def(fullevent));
265 }
266
267 // GHS parameters using class constants
268 if (doGHS) {
269 all_pseudojets_array[static_cast<std::size_t>(Algo::GHS)] =
270 run_GHS(base_jets, GHS_PT_CUT, GHS_ALPHA, GHS_OMEGA, flav_recombiner);
271 }
272
273 if (doSDF) {
274 SDFlavourCalc sdFlavCalc;
275 std::vector<PseudoJet> SDF_jets = base_jets;
276 sdFlavCalc(SDF_jets);
277 all_pseudojets_array[static_cast<std::size_t>(Algo::SDF)] = std::move(SDF_jets);
278 }
279
280 if (doAKT) {
281 // Copy base_jets instead of moving, as it may be used by GHS and SDF
282 all_pseudojets_array[static_cast<std::size_t>(Algo::AKT)] = std::move(base_jets);
283 }
284
285 std::vector<std::vector<PseudoJet>> all_pseudojets;
286 all_pseudojets.reserve(N_ALGOS);
287 for (std::size_t i = 0; i < N_ALGOS; ++i) {
288 all_pseudojets.push_back(std::move(all_pseudojets_array[i]));
289 }
290
291 return all_pseudojets;
292}
293
295 const ParticleJetTools::Tag_PseudoJets& tag_pjets,
297 bool doIFN, bool doCMP, bool doGHS, bool doSDF, bool doAKT) {
298
299 int IFN_label = doIFN ? (tag_pjets.IFN_b.size() ? JetIRCSafeLabelTool::LABEL_B :
301 int CMP_label = doCMP ? (tag_pjets.CMP_b.size() ? JetIRCSafeLabelTool::LABEL_B :
303 int GHS_label = doGHS ? (tag_pjets.GHS_b.size() ? JetIRCSafeLabelTool::LABEL_B :
305 int SDF_label = doSDF ? (tag_pjets.SDF_b.size() ? JetIRCSafeLabelTool::LABEL_B :
307 int AKT_label = doAKT ? (tag_pjets.AKT_b.size() ? JetIRCSafeLabelTool::LABEL_B :
309
310 decs.IFNsingleint(jet) = IFN_label;
311 decs.CMPsingleint(jet) = CMP_label;
312 decs.GHSsingleint(jet) = GHS_label;
313 decs.SDFsingleint(jet) = SDF_label;
314 decs.AKTsingleint(jet) = AKT_label;
315}
316
318
319 ATH_MSG_DEBUG(" Initializing... ");
320
321 // Initialize truth jet inputs key
322 ATH_CHECK(m_outTruthPartKey.initialize());
325
326 // Update label names from properties
327 m_ircsafelabelnames.IFNsingleint = m_labelNameIFN.value();
328 m_ircsafelabelnames.CMPsingleint = m_labelNameCMP.value();
329 m_ircsafelabelnames.GHSsingleint = m_labelNameGHS.value();
330 m_ircsafelabelnames.SDFsingleint = m_labelNameSDF.value();
331 m_ircsafelabelnames.AKTsingleint = m_labelNameAKT.value();
332
333 // Build decorators using updated label names
335 std::make_unique<ParticleJetTools::IRCSafeLabelDecorators>(m_ircsafelabelnames);
336
337 // Initialize all algorithms to false
338 m_doAlgo.fill(false);
339
340 // Parse enabled algorithm names from configuration
341 for (const auto& name : m_enabledAlgorithms.value()) {
342 std::string lowerName = toLower(name);
343 bool found = false;
344
345 for (std::size_t i = 0; i < N_ALGOS; ++i) {
346 if (toLower(ALGO_NAMES[i]) == lowerName) {
347 m_doAlgo[i] = true;
348 found = true;
349 break;
350 }
351 }
352
353 if (!found) {
354 ATH_MSG_WARNING("Unknown algorithm in EnabledAlgorithms: " << name);
355 }
356 }
357
358 // Check if any algorithm is enabled
359 bool anyEnabled = false;
360 for (bool enabled : m_doAlgo) {
361 if (enabled) {
362 anyEnabled = true;
363 break;
364 }
365 }
366
367 if (!anyEnabled) {
368 ATH_MSG_WARNING("EnabledAlgorithms is empty; no IRCSafe labelling will be performed.");
369 return StatusCode::SUCCESS;
370 }
371
372 bool doIFN = doAlgo(Algo::IFN);
373 bool doCMP = doAlgo(Algo::CMP);
374
375 // Build FastJet objects using property values
376 m_selectPt = std::make_unique<Selector>(SelectorPtMin(m_truthJetPtMin.value()));
377 m_flavRecombiner = std::make_unique<FlavRecombiner>(FlavRecombiner::net);
378 m_aktJetDef = std::make_unique<JetDefinition>(antikt_algorithm, m_truthR.value());
379 m_aktJetDef->set_recombiner(m_flavRecombiner.get());
380
381 // Interleaved flavour neutralisation - IFN (2306.07314)
382 if (doIFN) {
384 *m_aktJetDef, IFN_RFACTOR, IFN_BETA, FlavRecombiner::net
385 );
386 }
387
388 // Czakon, Mitov, Poncelet (CMP) algorithm - flavour anti-kt (2205.11879)
389 if (doCMP) {
391 m_truthR.value(), CMP_A,
392 CMPPlugin::CorrectionType::OverAllCoshyCosPhi_a2,
393 CMPPlugin::ClusteringType::DynamicKtMax
394 );
395 m_cmpJetDef->set_recombiner(m_flavRecombiner.get());
396 }
397
398 return StatusCode::SUCCESS;
399}
400
401std::vector< std::vector<const PseudoJet*> > JetIRCSafeLabelTool::match(
402 std::vector<PseudoJet>& tagged_pseudojets,
403 const JetContainer& jets) const {
404 ATH_MSG_VERBOSE("In " << name() << "::match()");
405
406 std::vector< std::vector<const PseudoJet*> > jetlabelparts(jets.size(), std::vector<const PseudoJet*>());
407
408 // Loop over pseudojets and find the best matched jet
409 for (unsigned int i_tj = 0; i_tj < tagged_pseudojets.size(); i_tj++) {
410
411 const auto* tag_pjet = &tagged_pseudojets[i_tj];
412
413 double mindr = DBL_MAX;
414 int mindrjetidx = -1;
415
416 for (unsigned int iJet = 0; iJet < jets.size(); iJet++) {
417
418 const Jet& jet = *jets[iJet];
419
420 double pt = jet.pt();
421 if (pt < m_jetPtMin.value())
422 continue;
423
424 double drap = abs(jet.rapidity() - tag_pjet->rap());
425 double dphi = abs(jet.phi() - tag_pjet->phi());
426 if (dphi > numbers::pi) dphi = 2*numbers::pi - dphi;
427 double dr = sqrt(drap*drap + dphi*dphi);
428
429 // Too far for matching criterion
430 if (dr > m_drMax.value())
431 continue;
432
433 // Store the matched jet
434 if (dr < mindr) {
435 mindr = dr;
436 mindrjetidx = iJet;
437 }
438
439 }
440
441 // Store the label particle with the jet
442 if (mindrjetidx >= 0) {
443 jetlabelparts.at(mindrjetidx).push_back(tag_pjet);
444 }
445 }
446
447 return jetlabelparts;
448}
449
450StatusCode JetIRCSafeLabelTool::decorate(const JetContainer& jets) const {
451
452 // Retrieve truth particle collections
456
457 if (!truthPartReadHandle.isValid()) {
458 ATH_MSG_ERROR("Invalid ReadHandle for TruthParticleCollection with key: " << truthPartReadHandle.key());
459 return StatusCode::FAILURE;
460 }
461 if (!bottomReadHandle.isValid()) {
462 ATH_MSG_ERROR("Invalid ReadHandle for bottomPartCollection with key: " << bottomReadHandle.key());
463 return StatusCode::FAILURE;
464 }
465 if (!charmReadHandle.isValid()) {
466 ATH_MSG_ERROR("Invalid ReadHandle for charmPartCollection with key: " << charmReadHandle.key());
467 return StatusCode::FAILURE;
468 }
469
470 // Get algorithm flags
471 bool doIFN = doAlgo(Algo::IFN);
472 bool doCMP = doAlgo(Algo::CMP);
473 bool doGHS = doAlgo(Algo::GHS);
474 bool doSDF = doAlgo(Algo::SDF);
475 bool doAKT = doAlgo(Algo::AKT);
476
477 // Get all pseudo-jets from enabled algorithms
478 std::vector<std::vector<PseudoJet>> all_pseudojets =
479 getJetInputs(*truthPartReadHandle, *bottomReadHandle, *charmReadHandle);
480
481 // Extract b- and c-tagged jets for each algorithm
482 std::vector<PseudoJet> btagged_pseudojetsIFN, ctagged_pseudojetsIFN;
483 std::vector<PseudoJet> btagged_pseudojetsCMP, ctagged_pseudojetsCMP;
484 std::vector<PseudoJet> btagged_pseudojetsGHS, ctagged_pseudojetsGHS;
485 std::vector<PseudoJet> btagged_pseudojetsSDF, ctagged_pseudojetsSDF;
486 std::vector<PseudoJet> btagged_pseudojetsAKT, ctagged_pseudojetsAKT;
487
488 // Extract IFN jets
489 if (doIFN && all_pseudojets.size() > static_cast<std::size_t>(Algo::IFN)) {
490 extractTaggedJets(all_pseudojets[static_cast<std::size_t>(Algo::IFN)],
491 btagged_pseudojetsIFN, ctagged_pseudojetsIFN);
492 }
493
494 // Extract CMP jets
495 if (doCMP && all_pseudojets.size() > static_cast<std::size_t>(Algo::CMP)) {
496 extractTaggedJets(all_pseudojets[static_cast<std::size_t>(Algo::CMP)],
497 btagged_pseudojetsCMP, ctagged_pseudojetsCMP);
498 }
499
500 // Extract GHS jets
501 if (doGHS && all_pseudojets.size() > static_cast<std::size_t>(Algo::GHS)) {
502 extractTaggedJets(all_pseudojets[static_cast<std::size_t>(Algo::GHS)],
503 btagged_pseudojetsGHS, ctagged_pseudojetsGHS);
504 }
505
506 // Extract SDF jets
507 if (doSDF && all_pseudojets.size() > static_cast<std::size_t>(Algo::SDF)) {
508 extractTaggedJets(all_pseudojets[static_cast<std::size_t>(Algo::SDF)],
509 btagged_pseudojetsSDF, ctagged_pseudojetsSDF);
510 }
511
512 // Extract AKT jets
513 if (doAKT && all_pseudojets.size() > static_cast<std::size_t>(Algo::AKT)) {
514 extractTaggedJets(all_pseudojets[static_cast<std::size_t>(Algo::AKT)],
515 btagged_pseudojetsAKT, ctagged_pseudojetsAKT);
516 }
517
518 // Match the tagged pseudojets to reco jets
519 std::vector<std::vector<const PseudoJet*>> jetlabelIFN_b = doIFN ? match(btagged_pseudojetsIFN, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
520 std::vector<std::vector<const PseudoJet*>> jetlabelIFN_c = doIFN ? match(ctagged_pseudojetsIFN, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
521 std::vector<std::vector<const PseudoJet*>> jetlabelCMP_b = doCMP ? match(btagged_pseudojetsCMP, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
522 std::vector<std::vector<const PseudoJet*>> jetlabelCMP_c = doCMP ? match(ctagged_pseudojetsCMP, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
523 std::vector<std::vector<const PseudoJet*>> jetlabelGHS_b = doGHS ? match(btagged_pseudojetsGHS, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
524 std::vector<std::vector<const PseudoJet*>> jetlabelGHS_c = doGHS ? match(ctagged_pseudojetsGHS, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
525 std::vector<std::vector<const PseudoJet*>> jetlabelSDF_b = doSDF ? match(btagged_pseudojetsSDF, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
526 std::vector<std::vector<const PseudoJet*>> jetlabelSDF_c = doSDF ? match(ctagged_pseudojetsSDF, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
527 std::vector<std::vector<const PseudoJet*>> jetlabelAKT_b = doAKT ? match(btagged_pseudojetsAKT, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
528 std::vector<std::vector<const PseudoJet*>> jetlabelAKT_c = doAKT ? match(ctagged_pseudojetsAKT, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
529
530 for (unsigned int iJet = 0; iJet < jets.size(); iJet++) {
531 const Jet& jet = *jets[iJet];
532 if (jet.pt() < m_jetPtMin.value()) {
533 m_ircsafelabeldecs->IFNsingleint(jet) = LABEL_DISABLED;
534 m_ircsafelabeldecs->CMPsingleint(jet) = LABEL_DISABLED;
535 m_ircsafelabeldecs->GHSsingleint(jet) = LABEL_DISABLED;
536 m_ircsafelabeldecs->SDFsingleint(jet) = LABEL_DISABLED;
537 m_ircsafelabeldecs->AKTsingleint(jet) = LABEL_DISABLED;
538 continue;
539 }
540
542 tag_pjet.IFN_b = jetlabelIFN_b[iJet];
543 tag_pjet.IFN_c = jetlabelIFN_c[iJet];
544 tag_pjet.CMP_b = jetlabelCMP_b[iJet];
545 tag_pjet.CMP_c = jetlabelCMP_c[iJet];
546 tag_pjet.GHS_b = jetlabelGHS_b[iJet];
547 tag_pjet.GHS_c = jetlabelGHS_c[iJet];
548 tag_pjet.SDF_b = jetlabelSDF_b[iJet];
549 tag_pjet.SDF_c = jetlabelSDF_c[iJet];
550 tag_pjet.AKT_b = jetlabelAKT_b[iJet];
551 tag_pjet.AKT_c = jetlabelAKT_c[iJet];
552
553 setJetIRCSafeLabels(jet, tag_pjet, *m_ircsafelabeldecs, doIFN, doCMP, doGHS, doSDF, doAKT);
554 }
555
556 return StatusCode::SUCCESS;
557}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
Handle class for reading from StoreGate.
std::unique_ptr< fastjet::JetDefinition > makeJetDefWithPlugin(Args &&... args)
void setJetIRCSafeLabels(const xAOD::Jet &jet, const ParticleJetTools::Tag_PseudoJets &tag_pjets, const ParticleJetTools::IRCSafeLabelDecorators &decs, bool doIFN, bool doCMP, bool doGHS, bool doSDF, bool doAKT)
static constexpr std::array< const char *, JetIRCSafeLabelTool::N_ALGOS > ALGO_NAMES
bool hit(const Container &ids, int pdgId)
constexpr std::array< int, N > negateID(const std::array< int, N > &in)
static std::string toLower(const std::string &s)
FlavInfo HeavyFlavourContent(int pdgId)
static void extractTaggedJets(const std::vector< fastjet::PseudoJet > &pseudojets, std::vector< fastjet::PseudoJet > &btagged, std::vector< fastjet::PseudoJet > &ctagged)
@ btagged
const_iterator end() const noexcept
Return a const_iterator pointing past the end of the collection.
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
StatusCode initialize() override
Dummy implementation of the initialisation function.
Gaudi::Property< std::vector< std::string > > m_enabledAlgorithms
Algorithm selection property.
JetIRCSafeLabelTool(const std::string &name)
Constructor.
static constexpr std::size_t N_ALGOS
static constexpr int LABEL_LIGHT
std::unique_ptr< fastjet::contrib::FlavRecombiner > m_flavRecombiner
Gaudi::Property< double > m_truthJetPtMin
Cut and configuration properties.
bool doAlgo(Algo a) const
Convenience function to check if an algorithm is enabled.
static constexpr double GHS_OMEGA
Gaudi::Property< std::string > m_labelNameCMP
SG::ReadHandleKey< xAOD::TruthParticleContainer > m_bottomPartCollectionKey
Read handles for truth particle collections.
static constexpr double IFN_BETA
std::vector< std::vector< const fastjet::PseudoJet * > > match(std::vector< fastjet::PseudoJet > &tagged_jets, const xAOD::JetContainer &jets) const
Match truth-level pseudo-jets to reconstructed jets.
SG::ReadHandleKey< xAOD::TruthParticleContainer > m_outTruthPartKey
static constexpr int LABEL_DISABLED
static constexpr double IFN_RFACTOR
static constexpr int LABEL_B
std::unique_ptr< fastjet::JetDefinition > m_aktJetDef
Gaudi::Property< std::string > m_labelNameGHS
std::unique_ptr< fastjet::JetDefinition > m_cmpJetDef
Gaudi::Property< double > m_truthR
static constexpr int LABEL_C
@ GHS
Gauld-Huss-Stagnitto flavour dressing.
@ CMP
Czakon-Mitov-Poncelet algorithm.
@ AKT
Anti-kt with net flavour (NOT IRC-safe, for comparison).
@ SDF
SDFlav algorithm (Marzani et al.).
@ IFN
Interleaved Flavour Neutralisation.
static constexpr double CMP_A
StatusCode decorate(const xAOD::JetContainer &jets) const override
Decorate a jet collection without otherwise modifying it.
Gaudi::Property< double > m_jetPtMin
Gaudi::Property< std::string > m_labelNameIFN
Label name properties.
Gaudi::Property< std::string > m_labelNameSDF
ParticleJetTools::IRCSafeLabelNames m_ircsafelabelnames
Name of jet label attributes.
std::unique_ptr< fastjet::JetDefinition > m_ifnJetDef
std::vector< std::vector< fastjet::PseudoJet > > getJetInputs(const xAOD::TruthParticleContainer &parts, const xAOD::TruthParticleContainer &label_bs, const xAOD::TruthParticleContainer &label_cs) const
Collect truth particles and cluster them into jets using the enabled algorithms.
Gaudi::Property< std::string > m_labelNameAKT
std::array< bool, N_ALGOS > m_doAlgo
Compact array storing enabled algorithms (true = enabled).
SG::ReadHandleKey< xAOD::TruthParticleContainer > m_charmPartCollectionKey
std::unique_ptr< ParticleJetTools::IRCSafeLabelDecorators > m_ircsafelabeldecs
std::unique_ptr< fastjet::Selector > m_selectPt
FastJet configuration cached at initialize to avoid per-event allocations.
static constexpr double GHS_PT_CUT
Gaudi::Property< double > m_drMax
static constexpr double GHS_ALPHA
storage of the time histories of all the cells
virtual bool isValid() override final
Can the handle be successfully dereferenced?
virtual const std::string & key() const override final
Return the StoreGate ID for the referenced object.
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
void childrenRemoved(const std::vector< const xAOD::TruthParticle * > &parents, std::vector< const xAOD::TruthParticle * > &children)
ICaloAffectedTool is abstract interface for tools checking if 4 mom is in calo affected region.
Jet_v1 Jet
Definition of the current "jet version".
setRcore setEtHad setFside pt
JetContainer_v1 JetContainer
Definition of the current "jet container version".
std::vector< const fastjet::PseudoJet * > CMP_b
std::vector< const fastjet::PseudoJet * > CMP_c
std::vector< const fastjet::PseudoJet * > AKT_b
std::vector< const fastjet::PseudoJet * > AKT_c
std::vector< const fastjet::PseudoJet * > IFN_b
std::vector< const fastjet::PseudoJet * > GHS_b
std::vector< const fastjet::PseudoJet * > SDF_c
std::vector< const fastjet::PseudoJet * > IFN_c
std::vector< const fastjet::PseudoJet * > SDF_b
std::vector< const fastjet::PseudoJet * > GHS_c