ATLAS Offline Software
Loading...
Searching...
No Matches
MCRecoToTruth.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#ifndef GENERATIONBASE
8using namespace MCTruthPartClassifier;
9
10std::pair<ParticleType, ParticleOrigin>
12{
13 ATH_MSG_DEBUG("Executing trackClassifier");
14 ParticleType parttype = Unknown;
15 ParticleOrigin partorig = NonDefined;
16 const xAOD::TruthParticle* genPart = getGenPart(trkPtr);
17 if (info) info->genPart = genPart;
18 if (!genPart) return std::make_pair(parttype, partorig);
19 ATH_MSG_DEBUG("trackClassifier succeeded ");
20 return particleTruthClassifier(genPart, info);
21}
22
23std::pair<ParticleType, ParticleOrigin>
25{
26 ATH_MSG_DEBUG("Executing egamma electron Classifier");
27 ParticleType parttype = Unknown;
28 ParticleOrigin partorig = NonDefined;
29 const xAOD::TruthParticle* genPart = nullptr;
30 const xAOD::TrackParticle* trkPtr = elec->trackParticle();
31 if (elec->author() != xAOD::EgammaParameters::AuthorFwdElectron ||trkPtr) {
32 // Central electron or forward electron with track (when reco
33 // implemented in the future)
34 if (!trkPtr){
35 return std::make_pair(parttype, partorig);
36 }
37 genPart = getGenPart(trkPtr);
38 } else {
39#ifndef XAOD_ANALYSIS // cluster matching available only in Athena
40 const xAOD::CaloCluster* clus = elec->caloCluster();
41 genPart = egammaClusMatch(clus, true, info);
42#else
43 ATH_MSG_WARNING("Forward Electron classification using extrapolation to Calo is available only in Athena , check your enviroment. ");
44#endif
45 }
46
47 if (info) info->genPart = genPart;
48 if (!genPart) return std::make_pair(parttype, partorig);
49 ATH_MSG_DEBUG("egamma electron Classifier succeeded ");
50 return particleTruthClassifier(genPart, info);
51}
52
53std::pair<ParticleType, ParticleOrigin>
55{
56 ATH_MSG_DEBUG("Executing egamma photon Classifier");
57 ParticleType parttype = Unknown;
58 ParticleOrigin partorig = NonDefined;
59 const xAOD::CaloCluster* clus = phot->caloCluster();
60 if (!clus) return std::make_pair(parttype, partorig);
61 if (std::fabs(clus->eta()) > 10.0 || std::fabs(clus->phi()) > 6.28 || (clus->et()) <= 0.) return std::make_pair(parttype, partorig);
62
63 const xAOD::Vertex* VxCvPtr = phot->vertex();
64 if (VxCvPtr != nullptr) {
65 for (int itrk = 0; itrk < (int)VxCvPtr->nTrackParticles(); itrk++) {
66 if (itrk > 1) continue;
67 const xAOD::TrackParticle* trkPtr = VxCvPtr->trackParticle(itrk);
68 if (!trkPtr) continue;
69 const xAOD::TruthParticle* thePart = getGenPart(trkPtr);
70 std::pair<ParticleType, ParticleOrigin> classif = particleTruthClassifier(thePart, info);
71 if (info) {
72 info->cnvPhotTrkPtr.push_back(trkPtr);
73 info->cnvPhotTrkToTruthPart.push_back(thePart);
74 info->cnvPhotPartType.push_back(classif.first);
75 info->cnvPhotPartOrig.push_back(classif.second);
76 }
77 }
78 }
79
80 const xAOD::TruthParticle* genPart = nullptr;
81#ifndef XAOD_ANALYSIS // Fwd electron available only in Athena
82 genPart = egammaClusMatch(clus, false, info);
83#else
84 ATH_MSG_WARNING("Photon Classification using extrapolation to Calo is available only in Athena , check your enviroment. ");
85#endif
86 if (!genPart) return std::make_pair(parttype, partorig);
87 if (info) info->genPart = genPart;
88 ATH_MSG_DEBUG("egamma photon Classifier succeeded ");
89 return particleTruthClassifier(genPart, info);
90}
91
92std::pair<ParticleType, ParticleOrigin>
94{
95 ATH_MSG_DEBUG("Executing muon Classifier");
96 ParticleType parttype = Unknown;
97 ParticleOrigin partorig = NonDefined;
98 const xAOD::TrackParticle* trkPtr = mu->primaryTrackParticle();
99
100 if (!trkPtr) return std::make_pair(parttype, partorig);
101
102 const xAOD::TruthParticle* genPart = getGenPart(trkPtr);
103 if (!genPart) return std::make_pair(parttype, partorig);
104 if (info) info->genPart = genPart;
105 ATH_MSG_DEBUG("muon Classifier succeeded ");
106 return particleTruthClassifier(genPart, info);
107}
108
109std::pair<ParticleType, ParticleOrigin>
111{
112 ATH_MSG_DEBUG("Executing egamma photon Classifier with cluster Input");
113 ParticleType parttype = Unknown;
114 ParticleOrigin partorig = NonDefined;
115 if (!clus) return std::make_pair(parttype, partorig);
116 if (std::fabs(clus->eta()) > 10.0 || std::fabs(clus->phi()) > M_PI || (clus->et()) <= 0.) return std::make_pair(parttype, partorig);
117 const xAOD::TruthParticle* genPart = nullptr;
118#ifndef XAOD_ANALYSIS // Fwd electron available only in Athena
119 genPart = egammaClusMatch(clus, false, info);
120#else
121 ATH_MSG_WARNING("Cluster Classification using extrapolation to Calo is available only in Athena , check your enviroment. ");
122#endif
123 if (!genPart) return std::make_pair(parttype, partorig);
124 ATH_MSG_DEBUG("Calo Cluster Classifier succeeded ");
125 if (info) info->genPart = genPart;
126 return particleTruthClassifier(genPart, info);
127}
128
129std::pair<ParticleType, ParticleOrigin>
131{
132 ATH_MSG_DEBUG("Executing Classifier with jet Input");
133 ParticleType parttype = UnknownJet;
134 ParticleOrigin partorig = NonDefined;
135 ParticleType tempparttype = UnknownJet;
136 std::set<const xAOD::TruthParticle*> allJetMothers;
137 std::set<const xAOD::TruthParticle*> constituents;
138 if (!jet) return std::make_pair(parttype, partorig);
139 allJetMothers.clear();
140 constituents.clear();
141 findJetConstituents(jet, constituents, DR);
142 // AV: Jet type is the type of hadron with "heaviest" flavour among the jet constituents.
143 // AV: No hadrons in the jet -- the flavour is unknown.
144 // AV: The algorithm will fail on 4/5 quark hadrons and probably on nonBSM hadrons. To be fixed.
145 for (const auto& thePart: constituents) {
146 MC::findParticleAncestors(thePart, allJetMothers);
147 //AV: probably skip ME particles
148 if (!MC::isPhysical(thePart)) continue;
149 // determine if hadron and its type
150 tempparttype = particleTruthClassifier(thePart, info).first;
151 if (tempparttype != Hadron) continue;
152 tempparttype = defTypeOfHadron(thePart->pdgId());
153 // classify the jet
154 if (tempparttype == BBbarMesonPart || tempparttype == BottomMesonPart || tempparttype == BottomBaryonPart) {
155 parttype = BJet;
156 continue;
157 }
158 if (tempparttype == CCbarMesonPart || tempparttype == CharmedMesonPart || tempparttype == CharmedBaryonPart) {
159 if (parttype != BJet) parttype = CJet;
160 continue;
161 }
162 if (tempparttype == StrangeBaryonPart || tempparttype == LightBaryonPart || tempparttype == StrangeMesonPart || tempparttype == LightMesonPart) {
163 if (parttype != BJet && parttype != CJet) parttype = LJet;
164 continue;
165 }
166 }
167
168 // clasify the jet origin
169 partorig = defJetOrig(allJetMothers);
170 allJetMothers.clear();
171 constituents.clear();
172 ATH_MSG_DEBUG(" jet Classifier succeeded");
173 return std::make_pair(parttype, partorig);
174}
175
178{
179 // return GenParticle corresponding to given TrackParticle
180 ATH_MSG_DEBUG("Executing getGenPart ");
181 if (!trk) return nullptr;
182 if (info) {
183 info->deltaRMatch = -999.;
184 info->deltaPhi = -999.;
185 info->probTrkToTruth = 0;
186 info->numOfSiHits = 0;
187 }
188
189 uint8_t NumOfPixHits = 0;
190 uint8_t NumOfSCTHits = 0;
192
193 static const SG::AuxElement::Accessor<TruthLink_t> tPL("truthParticleLink");
194 if (!tPL.isAvailable(*trk)) {
195 ATH_MSG_DEBUG("Track particle is not associated to truth particle");
196 return nullptr;
197 }
198
199 const auto& truthLink = tPL(*trk);
200 if (!truthLink.isValid()) {
201 ATH_MSG_DEBUG("Invalid link to truth particle");
202 return nullptr;
203 }
204
205 const xAOD::TruthParticle* theGenParticle = (*truthLink);
206 if (!theGenParticle) {
207 ATH_MSG_DEBUG("Could not find truth matching for track");
208 return nullptr;
209 }
210
211 if (info) {
212 static const SG::AuxElement::Accessor<float> tMP("truthMatchProbability");
213 if (tMP.isAvailable(*trk)) {
214 info->probTrkToTruth = tMP(*trk);
215 } else {
216 ATH_MSG_DEBUG("Truth match probability not available");
217 }
218 }
219
220 if (theGenParticle->status() == 3) {
221 ATH_MSG_WARNING("track matched to the truth with status " << theGenParticle->status());
222 }
223 else if (MC::isDecayed(theGenParticle)) {
224 // Matching to status == 2 particles is to be expected if
225 // quasi-stable particle simulation was used.
226 ATH_MSG_DEBUG("track matched to the truth with status " << theGenParticle->status());
227 }
228
229 if (MC::isDecayed(theGenParticle) && (MC::isElectron(theGenParticle) || MC::isMuon(theGenParticle))) {
230 const xAOD::TruthVertex* EndVrtx = theGenParticle->decayVtx();
231 const xAOD::TruthParticle* theGenPartTmp(nullptr);
232
233 if (EndVrtx != nullptr) {
234 int itr = 0;
235 do {
236 theGenPartTmp = nullptr;
237 for (const auto & theDaugt: EndVrtx->particles_out()) {
238 if (!theDaugt) continue;
239 if (theDaugt->pdgId() == theGenParticle->pdgId()) theGenPartTmp = theDaugt;
240 if (theDaugt->pdgId() != theGenParticle->pdgId() && !MC::isPhoton(theDaugt)) theGenPartTmp = nullptr;
241 }
242 itr++;
243 if (itr > 100) {
244 ATH_MSG_WARNING("getGenPart infinite while");
245 break;
246 }
247 EndVrtx = theGenPartTmp ? theGenPartTmp->decayVtx() : nullptr;
248 } while (theGenPartTmp && theGenPartTmp->pdgId() == theGenParticle->pdgId() && MC::isDecayed(theGenPartTmp) && EndVrtx != nullptr);
249
250 if (theGenPartTmp && theGenPartTmp->pdgId() == theGenParticle->pdgId()) theGenParticle = theGenPartTmp;
251 }
252 }
253
254 if (!trk->summaryValue(NumOfSCTHits, xAOD::numberOfSCTHits)) ATH_MSG_DEBUG("Could not retrieve number of SCT hits");
255 if (!trk->summaryValue(NumOfPixHits, xAOD::numberOfPixelHits)) ATH_MSG_DEBUG("Could not retrieve number of Pixel hits");
256
257 uint8_t NumOfSiHits = NumOfSCTHits + NumOfPixHits;
258
259 float deltaPhi = detPhi(theGenParticle->phi(), trk->phi());
260 float deteta = detEta(theGenParticle->eta(), trk->eta());
261 float deltaRMatch = std::hypot(deltaPhi, deteta);
262 if ((NumOfSiHits > m_NumOfSiHitsCut && deltaRMatch > m_deltaRMatchCut) ||
263 (NumOfSiHits <= m_NumOfSiHitsCut && deltaPhi > m_deltaPhiMatchCut)) theGenParticle = nullptr;
264
265 if (info) {
266 info->deltaRMatch = deltaRMatch;
267 info->deltaPhi = deltaPhi;
268 info->numOfSiHits = NumOfSiHits;
269 }
270 ATH_MSG_DEBUG("getGenPart succeeded ");
271 return (theGenParticle);
272}
273
275 std::set<const xAOD::TruthParticle*>& constituents,
276 bool DR) const
277{
278 if (DR) {
279 // use a DR matching scheme (default)
280 // retrieve collection and get a pointer
282
283 if (!truthParticleContainerReadHandle.isValid()) {
284 ATH_MSG_WARNING(" Invalid ReadHandle for xAOD::TruthParticleContainer with key: " << truthParticleContainerReadHandle.key());
285 return;
286 }
287 ATH_MSG_DEBUG("xAODTruthParticleContainer with key " << truthParticleContainerReadHandle.key() << " has valid ReadHandle ");
288 // find the matching truth particles
289 for (const auto *const thePart : *truthParticleContainerReadHandle) {
290 // match truth particles to the jet
291 if (MC::isStable(thePart) && thePart->p4().DeltaR(jet->p4()) < m_jetPartDRMatch) {
292 constituents.insert(thePart);
293 }
294 }
295 }
296 else {
297 xAOD::JetConstituentVector vec = jet->getConstituents();
298 for (const auto *particle0 : vec) {
299 const xAOD::TruthParticle* thePart = dynamic_cast<const xAOD::TruthParticle*>(particle0->rawConstituent());
300 if (MC::isStable(thePart)) {
301 constituents.insert(thePart);
302 }
303 }
304 }
305}
306double MCTruthClassifier::fracParticleInJet(const xAOD::TruthParticle* thePart, const xAOD::Jet* jet, bool DR, bool nparts) const
307{
308 std::set<const xAOD::TruthParticle*> constituents;
309 std::set<const xAOD::TruthParticle*> daughters;
310 std::set<const xAOD::TruthParticle*> intersect;
311
312 findJetConstituents(jet, constituents, DR);
313 MC::findParticleStableDescendants(thePart, daughters);
314 if (daughters.empty()) daughters.insert(thePart);
315 // Get the intersection of constituents and daughters
316 std::set_intersection(constituents.begin(),
317 constituents.end(),
318 daughters.begin(),
319 daughters.end(),
320 std::inserter(intersect, intersect.begin()));
321
322 if (nparts) return 1.0*intersect.size() / daughters.size();
323 double frac = 0;
324 double tot = 0;
325 for (const auto *daughter : daughters) { tot += daughter->pt();}
326 for (const auto *particle : intersect) { frac += particle->pt();}
327 return frac/tot;
328}
329
330#endif
#define M_PI
Scalar deltaPhi(const MatrixBase< Derived > &vec) const
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Handle class for reading from StoreGate.
std::vector< size_t > vec
ElementLink< xAOD::TruthParticleContainer > TruthLink_t
ParticleType
Definition TruthClasses.h:8
@ Hadron
@ StrangeMesonPart
@ UnknownJet
@ CharmedMesonPart
@ BottomMesonPart
@ Unknown
Definition TruthClasses.h:9
@ CJet
@ BJet
@ LightBaryonPart
@ LJet
@ CharmedBaryonPart
@ LightMesonPart
@ CCbarMesonPart
@ BottomBaryonPart
@ StrangeBaryonPart
@ BBbarMesonPart
ParticleOrigin
@ NonDefined
double fracParticleInJet(const xAOD::TruthParticle *, const xAOD::Jet *, bool DR, bool nparts) const
virtual const xAOD::TruthParticle * egammaClusMatch(const xAOD::CaloCluster *, bool, MCTruthPartClassifier::Info *info) const override final
double detEta(double x, double y) const
virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOrigin > particleTruthClassifier(const xAOD::TruthParticle *, MCTruthPartClassifier::Info *info=nullptr) const override final
void findJetConstituents(const xAOD::Jet *, std::set< const xAOD::TruthParticle * > &constituents, bool DR) const
double detPhi(double x, double y) const
SG::ReadHandleKey< xAOD::TruthParticleContainer > m_truthParticleContainerKey
virtual const xAOD::TruthParticle * getGenPart(const xAOD::TrackParticle *, MCTruthPartClassifier::Info *info=nullptr) const override final
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.
virtual double eta() const
The pseudorapidity ( ) of the particle.
virtual double phi() const
The azimuthal angle ( ) of the particle.
uint16_t author(uint16_t bitmask=EgammaParameters::AuthorALL) const
Get author.
const xAOD::CaloCluster * caloCluster(size_t index=0) const
Pointer to the xAOD::CaloCluster/s that define the electron candidate.
const xAOD::TrackParticle * trackParticle(size_t index=0) const
Pointer to the xAOD::TrackParticle/s that match the electron candidate.
A vector of jet constituents at the scale used during jet finding.
const xAOD::Vertex * vertex(size_t index=0) const
Pointer to the xAOD::Vertex/es that match the photon candidate.
Definition Photon_v1.cxx:61
virtual double phi() const override final
The azimuthal angle ( ) of the particle (has range to .).
bool summaryValue(uint8_t &value, const SummaryType &information) const
Accessor for TrackSummary values.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
int status() const
Status code.
int pdgId() const
PDG ID code.
const TruthVertex_v1 * decayVtx() const
The decay vertex of this particle.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
virtual double phi() const override final
The azimuthal angle ( ) of the particle.
std::vector< const TruthParticle * > particles_out() const
Get the outgoing particles.
size_t nTrackParticles() const
Get the number of tracks associated with this vertex.
const TrackParticle * trackParticle(size_t i) const
Get the pointer to a given track that was used in vertex reco.
ParticleOrigin defJetOrig(const T &allJetMothers)
ParticleType defTypeOfHadron(int pdg)
bool isPhoton(const T &p)
bool isElectron(const T &p)
bool isStable(const T &p)
Identify if the particle is stable, i.e. has not decayed.
void findParticleAncestors(T thePart, std::set< T > &allancestors)
Function to find all ancestors of the particle.
bool isMuon(const T &p)
bool isDecayed(const T &p)
Identify if the particle decayed.
void findParticleStableDescendants(T thePart, std::set< T > &allstabledescendants)
Function to get the particle stable MC daughters.
bool isPhysical(const T &p)
Identify if the particle is physical, i.e. is stable or decayed.
const uint16_t AuthorFwdElectron
Electron reconstructed by the Forward cluster-based algorithm.
Definition EgammaDefs.h:30
Jet_v1 Jet
Definition of the current "jet version".
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
TruthVertex_v1 TruthVertex
Typedef to implementation.
Definition TruthVertex.h:15
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Vertex_v1 Vertex
Define the latest version of the vertex class.
TruthParticle_v1 TruthParticle
Typedef to implementation.
Muon_v1 Muon
Reference the current persistent version:
Photon_v1 Photon
Definition of the current "egamma version".
@ numberOfSCTHits
number of hits in SCT [unit8_t].
@ numberOfPixelHits
these are the pixel hits, including the b-layer [unit8_t].
Electron_v1 Electron
Definition of the current "egamma version".