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 plugin.release();
77 return jetDef;
78}
79
80// Helper function to extract tagged jets for jet algorithms
81static void extractTaggedJets(const std::vector<fastjet::PseudoJet>& pseudojets,
82 std::vector<fastjet::PseudoJet>& btagged,
83 std::vector<fastjet::PseudoJet>& ctagged) {
84 for (const auto& p : pseudojets) {
85 if (p.user_info<fastjet::contrib::FlavHistory>().current_flavour()[5] != 0)
86 btagged.push_back(p);
87 if (p.user_info<fastjet::contrib::FlavHistory>().current_flavour()[4] != 0)
88 ctagged.push_back(p);
89 }
90}
91
92FlavInfo HeavyFlavourContent(int pdgId) {
93 // Simply using the default FlavInfo-from-pdg_code constructor doesn't seem
94 // right as it gives way too many +c flavours. It might be because we remove the children
95 // and we might be left with quite exotic D hadrons with pdg codes of length larger than 4
96 // and that default constructor is unpredictable then.
97
98 // I'm tired of trying to be clever about this. The lists below should contain all
99 // hadrons containing a non-zero net b or c flavour, split into groups. The FlavInfo
100 // is then decided by checking whether the pdgId belongs to one of these groups.
101 // The codes are taken from https://pdg.lbl.gov/2007/reviews/montecarlorpp.pdf
102
103 static constexpr std::array<int, 33> one_b_Ids = {
104 // BOTTOM MESONS WITH NO C
105 -511, -521, -10511, -10521, -513, -523, -10513, -10523, -20513, -20523,
106 -515, -525, -531, -10531, -533, -10533, -20533,
107 -535,
108 // BOTTOM BARYONS WITH NO C
109 5122, 5112, 5212, 5222, 5114, 5214, 5224, 5132, 5232, 5312, 5322, 5314,
110 5324, 5332, 5334
111 };
112 static constexpr std::array<int,33> one_antib_Ids = negateID(one_b_Ids);
113 static constexpr std::array<int,6> one_b_one_antic_Ids = {
114 // BOTTOM MESONS WITH ONE B ONE ANTIC
115 -541, -10541, -543, -10543, -20543, -545
116 };
117 static constexpr std::array<int,6> one_antib_one_c_Ids = negateID(one_b_one_antic_Ids);
118 static constexpr std::array<int,9> one_b_one_c_Ids = {
119 // BOTTOM BARYONS WITH ONE B ONE C
120 5142, 5242, 5412, 5422, 5414, 5424, 5342, 5432, 5434
121 };
122 static constexpr std::array<int,9> one_antib_one_antic_Ids = negateID(one_b_one_c_Ids);
123 static constexpr std::array<int,2> one_b_two_cs_Ids = {
124 // BOTTOM BARYONS WITH ONE B TWO CS
125 5442, 5444
126 };
127 static constexpr std::array<int,2> one_antib_two_antics_Ids = negateID(one_b_two_cs_Ids);
128 static constexpr std::array<int,6> two_bs_Ids = {
129 // BOTTOM BARYONS WITH TWO BS AND NO C
130 5512, 5522, 5514, 5524, 5532, 5534
131 };
132 static constexpr std::array<int,6> two_antibs_Ids = negateID(two_bs_Ids);
133 static constexpr std::array<int,2> two_bs_one_c_Ids = {
134 // BOTTOM BARYONS WITH TWO BS AND ONE C
135 5542, 5544
136 };
137 static constexpr std::array<int,2> two_antibs_one_antic_Ids = negateID(two_bs_one_c_Ids);
138 static constexpr std::array<int,1> three_bs = {
139 // BOTTOM BARYON WITH THREE BS (OMEGA-)
140 5554
141 };
142 static constexpr std::array<int,1> three_antibs = negateID(three_bs);
143
144 static constexpr std::array<int,33> one_c_Ids = {
145 // CHARMED MESONS WITH NO B (all of them; if they have B they become bottom hadrons)
146 411, 421, 10411, 10421, 413, 423, 10413, 10423, 20413, 20423,
147 415, 425, 431, 10431, 433, 10433, 20433, 435,
148 // CHARMED BARYONS WITH ONE C AND NO B (all of them)
149 4122, 4222, 4212, 4112, 4224, 4214, 4114, 4232, 4132, 4322, 4312, 4324,
150 4314, 4332, 4334
151 };
152 static constexpr std::array<int,33> one_antic_Ids = negateID(one_c_Ids);
153 static constexpr std::array<int,6> two_c_Ids = {
154 // CHARMED BARYONS WITH TWO Cs
155 4412, 4422, 4414, 4424, 4432, 4434
156 };
157 static constexpr std::array<int,6> two_antic_Ids = negateID(two_c_Ids);
158 static constexpr std::array<int,1> three_c_Ids = {
159 4444
160 };
161 static constexpr std::array<int,1> three_antic_Ids = negateID(three_c_Ids);
162
163
164 int nb = 0, nc = 0;
165
166 // Check most specific categories first
167 if (hit(three_bs, pdgId)) { nb = 3; }
168 else if (hit(three_antibs, pdgId)) { nb = -3; }
169 else if (hit(two_bs_one_c_Ids, pdgId)) { nb = 2; nc = 1; }
170 else if (hit(two_antibs_one_antic_Ids, pdgId)) { nb = -2; nc = -1; }
171 else if (hit(two_bs_Ids, pdgId)) { nb = 2; }
172 else if (hit(two_antibs_Ids, pdgId)) { nb = -2; }
173 else if (hit(one_b_two_cs_Ids, pdgId)) { nb = 1; nc = 2; }
174 else if (hit(one_antib_two_antics_Ids, pdgId)) { nb = -1; nc = -2; }
175 else if (hit(one_b_one_c_Ids, pdgId)) { nb = 1; nc = 1; }
176 else if (hit(one_antib_one_antic_Ids, pdgId)) { nb = -1; nc = -1; }
177 else if (hit(one_b_one_antic_Ids, pdgId)) { nb = 1; nc = -1; }
178 else if (hit(one_antib_one_c_Ids, pdgId)) { nb = -1; nc = 1; }
179 // Then check more general categories
180 else if (hit(one_b_Ids, pdgId)) { nb = 1; }
181 else if (hit(one_antib_Ids, pdgId)) { nb = -1; }
182 else if (hit(three_c_Ids, pdgId)) { nc = 3; }
183 else if (hit(three_antic_Ids, pdgId)) { nc = -3; }
184 else if (hit(two_c_Ids, pdgId)) { nc = 2; }
185 else if (hit(two_antic_Ids, pdgId)) { nc = -2; }
186 else if (hit(one_c_Ids, pdgId)) { nc = 1; }
187 else if (hit(one_antic_Ids, pdgId)) { nc = -1; }
188
189 return FlavInfo(0,0,0,nc,nb,0,0);
190}
191
192
194
195std::vector< std::vector<PseudoJet> > JetIRCSafeLabelTool::getJetInputs(
196 const TruthParticleContainer& parts,
197 const TruthParticleContainer& label_bs,
198 const TruthParticleContainer& label_cs) const {
199
200 // Collect all particles needed
201 std::vector<const TruthParticle*> truthparts(parts.begin(), parts.end());
202 std::vector<const TruthParticle*> bs(label_bs.begin(), label_bs.end());
203 std::vector<const TruthParticle*> cs(label_cs.begin(), label_cs.end());
204
205 // Remove all children of B and D hadrons
207 childrenRemoved(bs, bs);
208 childrenRemoved(bs, cs);
209 childrenRemoved(bs, truthparts);
210 childrenRemoved(cs, cs);
211 childrenRemoved(cs, truthparts);
212
213 // Add original B and D hadrons to the truth particles
214 truthparts.insert(truthparts.end(), bs.begin(), bs.end());
215 truthparts.insert(truthparts.end(), cs.begin(), cs.end());
216
217 // Now, create the PseudoJet event from them
218 std::vector<PseudoJet> fullevent(truthparts.size());
219 for (unsigned int ip = 0; ip < truthparts.size(); ip++) {
220 const TruthParticle* part = truthparts[ip];
221 double px = part->px();
222 double py = part->py();
223 double pz = part->pz();
224 double E = part->e();
225 fullevent[ip] = PseudoJet(px,py,pz,E);
226 FlavInfo partFlavInfo = HeavyFlavourContent(part->pdgId());
227 // fastjet sets a weird example to take ownership.
228 // But we don't have a better option than using their interface the way it's designed.
229 fullevent[ip].set_user_info(new FlavInfo(partFlavInfo));
230 }
231
232 std::array< std::vector<PseudoJet>, N_ALGOS > all_pseudojets_array{};
233
234 bool doIFN = doAlgo(Algo::IFN);
235 bool doCMP = doAlgo(Algo::CMP);
236 bool doGHS = doAlgo(Algo::GHS);
237 bool doSDF = doAlgo(Algo::SDF);
238 bool doAKT = doAlgo(Algo::AKT);
239
240 // If no algorithms enabled, return empty vector
241 if (!(doIFN || doCMP || doGHS || doSDF || doAKT)) {
242 std::vector<std::vector<PseudoJet>> empty_result;
243 empty_result.resize(N_ALGOS);
244 return empty_result;
245 }
246
247 const Selector& selectpt = *m_selectPt;
248 const FlavRecombiner& flav_recombiner = *m_flavRecombiner;
249 const JetDefinition& akt_jet_def = *m_aktJetDef;
250
251 if (doIFN) {
252 const JetDefinition& ifn_jet_def = *m_ifnJetDef;
253 all_pseudojets_array[static_cast<std::size_t>(Algo::IFN)] = selectpt(ifn_jet_def(fullevent));
254 }
255
256 if (doCMP) {
257 const JetDefinition& cmp_jet_def = *m_cmpJetDef;
258 all_pseudojets_array[static_cast<std::size_t>(Algo::CMP)] = selectpt(cmp_jet_def(fullevent));
259 }
260
261 std::vector<PseudoJet> base_jets;
262 if (doAKT || doGHS || doSDF) {
263 base_jets = selectpt(akt_jet_def(fullevent));
264 }
265
266 // GHS parameters using class constants
267 if (doGHS) {
268 all_pseudojets_array[static_cast<std::size_t>(Algo::GHS)] =
269 run_GHS(base_jets, GHS_PT_CUT, GHS_ALPHA, GHS_OMEGA, flav_recombiner);
270 }
271
272 if (doSDF) {
273 SDFlavourCalc sdFlavCalc;
274 std::vector<PseudoJet> SDF_jets = base_jets;
275 sdFlavCalc(SDF_jets);
276 all_pseudojets_array[static_cast<std::size_t>(Algo::SDF)] = std::move(SDF_jets);
277 }
278
279 if (doAKT) {
280 // Copy base_jets instead of moving, as it may be used by GHS and SDF
281 all_pseudojets_array[static_cast<std::size_t>(Algo::AKT)] = base_jets;
282 }
283
284 std::vector<std::vector<PseudoJet>> all_pseudojets;
285 all_pseudojets.reserve(N_ALGOS);
286 for (std::size_t i = 0; i < N_ALGOS; ++i) {
287 all_pseudojets.push_back(std::move(all_pseudojets_array[i]));
288 }
289
290 return all_pseudojets;
291}
292
294 const ParticleJetTools::Tag_PseudoJets& tag_pjets,
296 bool doIFN, bool doCMP, bool doGHS, bool doSDF, bool doAKT) {
297
298 int IFN_label = doIFN ? (tag_pjets.IFN_b.size() ? JetIRCSafeLabelTool::LABEL_B :
300 int CMP_label = doCMP ? (tag_pjets.CMP_b.size() ? JetIRCSafeLabelTool::LABEL_B :
302 int GHS_label = doGHS ? (tag_pjets.GHS_b.size() ? JetIRCSafeLabelTool::LABEL_B :
304 int SDF_label = doSDF ? (tag_pjets.SDF_b.size() ? JetIRCSafeLabelTool::LABEL_B :
306 int AKT_label = doAKT ? (tag_pjets.AKT_b.size() ? JetIRCSafeLabelTool::LABEL_B :
308
309 decs.IFNsingleint(jet) = IFN_label;
310 decs.CMPsingleint(jet) = CMP_label;
311 decs.GHSsingleint(jet) = GHS_label;
312 decs.SDFsingleint(jet) = SDF_label;
313 decs.AKTsingleint(jet) = AKT_label;
314}
315
317
318 ATH_MSG_DEBUG(" Initializing... ");
319
320 // Initialize truth jet inputs key
321 ATH_CHECK(m_outTruthPartKey.initialize());
324
325 // Update label names from properties
326 m_ircsafelabelnames.IFNsingleint = m_labelNameIFN.value();
327 m_ircsafelabelnames.CMPsingleint = m_labelNameCMP.value();
328 m_ircsafelabelnames.GHSsingleint = m_labelNameGHS.value();
329 m_ircsafelabelnames.SDFsingleint = m_labelNameSDF.value();
330 m_ircsafelabelnames.AKTsingleint = m_labelNameAKT.value();
331
332 // Build decorators using updated label names
334 std::make_unique<ParticleJetTools::IRCSafeLabelDecorators>(m_ircsafelabelnames);
335
336 // Initialize all algorithms to false
337 m_doAlgo.fill(false);
338
339 // Parse enabled algorithm names from configuration
340 for (const auto& name : m_enabledAlgorithms.value()) {
341 std::string lowerName = toLower(name);
342 bool found = false;
343
344 for (std::size_t i = 0; i < N_ALGOS; ++i) {
345 if (toLower(ALGO_NAMES[i]) == lowerName) {
346 m_doAlgo[i] = true;
347 found = true;
348 break;
349 }
350 }
351
352 if (!found) {
353 ATH_MSG_WARNING("Unknown algorithm in EnabledAlgorithms: " << name);
354 }
355 }
356
357 // Check if any algorithm is enabled
358 bool anyEnabled = false;
359 for (bool enabled : m_doAlgo) {
360 if (enabled) {
361 anyEnabled = true;
362 break;
363 }
364 }
365
366 if (!anyEnabled) {
367 ATH_MSG_WARNING("EnabledAlgorithms is empty; no IRCSafe labelling will be performed.");
368 return StatusCode::SUCCESS;
369 }
370
371 bool doIFN = doAlgo(Algo::IFN);
372 bool doCMP = doAlgo(Algo::CMP);
373
374 // Build FastJet objects using property values
375 m_selectPt = std::make_unique<Selector>(SelectorPtMin(m_truthJetPtMin.value()));
376 m_flavRecombiner = std::make_unique<FlavRecombiner>(FlavRecombiner::net);
377 m_aktJetDef = std::make_unique<JetDefinition>(antikt_algorithm, m_truthR.value());
378 m_aktJetDef->set_recombiner(m_flavRecombiner.get());
379
380 // Interleaved flavour neutralisation - IFN (2306.07314)
381 if (doIFN) {
383 *m_aktJetDef, IFN_RFACTOR, IFN_BETA, FlavRecombiner::net
384 );
385 }
386
387 // Czakon, Mitov, Poncelet (CMP) algorithm - flavour anti-kt (2205.11879)
388 if (doCMP) {
390 m_truthR.value(), CMP_A,
391 CMPPlugin::CorrectionType::OverAllCoshyCosPhi_a2,
392 CMPPlugin::ClusteringType::DynamicKtMax
393 );
394 m_cmpJetDef->set_recombiner(m_flavRecombiner.get());
395 }
396
397 return StatusCode::SUCCESS;
398}
399
400std::vector< std::vector<const PseudoJet*> > JetIRCSafeLabelTool::match(
401 std::vector<PseudoJet>& tagged_pseudojets,
402 const JetContainer& jets) const {
403 ATH_MSG_VERBOSE("In " << name() << "::match()");
404
405 std::vector< std::vector<const PseudoJet*> > jetlabelparts(jets.size(), std::vector<const PseudoJet*>());
406
407 // Loop over pseudojets and find the best matched jet
408 for (unsigned int i_tj = 0; i_tj < tagged_pseudojets.size(); i_tj++) {
409
410 const auto* tag_pjet = &tagged_pseudojets[i_tj];
411
412 double mindr = DBL_MAX;
413 int mindrjetidx = -1;
414
415 for (unsigned int iJet = 0; iJet < jets.size(); iJet++) {
416
417 const Jet& jet = *jets[iJet];
418
419 double pt = jet.pt();
420 if (pt < m_jetPtMin.value())
421 continue;
422
423 double drap = abs(jet.rapidity() - tag_pjet->rap());
424 double dphi = abs(jet.phi() - tag_pjet->phi());
425 if (dphi > numbers::pi) dphi = 2*numbers::pi - dphi;
426 double dr = sqrt(drap*drap + dphi*dphi);
427
428 // Too far for matching criterion
429 if (dr > m_drMax.value())
430 continue;
431
432 // Store the matched jet
433 if (dr < mindr) {
434 mindr = dr;
435 mindrjetidx = iJet;
436 }
437
438 }
439
440 // Store the label particle with the jet
441 if (mindrjetidx >= 0) {
442 jetlabelparts.at(mindrjetidx).push_back(tag_pjet);
443 }
444 }
445
446 return jetlabelparts;
447}
448
449StatusCode JetIRCSafeLabelTool::decorate(const JetContainer& jets) const {
450
451 // Retrieve truth particle collections
455
456 if (!truthPartReadHandle.isValid()) {
457 ATH_MSG_ERROR("Invalid ReadHandle for TruthParticleCollection with key: " << truthPartReadHandle.key());
458 return StatusCode::FAILURE;
459 }
460 if (!bottomReadHandle.isValid()) {
461 ATH_MSG_ERROR("Invalid ReadHandle for bottomPartCollection with key: " << bottomReadHandle.key());
462 return StatusCode::FAILURE;
463 }
464 if (!charmReadHandle.isValid()) {
465 ATH_MSG_ERROR("Invalid ReadHandle for charmPartCollection with key: " << charmReadHandle.key());
466 return StatusCode::FAILURE;
467 }
468
469 // Get algorithm flags
470 bool doIFN = doAlgo(Algo::IFN);
471 bool doCMP = doAlgo(Algo::CMP);
472 bool doGHS = doAlgo(Algo::GHS);
473 bool doSDF = doAlgo(Algo::SDF);
474 bool doAKT = doAlgo(Algo::AKT);
475
476 // Get all pseudo-jets from enabled algorithms
477 std::vector<std::vector<PseudoJet>> all_pseudojets =
478 getJetInputs(*truthPartReadHandle, *bottomReadHandle, *charmReadHandle);
479
480 // Extract b- and c-tagged jets for each algorithm
481 std::vector<PseudoJet> btagged_pseudojetsIFN, ctagged_pseudojetsIFN;
482 std::vector<PseudoJet> btagged_pseudojetsCMP, ctagged_pseudojetsCMP;
483 std::vector<PseudoJet> btagged_pseudojetsGHS, ctagged_pseudojetsGHS;
484 std::vector<PseudoJet> btagged_pseudojetsSDF, ctagged_pseudojetsSDF;
485 std::vector<PseudoJet> btagged_pseudojetsAKT, ctagged_pseudojetsAKT;
486
487 // Extract IFN jets
488 if (doIFN && all_pseudojets.size() > static_cast<std::size_t>(Algo::IFN)) {
489 extractTaggedJets(all_pseudojets[static_cast<std::size_t>(Algo::IFN)],
490 btagged_pseudojetsIFN, ctagged_pseudojetsIFN);
491 }
492
493 // Extract CMP jets
494 if (doCMP && all_pseudojets.size() > static_cast<std::size_t>(Algo::CMP)) {
495 extractTaggedJets(all_pseudojets[static_cast<std::size_t>(Algo::CMP)],
496 btagged_pseudojetsCMP, ctagged_pseudojetsCMP);
497 }
498
499 // Extract GHS jets
500 if (doGHS && all_pseudojets.size() > static_cast<std::size_t>(Algo::GHS)) {
501 extractTaggedJets(all_pseudojets[static_cast<std::size_t>(Algo::GHS)],
502 btagged_pseudojetsGHS, ctagged_pseudojetsGHS);
503 }
504
505 // Extract SDF jets
506 if (doSDF && all_pseudojets.size() > static_cast<std::size_t>(Algo::SDF)) {
507 extractTaggedJets(all_pseudojets[static_cast<std::size_t>(Algo::SDF)],
508 btagged_pseudojetsSDF, ctagged_pseudojetsSDF);
509 }
510
511 // Extract AKT jets
512 if (doAKT && all_pseudojets.size() > static_cast<std::size_t>(Algo::AKT)) {
513 extractTaggedJets(all_pseudojets[static_cast<std::size_t>(Algo::AKT)],
514 btagged_pseudojetsAKT, ctagged_pseudojetsAKT);
515 }
516
517 // Match the tagged pseudojets to reco jets
518 std::vector<std::vector<const PseudoJet*>> jetlabelIFN_b = doIFN ? match(btagged_pseudojetsIFN, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
519 std::vector<std::vector<const PseudoJet*>> jetlabelIFN_c = doIFN ? match(ctagged_pseudojetsIFN, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
520 std::vector<std::vector<const PseudoJet*>> jetlabelCMP_b = doCMP ? match(btagged_pseudojetsCMP, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
521 std::vector<std::vector<const PseudoJet*>> jetlabelCMP_c = doCMP ? match(ctagged_pseudojetsCMP, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
522 std::vector<std::vector<const PseudoJet*>> jetlabelGHS_b = doGHS ? match(btagged_pseudojetsGHS, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
523 std::vector<std::vector<const PseudoJet*>> jetlabelGHS_c = doGHS ? match(ctagged_pseudojetsGHS, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
524 std::vector<std::vector<const PseudoJet*>> jetlabelSDF_b = doSDF ? match(btagged_pseudojetsSDF, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
525 std::vector<std::vector<const PseudoJet*>> jetlabelSDF_c = doSDF ? match(ctagged_pseudojetsSDF, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
526 std::vector<std::vector<const PseudoJet*>> jetlabelAKT_b = doAKT ? match(btagged_pseudojetsAKT, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
527 std::vector<std::vector<const PseudoJet*>> jetlabelAKT_c = doAKT ? match(ctagged_pseudojetsAKT, jets) : std::vector<std::vector<const PseudoJet*>>(jets.size());
528
529 for (unsigned int iJet = 0; iJet < jets.size(); iJet++) {
530 const Jet& jet = *jets[iJet];
531 if (jet.pt() < m_jetPtMin.value()) {
532 m_ircsafelabeldecs->IFNsingleint(jet) = LABEL_DISABLED;
533 m_ircsafelabeldecs->CMPsingleint(jet) = LABEL_DISABLED;
534 m_ircsafelabeldecs->GHSsingleint(jet) = LABEL_DISABLED;
535 m_ircsafelabeldecs->SDFsingleint(jet) = LABEL_DISABLED;
536 m_ircsafelabeldecs->AKTsingleint(jet) = LABEL_DISABLED;
537 continue;
538 }
539
541 tag_pjet.IFN_b = jetlabelIFN_b[iJet];
542 tag_pjet.IFN_c = jetlabelIFN_c[iJet];
543 tag_pjet.CMP_b = jetlabelCMP_b[iJet];
544 tag_pjet.CMP_c = jetlabelCMP_c[iJet];
545 tag_pjet.GHS_b = jetlabelGHS_b[iJet];
546 tag_pjet.GHS_c = jetlabelGHS_c[iJet];
547 tag_pjet.SDF_b = jetlabelSDF_b[iJet];
548 tag_pjet.SDF_c = jetlabelSDF_c[iJet];
549 tag_pjet.AKT_b = jetlabelAKT_b[iJet];
550 tag_pjet.AKT_c = jetlabelAKT_c[iJet];
551
552 setJetIRCSafeLabels(jet, tag_pjet, *m_ircsafelabeldecs, doIFN, doCMP, doGHS, doSDF, doAKT);
553 }
554
555 return StatusCode::SUCCESS;
556}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(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