ATLAS Offline Software
Loading...
Searching...
No Matches
ParticleJetLabelCommon.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
8
9// private internal functions
10namespace {
11 // this returns a charm child if it exists, otherwise returns the
12 // particle itself. If the truth record contains broken links return
13 // a nullptr.
14 const xAOD::TruthParticle* getCharmChild(const xAOD::TruthParticle* p) {
15 for (unsigned int n = 0; n < p->nChildren(); n++) {
16 const xAOD::TruthParticle* child = p->child(n);
17 // nullptr would indicate a broken truth record, but the rest of
18 // the code lets this pass silently so we'll do the same here.
19 if (!child) return nullptr;
20 if (MC::hasCharm(child->pdgId())) {
21 return getCharmChild(child);
22 }
23 }
24 return p;
25 }
26}
27
28namespace ParticleJetTools {
29
30 // the code below is taken from ParticleJetDeltaRLabelTool with
31 // minimal modification
32 // --------------------------------------------------------------
33
34 inline bool isChild( const xAOD::TruthParticle* p, const xAOD::TruthParticle* c) {
35
36 if ( HepMC::is_same_particle(p,c) ) { return false; }
37
38 for (size_t iC = 0; iC < p->nChildren(); iC++) {
39 const xAOD::TruthParticle* cc = p->child(iC);
40 if (!cc) { continue; }
41
42 if ( HepMC::is_same_particle(cc,c) ) { return true; }
43
44 if (isChild(cc, c)) { return true; }
45 }
46
47 return false;
48 }
49
51 if (!p) return {NAN, NAN, NAN};
52 return {p->x(), p->y(), p->z()};
53 }
55 return {j.px(), j.py(), j.pz()};
56 }
58 if (events.empty()) return {NAN, NAN, NAN};
59 return p3(events.at(0)->signalProcessVertex());
60 }
61
62
64 ( const std::vector<const xAOD::TruthParticle*>& parents
65 , std::vector<const xAOD::TruthParticle*>& children
66 ) {
67
68 if ( &parents == &children ) {
69 // Same vector provided for both inputs. Extra care needed in
70 // this case...
71 const std::vector<const xAOD::TruthParticle*> copyParents = parents;
72 childrenRemoved(copyParents, children);
73 return;
74 }
75 // We can now safely assume that parents will not be modified
76 // during this loop.
77 for ( const xAOD::TruthParticle* p : parents ) {
78 if (!p) continue;
79 children.erase(std::remove_if(children.begin(),
80 children.end(),
81 [p](const xAOD::TruthParticle* c) { return (c && isChild(p, c)); }),
82 children.end());
83 // auto erased = std::erase_if(children, [p](const xAOD::TruthParticle* c) { return (c && isChild(p, c)); }); // C++20
84 }
85 return;
86 }
87
88
89 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
90 // End of code copied from ParticleJetDeltaRLabelTool
91
93 auto chk = [](const std::string& s, const std::string& varname) {
94 if (s.empty()) throw std::runtime_error(
95 "name for '" + varname + "' is not specified in particle jet tools"
96 " configuration");
97 };
98#define CHECK(var) chk(var, #var)
101 CHECK(pt);
102 CHECK(Lxy);
103 CHECK(dr);
104 CHECK(pdgId);
109 CHECK(childPt);
113#undef CHECK
114 }
115
119 pt(n.pt),
120 Lxy(n.Lxy),
121 dr(n.dr),
122 pdgId(n.pdgId),
127 childPt(n.childPt),
131 // ATLASRECTS-8290: this is for backward compatability, remove eventually
132 acc_uid(n.useBarcode ? "barcode" : "uid")
133 {
134 }
135
136
137 // key might be added back if we figure out how to get the store
138 // gate key from a read handle in analysis base
141 const std::string& linkname):
142 m_dec(linkname)
143 {
144 }
146 const xAOD::Jet& jet,
147 const std::vector<const xAOD::TruthParticle*>& ipv) const
148 {
149 IPLV links;
150 for (const xAOD::TruthParticle* ip: ipv) {
151 // I copied this whole song and dance from setAssociatedObjects
152 // in the jet edm. It would be much easier if we could store the
153 // container hash in this object and use ElementLink(sgkey,
154 // index) but that seems to break in AnalysisBase
155 IPLV::value_type link;
156 const auto* ipc = dynamic_cast<const xAOD::IParticleContainer*>(
157 ip->container());
158 link.toIndexedElement(*ipc, ip->index());
159 links.push_back(link);
160 }
161 m_dec(jet) = std::move(links);
162 }
163
165 const Particles& particles,
166 const LabelDecorators& decs) {
167
168 // we also want to save information about the maximum pt particle of the labeling partons
169 auto getMaxPtPart = [](const auto& container) -> const xAOD::TruthParticle* {
170 if (container.size() == 0) return nullptr;
171 auto itr = std::max_element(container.begin(), container.end(),
172 [](auto* p1, auto* p2) {
173 return p1->pt() < p2->pt();
174 });
175 return *itr;
176 };
177
178 // set truth label for jets above pt threshold
179 // hierarchy: b > c > tau > light
180 int label = 0; // default: light
181 const xAOD::TruthParticle* labelling_particle = nullptr;
182 const xAOD::TruthParticle* child_particle = nullptr;
183 if (particles.b.size()) {
184 label = 5;
185 labelling_particle = getMaxPtPart(particles.b);
186 child_particle = getCharmChild(labelling_particle);
187 } else if (particles.c.size()) {
188 label = 4;
189 labelling_particle = getMaxPtPart(particles.c);
190 } else if (particles.tau.size()) {
191 label = 15;
192 labelling_particle = getMaxPtPart(particles.tau);
193 }
194
195 const Amg::Vector3D& origin = particles.origin;
196
197 // decorate info about the labelling particle
198 decs.singleint(jet) = label;
199 if (label == 0) {
200 decs.pt(jet) = NAN;
201 decs.Lxy(jet) = NAN;
202 decs.dr(jet) = NAN;
203 decs.pdgId(jet) = 0;
204 decs.positionDPhi(jet) = NAN;
205 decs.positionDEta(jet) = NAN;
207 decs.childLxy(jet) = NAN;
208 decs.childPt(jet) = NAN;
209 decs.childPdgId(jet) = 0;
210 decs.childPositionDPhi(jet) = NAN;
211 decs.childPositionDEta(jet) = NAN;
212 } else {
213 decs.pt(jet) = partPt(labelling_particle);
214 decs.Lxy(jet) = partLxy(labelling_particle, origin);
215 decs.dr(jet) = partDR(labelling_particle, jet);
216 decs.pdgId(jet) = partPdgId(labelling_particle);
217 decs.positionDPhi(jet) = positionDPhi(labelling_particle, jet, origin);
218 decs.positionDEta(jet) = positionDEta(labelling_particle, jet, origin);
219 decs.uniqueID(jet) = labelling_particle ?
220 // ATLASRECTS-8290: this should be replaced with ->uid()
221 decs.acc_uid(*labelling_particle) : HepMC::INVALID_PARTICLE_ID;
222 decs.childLxy(jet) = partLxy(child_particle, origin);
223 decs.childPt(jet) = partPt(child_particle);
224 decs.childPdgId(jet) = partPdgId(child_particle);
225 decs.childPositionDPhi(jet) = positionDPhi(child_particle, jet, origin);
226 decs.childPositionDEta(jet) = positionDEta(child_particle, jet, origin);
227 }
228
229 // extended flavour label
230 int double_label = 0;
231 if (particles.b.size()) {
232 if (particles.b.size() >= 2)
233 double_label = 55;
234
235 else if (particles.c.size())
236 double_label = 54;
237
238 else
239 double_label = 5;
240
241 } else if (particles.c.size()) {
242 if (particles.c.size() >= 2)
243 double_label = 44;
244
245 else
246 double_label = 4;
247
248 } else if (particles.tau.size()){
249
250 bool hasElectrondecay = false;
251 bool hasMuondecay = false;
252 bool hasHadronicdecay = false;
253 for (auto itau: particles.tau){
254 for (size_t i = 0; i< itau->nChildren(); i++){ // tau children loop
255 if (itau->child(i)->absPdgId() == 12 || itau->child(i)->absPdgId() == 14 || itau->child(i)->absPdgId() == 16) continue;
256 if (MC::isMuon(itau->child(i))) hasMuondecay = true;
257 else if (MC::isElectron(itau->child(i))) hasElectrondecay = true;
258 else hasHadronicdecay = true;
259 }
260 }
261
262 if (particles.tau.size() >= 2){
263 // check if we have at least one hadronic tau
264 if (hasHadronicdecay){
265 // check if we have also tau->mu decay
266 if (hasMuondecay) double_label = 151513;
267 // check if we have also tau->el decay
268 else if (hasElectrondecay) double_label = 151511;
269 // otherwise fully hadronic di-tau decay
270 else double_label = 1515;
271 }
272 } else {
273 // only consider hadronic tau decay
274 if (hasHadronicdecay) double_label = 15;
275 }
276
277 }
278
279 decs.doubleint(jet) = double_label;
280
281 }
282
284 const Particles& particles,
285 const LabelNames& names) {
286 setJetLabels(jet, particles, LabelDecorators(names));
287 }
288
289 float partPt(const xAOD::TruthParticle* part) {
290 if (!part) return NAN;
291 return part->pt();
292 }
293 float partLxy(const xAOD::TruthParticle* part, const Amg::Vector3D& origin) {
294 if (!part) return NAN;
295 if (const auto* vx = part->decayVtx() ) return (p3(vx) - origin).perp();
296 return INFINITY;
297 }
298 float partDR(const xAOD::TruthParticle* part, const xAOD::Jet& jet) {
299 if (!part) return NAN;
300 return part->p4().DeltaR(jet.p4());
301 }
303 if (!part) return 0;
304 return part->pdgId();
305 }
307 const xAOD::Jet& jet,
308 const Amg::Vector3D& origin) {
309 if (!part) return NAN;
310 if (const auto* vx = part->decayVtx() ) {
311 Amg::Vector3D displacement = p3(vx) - origin;
312 return p3(jet).deltaPhi(displacement);
313 }
314 return INFINITY;
315 }
317 const xAOD::Jet& jet,
318 const Amg::Vector3D& origin) {
319 if (!part) return NAN;
320 if (const auto* vx = part->decayVtx() ) {
321 Amg::Vector3D displacement = p3(vx) - origin;
322 return displacement.eta() - jet.eta();
323 }
324 return INFINITY;
325 }
326
327}
#define CHECK(...)
Evaluate an expression and check for errors.
ATLAS-specific HepMC functions.
SG::AuxElement::Decorator< IPLV > m_dec
void decorate(const xAOD::Jet &, const std::vector< const xAOD::TruthParticle * > &) const
std::vector< ElementLink< xAOD::IParticleContainer > > IPLV
IParticleLinker(const SG::ReadHandleKey< xAOD::TruthParticleContainer > &, const std::string &linkName)
Property holding a SG store/key/clid from which a ReadHandle is made.
float py() const
The y-component of the jet's momentum.
Definition Jet_v1.cxx:94
float px() const
The x-component of the jet's momentum.
Definition Jet_v1.cxx:90
float pz() const
The z-component of the jet's momentum.
Definition Jet_v1.cxx:99
int pdgId() const
PDG ID code.
std::string label(const std::string &format, int i)
Definition label.h:19
Eigen::Matrix< double, 3, 1 > Vector3D
constexpr int INVALID_PARTICLE_ID
bool is_same_particle(const T1 &p1, const T2 &p2)
Method to establish if two particles in the GenEvent actually represent the same particle.
bool hasCharm(const T &p)
bool isElectron(const T &p)
bool isMuon(const T &p)
void setJetLabels(const xAOD::Jet &jet, const Particles &particles, const LabelNames &names)
float positionDEta(const xAOD::TruthParticle *part, const xAOD::Jet &jet, const Amg::Vector3D &origin)
float partDR(const xAOD::TruthParticle *part, const xAOD::Jet &jet)
float partPt(const xAOD::TruthParticle *part)
Amg::Vector3D p3(const xAOD::TruthVertex *p)
void childrenRemoved(const std::vector< const xAOD::TruthParticle * > &parents, std::vector< const xAOD::TruthParticle * > &children)
bool isChild(const xAOD::TruthParticle *p, const xAOD::TruthParticle *c)
Amg::Vector3D signalProcessP3(const xAOD::TruthEventContainer &)
float partLxy(const xAOD::TruthParticle *part, const Amg::Vector3D &origin)
float positionDPhi(const xAOD::TruthParticle *part, const xAOD::Jet &jet, const Amg::Vector3D &origin)
int partPdgId(const xAOD::TruthParticle *part)
DataModel_detail::iterator< DVL > remove_if(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, Predicate pred)
Specialization of remove_if for DataVector/List.
Jet_v1 Jet
Definition of the current "jet version".
TruthEventContainer_v1 TruthEventContainer
Declare the latest version of the truth event container.
TruthVertex_v1 TruthVertex
Typedef to implementation.
Definition TruthVertex.h:15
TruthParticle_v1 TruthParticle
Typedef to implementation.
DataVector< IParticle > IParticleContainer
Simple convenience declaration of IParticleContainer.
SG::AuxElement::Decorator< float > childPositionDEta
SG::AuxElement::Decorator< int > uniqueID
SG::AuxElement::Decorator< int > pdgId
SG::AuxElement::Decorator< float > pt
SG::AuxElement::Decorator< int > doubleint
SG::AuxElement::Decorator< float > Lxy
SG::AuxElement::Decorator< float > dr
SG::AuxElement::Decorator< int > childPdgId
SG::AuxElement::Decorator< float > positionDEta
SG::AuxElement::Decorator< float > childPositionDPhi
SG::AuxElement::Decorator< float > positionDPhi
SG::AuxElement::Decorator< float > childLxy
SG::AuxElement::Decorator< float > childPt
SG::AuxElement::Decorator< int > singleint