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 = nullptr;
99 if (mu->primaryTrackParticleLink().isValid()) trkPtr = *mu->primaryTrackParticleLink();
100 else if (mu->combinedTrackParticleLink().isValid()) trkPtr = *mu->combinedTrackParticleLink();
101 else if (mu->inDetTrackParticleLink().isValid()) trkPtr = *mu->combinedTrackParticleLink();
102 else if (mu->muonSpectrometerTrackParticleLink().isValid()) trkPtr = *mu->muonSpectrometerTrackParticleLink();
103
104 if (!trkPtr) return std::make_pair(parttype, partorig);
105
106 const xAOD::TruthParticle* genPart = getGenPart(trkPtr);
107 if (!genPart) return std::make_pair(parttype, partorig);
108 if (info) info->genPart = genPart;
109 ATH_MSG_DEBUG("muon Classifier succeeded ");
110 return particleTruthClassifier(genPart, info);
111}
112
113std::pair<ParticleType, ParticleOrigin>
115{
116 ATH_MSG_DEBUG("Executing egamma photon Classifier with cluster Input");
117 ParticleType parttype = Unknown;
118 ParticleOrigin partorig = NonDefined;
119 if (!clus) return std::make_pair(parttype, partorig);
120 if (std::fabs(clus->eta()) > 10.0 || std::fabs(clus->phi()) > M_PI || (clus->et()) <= 0.) return std::make_pair(parttype, partorig);
121 const xAOD::TruthParticle* genPart = nullptr;
122#ifndef XAOD_ANALYSIS // Fwd electron available only in Athena
123 genPart = egammaClusMatch(clus, false, info);
124#else
125 ATH_MSG_WARNING("Cluster Classification using extrapolation to Calo is available only in Athena , check your enviroment. ");
126#endif
127 if (!genPart) return std::make_pair(parttype, partorig);
128 ATH_MSG_DEBUG("Calo Cluster Classifier succeeded ");
129 if (info) info->genPart = genPart;
130 return particleTruthClassifier(genPart, info);
131}
132
133std::pair<ParticleType, ParticleOrigin>
135{
136 ATH_MSG_DEBUG("Executing Classifier with jet Input");
137 ParticleType parttype = UnknownJet;
138 ParticleOrigin partorig = NonDefined;
139 ParticleType tempparttype = UnknownJet;
140 std::set<const xAOD::TruthParticle*> allJetMothers;
141 std::set<const xAOD::TruthParticle*> constituents;
142 if (!jet) return std::make_pair(parttype, partorig);
143 allJetMothers.clear();
144 constituents.clear();
145 findJetConstituents(jet, constituents, DR);
146 // AV: Jet type is the type of hadron with "heaviest" flavour among the jet constituents.
147 // AV: No hadrons in the jet -- the flavour is unknown.
148 // AV: The algorithm will fail on 4/5 quark hadrons and probably on nonBSM hadrons. To be fixed.
149 for (const auto& thePart: constituents) {
150 MC::findParticleAncestors(thePart, allJetMothers);
151 //AV: probably skip ME particles
152 if (!MC::isPhysical(thePart)) continue;
153 // determine if hadron and its type
154 tempparttype = particleTruthClassifier(thePart, info).first;
155 if (tempparttype != Hadron) continue;
156 tempparttype = defTypeOfHadron(thePart->pdgId());
157 // classify the jet
158 if (tempparttype == BBbarMesonPart || tempparttype == BottomMesonPart || tempparttype == BottomBaryonPart) {
159 parttype = BJet;
160 continue;
161 }
162 if (tempparttype == CCbarMesonPart || tempparttype == CharmedMesonPart || tempparttype == CharmedBaryonPart) {
163 if (parttype != BJet) parttype = CJet;
164 continue;
165 }
166 if (tempparttype == StrangeBaryonPart || tempparttype == LightBaryonPart || tempparttype == StrangeMesonPart || tempparttype == LightMesonPart) {
167 if (parttype != BJet && parttype != CJet) parttype = LJet;
168 continue;
169 }
170 }
171
172 // clasify the jet origin
173 partorig = defJetOrig(allJetMothers);
174 allJetMothers.clear();
175 constituents.clear();
176 ATH_MSG_DEBUG(" jet Classifier succeeded");
177 return std::make_pair(parttype, partorig);
178}
179
182{
183 // return GenParticle corresponding to given TrackParticle
184 ATH_MSG_DEBUG("Executing getGenPart ");
185 if (!trk) return nullptr;
186 if (info) {
187 info->deltaRMatch = -999.;
188 info->deltaPhi = -999.;
189 info->probTrkToTruth = 0;
190 info->numOfSiHits = 0;
191 }
192
193 uint8_t NumOfPixHits = 0;
194 uint8_t NumOfSCTHits = 0;
196
197 static const SG::AuxElement::Accessor<TruthLink_t> tPL("truthParticleLink");
198 if (!tPL.isAvailable(*trk)) {
199 ATH_MSG_DEBUG("Track particle is not associated to truth particle");
200 return nullptr;
201 }
202
203 const auto& truthLink = tPL(*trk);
204 if (!truthLink.isValid()) {
205 ATH_MSG_DEBUG("Invalid link to truth particle");
206 return nullptr;
207 }
208
209 const xAOD::TruthParticle* theGenParticle = (*truthLink);
210 if (!theGenParticle) {
211 ATH_MSG_DEBUG("Could not find truth matching for track");
212 return nullptr;
213 }
214
215 if (info) {
216 static const SG::AuxElement::Accessor<float> tMP("truthMatchProbability");
217 if (tMP.isAvailable(*trk)) {
218 info->probTrkToTruth = tMP(*trk);
219 } else {
220 ATH_MSG_DEBUG("Truth match probability not available");
221 }
222 }
223
224 if (theGenParticle->status() == 3) {
225 ATH_MSG_WARNING("track matched to the truth with status " << theGenParticle->status());
226 }
227 else if (MC::isDecayed(theGenParticle)) {
228 // Matching to status == 2 particles is to be expected if
229 // quasi-stable particle simulation was used.
230 ATH_MSG_DEBUG("track matched to the truth with status " << theGenParticle->status());
231 }
232
233 if (MC::isDecayed(theGenParticle) && (MC::isElectron(theGenParticle) || MC::isMuon(theGenParticle))) {
234 const xAOD::TruthVertex* EndVrtx = theGenParticle->decayVtx();
235 const xAOD::TruthParticle* theGenPartTmp(nullptr);
236
237 if (EndVrtx != nullptr) {
238 int itr = 0;
239 do {
240 theGenPartTmp = nullptr;
241 for (const auto & theDaugt: EndVrtx->particles_out()) {
242 if (!theDaugt) continue;
243 if (theDaugt->pdgId() == theGenParticle->pdgId()) theGenPartTmp = theDaugt;
244 if (theDaugt->pdgId() != theGenParticle->pdgId() && !MC::isPhoton(theDaugt)) theGenPartTmp = nullptr;
245 }
246 itr++;
247 if (itr > 100) {
248 ATH_MSG_WARNING("getGenPart infinite while");
249 break;
250 }
251 EndVrtx = theGenPartTmp ? theGenPartTmp->decayVtx() : nullptr;
252 } while (theGenPartTmp && theGenPartTmp->pdgId() == theGenParticle->pdgId() && MC::isDecayed(theGenPartTmp) && EndVrtx != nullptr);
253
254 if (theGenPartTmp && theGenPartTmp->pdgId() == theGenParticle->pdgId()) theGenParticle = theGenPartTmp;
255 }
256 }
257
258 if (!trk->summaryValue(NumOfSCTHits, xAOD::numberOfSCTHits)) ATH_MSG_DEBUG("Could not retrieve number of SCT hits");
259 if (!trk->summaryValue(NumOfPixHits, xAOD::numberOfPixelHits)) ATH_MSG_DEBUG("Could not retrieve number of Pixel hits");
260
261 uint8_t NumOfSiHits = NumOfSCTHits + NumOfPixHits;
262
263 float deltaPhi = detPhi(theGenParticle->phi(), trk->phi());
264 float deteta = detEta(theGenParticle->eta(), trk->eta());
265 float deltaRMatch = std::hypot(deltaPhi, deteta);
266 if ((NumOfSiHits > m_NumOfSiHitsCut && deltaRMatch > m_deltaRMatchCut) ||
267 (NumOfSiHits <= m_NumOfSiHitsCut && deltaPhi > m_deltaPhiMatchCut)) theGenParticle = nullptr;
268
269 if (info) {
270 info->deltaRMatch = deltaRMatch;
271 info->deltaPhi = deltaPhi;
272 info->numOfSiHits = NumOfSiHits;
273 }
274 ATH_MSG_DEBUG("getGenPart succeeded ");
275 return (theGenParticle);
276}
277
279 std::set<const xAOD::TruthParticle*>& constituents,
280 bool DR) const
281{
282 if (DR) {
283 // use a DR matching scheme (default)
284 // retrieve collection and get a pointer
286
287 if (!truthParticleContainerReadHandle.isValid()) {
288 ATH_MSG_WARNING(" Invalid ReadHandle for xAOD::TruthParticleContainer with key: " << truthParticleContainerReadHandle.key());
289 return;
290 }
291 ATH_MSG_DEBUG("xAODTruthParticleContainer with key " << truthParticleContainerReadHandle.key() << " has valid ReadHandle ");
292 // find the matching truth particles
293 for (const auto *const thePart : *truthParticleContainerReadHandle) {
294 // match truth particles to the jet
295 if (MC::isStable(thePart) && thePart->p4().DeltaR(jet->p4()) < m_jetPartDRMatch) {
296 constituents.insert(thePart);
297 }
298 }
299 }
300 else {
301 xAOD::JetConstituentVector vec = jet->getConstituents();
302 for (const auto *particle0 : vec) {
303 const xAOD::TruthParticle* thePart = dynamic_cast<const xAOD::TruthParticle*>(particle0->rawConstituent());
304 if (MC::isStable(thePart)) {
305 constituents.insert(thePart);
306 }
307 }
308 }
309}
310double MCTruthClassifier::fracParticleInJet(const xAOD::TruthParticle* thePart, const xAOD::Jet* jet, bool DR, bool nparts) const
311{
312 std::set<const xAOD::TruthParticle*> constituents;
313 std::set<const xAOD::TruthParticle*> daughters;
314 std::set<const xAOD::TruthParticle*> intersect;
315
316 findJetConstituents(jet, constituents, DR);
317 MC::findParticleStableDescendants(thePart, daughters);
318 if (daughters.empty()) daughters.insert(thePart);
319 // Get the intersection of constituents and daughters
320 std::set_intersection(constituents.begin(),
321 constituents.end(),
322 daughters.begin(),
323 daughters.end(),
324 std::inserter(intersect, intersect.begin()));
325
326 if (nparts) return 1.0*intersect.size() / daughters.size();
327 double frac = 0;
328 double tot = 0;
329 for (const auto *daughter : daughters) { tot += daughter->pt();}
330 for (const auto *particle : intersect) { frac += particle->pt();}
331 return frac/tot;
332}
333
334#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
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
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".