ATLAS Offline Software
Loading...
Searching...
No Matches
TruthSvc.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5// class header
6#include "TruthSvc.h"
7// other ISF_HepMC includes
8// ISF includes
10// Framework
11#include "GaudiKernel/ISvcLocator.h"
13#include "GaudiKernel/SystemOfUnits.h"
14// HepMC includes
17#include "AtlasHepMC/GenEvent.h"
22
23// CLHEP includes
24#include "CLHEP/Geometry/Point3D.h"
25
26// DetectorDescription
28
29#include <sstream>
30
31
32std::vector<HepMC::GenParticlePtr> findChildren(const HepMC::GenParticlePtr& p) {
33 if (!p) return std::vector<HepMC::GenParticlePtr>();
34 const auto& v = p->end_vertex();
35 if (!v) return std::vector<HepMC::GenParticlePtr>();
36#ifdef HEPMC3
37 std::vector<HepMC::GenParticlePtr> ret = v->particles_out();
38#else
39 std::vector<HepMC::GenParticlePtr> ret;
40 for (auto pp=v->particles_out_const_begin();pp!=v->particles_out_const_end();++pp) ret.push_back(*pp);
41#endif
42 if (ret.size()==1) if (ret.at(0)->pdg_id()==p->pdg_id()) ret = findChildren(ret.at(0));
43 return ret;
44}
45
46#undef DEBUG_TRUTHSVC
47
49ISF::TruthSvc::TruthSvc(const std::string& name,ISvcLocator* svc) :
50 base_class(name,svc),
53{
54}
55
58{
59 ATH_MSG_VERBOSE( "initialize()" );
60
61 // Screen output
62 ATH_MSG_DEBUG("--------------------------------------------------------");
63
64 // retrieve BarcodeSvc
65 if ( m_barcodeSvc.retrieve().isFailure() ) {
66 ATH_MSG_FATAL("Could not retrieve BarcodeService. Abort.");
67 return StatusCode::FAILURE;
68 }
69
70 // copy a pointer to the strategy instance to the local
71 // array of pointers (for faster access)
72 ATH_CHECK(m_truthStrategies.retrieve());
73 // Would be nicer to make m_geoStrategies a vector of vectors
74 for ( unsigned short geoID=AtlasDetDescr::fFirstAtlasRegion; geoID<AtlasDetDescr::fNumAtlasRegions; ++geoID) {
75 m_numStrategies[geoID] = 0;
76 for ( const auto &truthStrategy : m_truthStrategies) {
77 if(truthStrategy->appliesToRegion(geoID)) {
78 ++m_numStrategies[geoID];
79 }
80 }
81 }
82 for ( unsigned short geoID=AtlasDetDescr::fFirstAtlasRegion; geoID<AtlasDetDescr::fNumAtlasRegions; ++geoID) {
84 unsigned short curNumStrategies = m_truthStrategies.size();
85 unsigned short nStrat(0);
86 for ( unsigned short i = 0; i < curNumStrategies; ++i) {
87 if(m_truthStrategies[i]->appliesToRegion(geoID)) {
88 m_geoStrategies[geoID][nStrat++] = &(*m_truthStrategies[i]);
89 }
90 }
91
92 // setup whether we want to write end-vertices in this region whenever a truth particle dies
93 // create an end-vertex for all truth particles ending in the current AtlasRegion?
94 bool forceEndVtx = std::find( m_forceEndVtxRegionsVec.begin(),
96 geoID ) != m_forceEndVtxRegionsVec.end();
97 m_forceEndVtx[geoID] = forceEndVtx;
98 }
99 ATH_MSG_VERBOSE("initialize() successful");
100 return StatusCode::SUCCESS;
101}
102
103
106{
107 ATH_MSG_VERBOSE("Finalizing ...");
108 return StatusCode::SUCCESS;
109}
110
111
113StatusCode ISF::TruthSvc::initializeTruthCollection(int largestGeneratedParticleBC, int largestGeneratedVertexBC)
114{
115 ATH_CHECK( m_barcodeSvc->initializeBarcodes(largestGeneratedParticleBC, largestGeneratedVertexBC) );
116 return StatusCode::SUCCESS;
117}
118
120 return StatusCode::SUCCESS;
121}
122
123
125void ISF::TruthSvc::registerTruthIncident( ISF::ITruthIncident& ti, bool saveAllChildren) const {
126
127 const bool passWholeVertex = m_passWholeVertex || saveAllChildren;
128 // pass whole vertex or individual child particles
129 ti.setPassWholeVertices(passWholeVertex);
130
131 // the GeoID
133
134 // check geoID assigned to the TruthIncident
135 if ( !validAtlasRegion(geoID) ) {
136 const auto& position = ti.position();
137 ATH_MSG_ERROR("Unable to register truth incident with unknown SimGeoID="<< geoID
138 << " at position z=" << position.z() << " r=" << position.perp());
139 return;
140 }
141
142 ATH_MSG_VERBOSE( "Registering TruthIncident for SimGeoID="
144
145 // number of child particles
146 const unsigned short numSec = ti.numberOfChildren();
147 if ( m_skipIfNoChildren && (numSec==0) ) {
148 ATH_MSG_VERBOSE( "No child particles present in the TruthIncident,"
149 << " will not record this TruthIncident.");
150 return;
151 }
152
153 // the parent particle -> get its id
154 const int parentID = ti.parentUniqueID();
155 if ( m_skipIfNoParentId && (parentID == HepMC::UNDEFINED_ID) ) {
156 ATH_MSG_VERBOSE( "Parent particle in TruthIncident does not have an id,"
157 << " will not record this TruthIncident.");
158 return;
159 }
160
161 // loop over registered truth strategies for given geoID
162 bool pass = false;
163 for ( unsigned short stratID=0; (!pass) && (stratID<m_numStrategies[geoID]); stratID++) {
164 // (*) test if given TruthIncident passes current strategy
165 pass = m_geoStrategies[geoID][stratID]->pass(ti);
166 }
167
168 if (pass) {
169 ATH_MSG_VERBOSE("At least one TruthStrategy passed.");
170 // at least one truth strategy returned true
171 // -> record incident
172 recordIncidentToMCTruth(ti, passWholeVertex);
173
174 } else {
175 // none of the truth strategies returned true
176 // -> child particles will NOT be added to the TruthEvent collection
177 // attach parent particle end vertex if it gets killed by this interaction
178 if ( m_forceEndVtx[geoID] && !ti.parentSurvivesIncident() ) {
179 ATH_MSG_VERBOSE("No TruthStrategies passed and parent destroyed - create end vertex.");
181
182#ifdef DEBUG_TRUTHSVC
183 const std::string survival = (ti.parentSurvivesIncident()) ? "parent survives" : "parent destroyed";
184 const std::string vtxType = (ti.interactionClassification()==ISF::STD_VTX) ? "Normal" : "Quasi-stable";
185 ATH_MSG_INFO("TruthSvc: " << vtxType << " vertex + " << survival
186 << ", TI Class: " << ti.interactionClassification()
187 << ", ProcessType: " << ti.physicsProcessCategory()
188 << ", ProcessSubType: " << ti.physicsProcessCode());
189#endif
190
191 }
192
193 }
194
195 return;
196}
197
199void ISF::TruthSvc::recordIncidentToMCTruth( ISF::ITruthIncident& ti, bool passWholeVertex) const {
200#ifdef DEBUG_TRUTHSVC
201 ATH_MSG_INFO("Starting recordIncidentToMCTruth(...)");
202#endif
203 int parentBC = ti.parentBarcode();
204
205 if (ti.parentParticle()->end_vertex()) {
206 ATH_MSG_WARNING ("Attempting to record a TruthIncident for a particle which has already decayed!");
207 ATH_MSG_WARNING ("No action will be taken - please fix client code.");
208 return;
209 }
210
211 // record the GenVertex
213 const ISF::InteractionClass_t classification = ti.interactionClassification();
214#ifdef DEBUG_TRUTHSVC
215 const std::string survival = (ti.parentSurvivesIncident()) ? "parent survives" : "parent destroyed";
216 const std::string vtxType = (ti.interactionClassification()==ISF::STD_VTX) ? "Normal" : "Quasi-stable";
217 ATH_MSG_INFO("TruthSvc: " << vtxType << " vertex + " << survival
218 << ", TI Class: " << ti.interactionClassification()
219 << ", ProcessType: " << ti.physicsProcessCategory()
220 << ", ProcessSubType: " << ti.physicsProcessCode());
221#endif
222
223 ATH_MSG_VERBOSE ( "Outgoing particles:" );
224 // update parent barcode and add it to the vertex as outgoing particle
225 int newPrimaryBC = HepMC::UNDEFINED_ID;
226 if (classification == ISF::QS_SURV_VTX) {
227 // Special case when a particle with a pre-defined decay interacts
228 // and survives.
229 // Set the barcode to the next available value below the simulation
230 // barcode offset.
231 newPrimaryBC = m_barcodeSvc->newGeneratedParticle(parentBC);
232 }
233 else {
234 newPrimaryBC = parentBC + HepMC::SIM_REGENERATION_INCREMENT;
235 }
236
237 HepMC::GenParticlePtr parentAfterIncident = ti.parentParticleAfterIncident( newPrimaryBC ); // This call changes ti.parentParticle() output
238 if(parentAfterIncident) {
239 if (classification==ISF::QS_SURV_VTX) {
240 // Special case when a particle with a pre-defined decay
241 // interacts and survives.
242 // As the parentParticleAfterIncident has a pre-defined decay
243 // its status should end in 2, but we should flag that it has
244 // survived an interaction.
245 if (!MC::isDecayed(parentAfterIncident)) {
246 ATH_MSG_WARNING ( "recordIncidentToMCTruth - check parentAfterIncident: " << parentAfterIncident );
247 }
248 }
249 vtxFromTI->add_particle_out( parentAfterIncident );
250#ifdef HEPMC3
251 HepMC::suggest_barcode( parentAfterIncident, newPrimaryBC ); // TODO check this works correctly
252#endif
253 // NB For ISFTruthIncident the m_parent ISFParticle still needs
254 // its id and particleLink properties to be properly updated at
255 // this point.
256 ATH_MSG_VERBOSE ( "Parent After Incident: " << parentAfterIncident << ", barcode: " << HepMC::barcode(parentAfterIncident));
257 }
258
259 const bool isQuasiStableVertex = (classification == ISF::QS_PREDEF_VTX); // QS_DEST_VTX and QS_SURV_VTX should be treated as normal from now on.
260 // add child particles to the vertex
261 const unsigned short numSec = ti.numberOfChildren();
262 for ( unsigned short i=0; i<numSec; ++i) {
263 bool writeOutChild = isQuasiStableVertex || passWholeVertex || ti.childPassedFilters(i);
264 if (writeOutChild) {
265 HepMC::GenParticlePtr p = nullptr;
266 // generate a new barcode for the child particle
267 int secondaryParticleBC = (isQuasiStableVertex) ?
268 m_barcodeSvc->newGeneratedParticle(parentBC) : m_barcodeSvc->newSecondaryParticle(parentBC); // TODO replace m_barcodeSvc
269 if ( secondaryParticleBC == HepMC::UNDEFINED_ID) {
271 ATH_MSG_WARNING("Unable to generate new Secondary Particle Barcode. Continuing due to 'IgnoreUndefinedBarcodes'==True");
272 else {
273 ATH_MSG_ERROR("Unable to generate new Secondary Particle Barcode. Aborting");
274 abort();
275 }
276 }
277 p = ti.childParticle( i, secondaryParticleBC ); // potentially overrides secondaryParticleBC
278 if (p) {
279 // add particle to vertex
280 vtxFromTI->add_particle_out( p);
281#ifdef HEPMC3
282 int secondaryParticleBCFromTI = ti.childBarcode(i);
283 HepMC::suggest_barcode( p, secondaryParticleBCFromTI ? secondaryParticleBCFromTI : secondaryParticleBC );
284 // NB For ISFTruthIncident the current child ISFParticle still needs
285 // its id and particleLink properties to be properly updated at
286 // this point.
287#endif
288 }
289 ATH_MSG_VERBOSE ( "Writing out " << i << "th child particle: " << p << ", barcode: " << HepMC::barcode(p));
290 } // <-- if write out child particle
291 else {
292 ATH_MSG_VERBOSE ( "Not writing out " << i << "th child particle." );
293 }
294
295 } // <-- loop over all child particles
296 ATH_MSG_VERBOSE("--------------------------------------------------------");
297}
298
301
302 int processCode = ti.physicsProcessCode();
303 int parentBC = ti.parentBarcode();
304
305 std::vector<double> weights(1);
306 int primaryBC = parentBC % HepMC::SIM_REGENERATION_INCREMENT;
307 weights[0] = static_cast<double>( primaryBC ); // FIXME vertex weights should not be used to encode other info.
308
309 // Check for a previous end vertex on this particle. If one existed, then we should put down next to this
310 // a new copy of the particle. This is the agreed upon version of the quasi-stable particle truth, where
311 // the vertex at which we start Q-S simulation no longer conserves energy, but we keep both copies of the
312 // truth particles
314 if (!parent) {
315 ATH_MSG_ERROR("Unable to write particle interaction to MC truth due to missing parent HepMC::GenParticle instance");
316 abort();
317 }
318 HepMC::GenEvent *mcEvent = parent->parent_event();
319 if (!mcEvent) {
320 ATH_MSG_ERROR("Unable to write particle interaction to MC truth due to missing parent HepMC::GenEvent instance");
321 abort();
322 }
323
324 // generate vertex
325 int vtxbcode = m_barcodeSvc->newSimulationVertex(); // TODO replace barcodeSvc
326 if ( vtxbcode == HepMC::UNDEFINED_ID) {
328 ATH_MSG_WARNING("Unable to generate new Truth Vertex Barcode. Continuing due to 'IgnoreUndefinedBarcodes'==True");
329 } else {
330 ATH_MSG_ERROR("Unable to generate new Truth Vertex Barcode. Aborting");
331 abort();
332 }
333 }
334 const int vtxStatus = 1000 + static_cast<int>(processCode) + HepMC::SIM_STATUS_THRESHOLD;
335#ifdef HEPMC3
336 auto newVtx = HepMC::newGenVertexPtr( ti.position(),vtxStatus);
337#else
338 // NB In HepMC2 there is no GenVertex status, so we set the GenVertex ID.
339 std::unique_ptr<HepMC::GenVertex> newVtx = std::make_unique<HepMC::GenVertex>( ti.position(), vtxStatus, weights );
340 HepMC::suggest_barcode( newVtx.get(), vtxbcode );
341#endif
342
343 if (parent->end_vertex()){
344 ATH_MSG_ERROR ("createGVfromTI: Parent particle found with an end vertex attached. This should not happen!");
345 ATH_MSG_ERROR ("createGVfromTI: Parent 1: " << parent << ", barcode: " << HepMC::barcode(parent));
346 ATH_MSG_ERROR ( "createGVfromTI: parent->end_vertex(): " << parent->end_vertex() << ", barcode: " << HepMC::barcode(parent->end_vertex()) );
347 abort();
348 } else { // Normal simulation
349#ifdef DEBUG_TRUTHSVC
350 ATH_MSG_VERBOSE ("createGVfromTI Parent 1: " << parent << ", barcode: " << HepMC::barcode(parent));
351#endif
352 // add parent particle to newVtx
353 newVtx->add_particle_in( parent );
354#ifdef DEBUG_TRUTHSVC
355 ATH_MSG_VERBOSE ( "createGVfromTI End Vertex representing process: " << processCode << ", for parent with barcode "<<parentBC<<". Creating." );
356 ATH_MSG_VERBOSE ( "createGVfromTI Parent 2: " << parent << ", barcode: " << HepMC::barcode(parent));
357#endif
358#ifdef HEPMC3
359 mcEvent->add_vertex(newVtx);
360 HepMC::suggest_barcode( newVtx, vtxbcode );
361 newVtx->add_attribute("weights",std::make_shared<HepMC3::VectorDoubleAttribute>(weights));
362#else
363 mcEvent->add_vertex( newVtx.release() );
364#endif
365 }
366
367 return parent->end_vertex();
368}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
bool validAtlasRegion(AtlasDetDescr::AtlasRegion region)
Check a given AtlasRegion for its validity.
Definition AtlasRegion.h:40
ATLAS-specific HepMC functions.
std::vector< HepMC::GenParticlePtr > findChildren(const HepMC::GenParticlePtr &p)
Definition TruthSvc.cxx:32
static const char * getName(int region)
ISF interface class for TruthIncidents.
virtual int physicsProcessCategory() const =0
Return category of the physics process represented by the truth incident (eg hadronic,...
virtual int physicsProcessCode() const =0
Return specific physics process code of the truth incident (eg ionisation, bremsstrahlung,...
virtual ISF::InteractionClass_t interactionClassification() const
The interaction classifications are described as follows: STD_VTX: interaction of a particle without ...
virtual int parentBarcode()=0
Return the barcode of the parent particle.
virtual HepMC::GenParticlePtr parentParticle()=0
Return the parent particle as a HepMC particle type (only called for particles that will enter the He...
bool childPassedFilters(unsigned short index) const
Should a particular child be written out to the GenEvent.
virtual HepMC::GenParticlePtr childParticle(unsigned short index, int bc=HepMC::UNDEFINED_ID)=0
Return the i-th child as a HepMC particle type and assign the given Barcode to the simulator particle...
unsigned short numberOfChildren() const
Return total number of child particles.
AtlasDetDescr::AtlasRegion geoID()
Return the SimGeoID corresponding to the vertex of the truth incident.
virtual int parentUniqueID()=0
Return the unique ID of the parent particle.
virtual HepMC::GenParticlePtr parentParticleAfterIncident(int newBC)=0
Return the parent particle after the TruthIncident vertex (and assign a new barcode to it)
void setPassWholeVertices(bool passWholeVertex)
Set whether this TruthIncident should pass the vertex as a whole or individual children.
virtual bool parentSurvivesIncident() const =0
Return a boolean whether or not the parent particle survives the incident.
virtual int childBarcode(unsigned short index) const =0
Return the barcode of the i-th child particle (if defined as part of the TruthIncident) otherwise ret...
virtual const HepMC::FourVector & position() const =0
Return HepMC position of the truth vertex.
StatusCode initializeTruthCollection(int largestGeneratedParticleBC=0, int largestGeneratedVertexBC=0) override
Initialize the Truth Svc at the beginning of each event.
Definition TruthSvc.cxx:113
Gaudi::Property< bool > m_passWholeVertex
Definition TruthSvc.h:96
ServiceHandle< Barcode::IBarcodeSvc > m_barcodeSvc
The Barcode service.
Definition TruthSvc.h:83
void registerTruthIncident(ITruthIncident &truthincident, bool saveAllChildren=false) const override
Register a truth incident.
Definition TruthSvc.cxx:125
unsigned short m_numStrategies[AtlasDetDescr::fNumAtlasRegions]
Definition TruthSvc.h:89
HepMC::GenVertexPtr createGenVertexFromTruthIncident(ITruthIncident &truthincident) const
Record and end vertex to the MC Truth for the parent particle.
Definition TruthSvc.cxx:300
Gaudi::Property< std::vector< unsigned int > > m_forceEndVtxRegionsVec
property containing AtlasRegions for which
Definition TruthSvc.h:98
StatusCode finalize() override
Athena algorithm's interface method finalize()
Definition TruthSvc.cxx:105
StatusCode releaseEvent() override
Finalize the Truth Svc at the end of each event.
Definition TruthSvc.cxx:119
TruthSvc(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
Definition TruthSvc.cxx:49
void recordIncidentToMCTruth(ITruthIncident &truthincident, bool passWholeVertex) const
Record the given truth incident to the MC Truth.
Definition TruthSvc.cxx:199
Gaudi::Property< bool > m_skipIfNoChildren
MCTruth steering.
Definition TruthSvc.h:92
ITruthStrategy ** m_geoStrategies[AtlasDetDescr::fNumAtlasRegions]
for faster access: using an internal pointer to the actual ITruthStrategy instances
Definition TruthSvc.h:88
ToolHandleArray< ITruthStrategy > m_truthStrategies
the truth strategies applied (as AthenaToolHandle Array)
Definition TruthSvc.h:86
Gaudi::Property< bool > m_ignoreUndefinedBarcodes
do/don't abort if retrieve an undefined barcode
Definition TruthSvc.h:94
std::array< bool, AtlasDetDescr::fNumAtlasRegions > m_forceEndVtx
attach end vertex to
Definition TruthSvc.h:100
StatusCode initialize() override
Athena algorithm's interface method initialize()
Definition TruthSvc.cxx:57
Gaudi::Property< bool > m_skipIfNoParentId
do not record if parentId == HepMC::UNDEFINED_ID
Definition TruthSvc.h:93
AtlasRegion
A simple enum of ATLAS regions and sub-detectors.
Definition AtlasRegion.h:21
int barcode(const T *p)
Definition Barcode.h:16
constexpr int UNDEFINED_ID
HepMC::GenVertex * GenVertexPtr
Definition GenVertex.h:59
constexpr int SIM_STATUS_THRESHOLD
Constant definiting the status threshold for simulated particles, eg. can be used to separate generat...
bool suggest_barcode(T &p, int i)
Definition GenEvent.h:672
GenVertexPtr newGenVertexPtr(const HepMC::FourVector &pos=HepMC::FourVector(0.0, 0.0, 0.0, 0.0), const int i=0)
Definition GenVertex.h:64
GenParticle * GenParticlePtr
Definition GenParticle.h:37
constexpr int SIM_REGENERATION_INCREMENT
Constant defining the barcode threshold for regenerated particles, i.e. particles surviving an intera...
InteractionClass_t
The interaction classifications are described as follows: STD_VTX: interaction of a particle without ...
@ QS_SURV_VTX
@ QS_PREDEF_VTX
bool isDecayed(const T &p)
Identify if the particle decayed.