ATLAS Offline Software
Loading...
Searching...
No Matches
ParticleBrokerDynamicOnReadIn.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// class header
7
8// ISF includes
12
14
15// DetectorDescription
17
18// Benchmarking
20
21// ROOT includes
22#include "TTree.h"
23
24#include <utility>
25
26// C include
27#include <assert.h>
28
31 base_class(name,svc),
37{
38}
39
40
43
44
47{
48 ATH_MSG_DEBUG("initialize() ...");
49
50 // retrieve the entry layer tool
51 ATH_CHECK ( m_entryLayerTool.retrieve() );
52
53 // retrieve the particle ing tool if given
54 ATH_CHECK ( m_orderingTool.retrieve( DisableTool{m_orderingTool.empty()} ) );
55
56 // retrieve the geo identification decision tool
57 ATH_CHECK ( m_geoIDSvc.retrieve() );
58 // store a quick-access-pointer (removes GaudiOverhead)
59 m_geoIDSvcQuick = &(*m_geoIDSvc);
60
61 // setup CPU Benchmarks
63 if (!m_benchPDGCode) {
65 }
66 if (!m_benchGeoID) {
68 }
69 }
70
71 // setup for validation mode
72 if ( m_validationOutput) {
73 // retrieve the histogram service
74 ATH_CHECK ( m_thistSvc.retrieve() );
75 ATH_CHECK( registerPosValTree( "push_position",
76 "push() particle positions",
78 ATH_CHECK( registerPosValTree( "caloEntry_pos",
79 "CaloEntryLayer positions",
81 ATH_CHECK( registerPosValTree( "muonEntry_pos",
82 "MuonEntryLayer positions",
84 ATH_CHECK( registerPosValTree( "muonExit_pos",
85 "MuonExitLayer positions",
87 }
88
89 // initialization was successful
90 return StatusCode::SUCCESS;
91}
92
93
96{
97 // (1.) retrieve all SimulationSelector tools in the array
98 if ( simSelectorTools.retrieve().isFailure() ) {
99 ATH_MSG_FATAL( m_screenOutputPrefix << "Could not retrieve SimulatorSelector Tool Array. Abort.");
100 return StatusCode::FAILURE;
101 }
102
103 // reserve memory in STL vector
104 m_simSelector[geoID].reserve ( simSelectorTools.size());
105
106 // (2.) loop over SimulationSelector tool array and store
107 // its contents in m_simSelector[]
108 SimSelectorToolArray::iterator fSimSelIter = simSelectorTools.begin();
109 SimSelectorToolArray::iterator fSimSelIterEnd = simSelectorTools.end();
110 for ( ; fSimSelIter != fSimSelIterEnd; ++fSimSelIter ) {
111 ISimulationSelector *curSelector = &**fSimSelIter;
112 // initialize the SimulationSelector
113 curSelector->initializeSelector();
114 // register current SimulationSelector to the m_simSelector vector
115 m_simSelector[geoID].push_back( curSelector);
116 }
117
118 return StatusCode::SUCCESS;
119}
120
121
124 const char *treeDescr,
125 TTree *&tree ) {
126 // Create the prefix of histogram names for the THistSvc
127 std::string prefix = "/" + m_validationStream + "/";
128
129 tree = new TTree( treeName, treeDescr );
130 tree->Branch("x" , &m_val_x , "x/F");
131 tree->Branch("y" , &m_val_y , "y/F");
132 tree->Branch("z" , &m_val_z , "z/F");
133 tree->Branch("p" , &m_val_p , "p/F");
134 tree->Branch("pdg", &m_val_pdg, "pdg/I");
135
136 // register the Tree to the THistSvc and return it's StatusCode
137 return (m_thistSvc->regTree( prefix+treeName, tree) );
138}
139
140
143 const ISFParticle &p ) {
144 // the particle position
145 const Amg::Vector3D &pos = p.position();
146 // fill the member variables
147 m_val_x = pos.x();
148 m_val_y = pos.y();
149 m_val_z = pos.z();
150 m_val_p = p.momentum().mag();
151 m_val_pdg = p.pdgCode();
152 // fill the ROOT TTree
153 tree->Fill();
154
155 return;
156}
157
158
161 for ( const auto& simSelector : m_simSelectorSet ) {
162 simSelector->update(particle);
163 }
164}
165
166
170{
171 // consult the routing chain to find the simulator ID corresponding to this
172 // particle
173 SimSvcID selectedSimID = identifySimID( p);
174
175 // in case a simulator was determined for this particle
176 // -> register this simulator to the particle
177 // -> push particle onto container
178 if ( selectedSimID != ISF::fUndefinedSimID) {
179 ATH_MSG_VERBOSE( m_screenOutputPrefix << "Assigning " << *p
180 << " to simulator with ID=" << selectedSimID << ".");
181 // register the SimulatorID to the particle
182 p->setNextSimID( selectedSimID);
183
184 if ( m_orderingTool.isEnabled() ) { m_orderingTool->setOrder(*p); }
185
186 // store particle locally
187 m_particles.push(p);
188
189 // no simulator could be found
190 // -> drop particle
191 } else {
192 AtlasDetDescr::AtlasRegion geoID = p->nextGeoID();
193 // different error message for empty simulation Selector chain:
194 if ( !m_simSelector[geoID].size()) {
195 ATH_MSG_INFO( m_screenOutputPrefix << "No SimulationSelectors registered for GeoID="
196 << AtlasDetDescr::AtlasRegionHelper::getName(geoID) << ". Will not assign this particle to any simulator, dropping it.");
197 }
198 else {
199 ATH_MSG_INFO( m_screenOutputPrefix << "Current particle not selected by any SimulationSelector with GeoID="
200 << AtlasDetDescr::AtlasRegionHelper::getName(geoID) << ". Will not assign this particle to any simulator, dropping it.");
201 }
202 delete p;
203 }
204}
205
209 // implicit assumption that the geoID is set properly at this point (it is a private method)!
210 AtlasDetDescr::AtlasRegion geoID = p->nextGeoID();
211
212 // iterators used to loop over all simulation Selectors
213 SimSelectorArray::iterator selectorIt = m_simSelector[geoID].begin();
214 SimSelectorArray::iterator selectorItEnd = m_simSelector[geoID].end();
215
216 // will store whether the particle was selected by a simulation filter
217 bool selected = false;
218
219 // block defines scope for Benchmarks
220 // -> benchmarks will be stared/stopped automatically via the CustomBenchmarkGuard
221 // constructor and destructor, respectively
222 {
223 // prepare the pdgCode for the benchmark
224 unsigned int pdgCode = ISFBenchmarkHelper::getBenchReadyPdgCode( *p);
225
226 // setup sim svc benchmarks
228 PMonUtils::CustomBenchmarkGuard benchGeoID( m_benchGeoID , geoID );
229
230 // go through the chain of selectors and find the first
231 // selector which selects out the particle
232 for ( ; !selected && (selectorIt != selectorItEnd) ; ++selectorIt) {
233 // check if the current selector selects it
234 selected = (*selectorIt)->selfSelect( *p);
235 }
236
237 } // stop benchmarks
238
239 // determine the simulator ID
240 ISF::SimSvcID simID = selected ? (*--selectorIt)->simSvcID() : ISF::SimSvcID(ISF::fUndefinedSimID);
241
242 return simID;
243}
244
245
248{
249 ATH_MSG_DEBUG( m_screenOutputPrefix << "Initializing particle stack");
250
251 // fill set of simulation selectors once per job
252 // -> the std::set allows us to address each selector only once
253 // (the same selector might appear in multiple geoIDs)
254 if ( !m_simSelectorSet.size() ) {
255 for ( int curGeoID = AtlasDetDescr::fFirstAtlasRegion; curGeoID < AtlasDetDescr::fNumAtlasRegions; ++curGeoID) {
256 // fill the set with the selectors from the current geoID
257 m_simSelectorSet.insert( m_simSelector[curGeoID].begin(), m_simSelector[curGeoID].end() );
258 }
259
260 ATH_MSG_DEBUG("Number of unique SimulationSelctors registered: "
261 << m_simSelectorSet.size() );
262 }
263
264 // call beginEvent() for all selectors registerd to the ParticleBroker:
265 for ( const auto& simSelector : m_simSelectorSet ) {
266 simSelector->beginEvent();
267 }
268
269 m_entryLayerTool->setupEvent();
270 // update the routing chain selectors with the particles in the initial stack
271 for ( auto& particlePointer : simParticles ) {
272 auto& particle = *particlePointer;
273
274 // identify the geoID of the particle
275 m_geoIDSvcQuick->identifyAndRegNextGeoID(particle);
276 // the geoID at this point better makes sense :)
277 assert(validAtlasRegion( particle.nextGeoID() ));
278
279 // update all registered selectors (in all geoIDs) with this particle
280 updateAllSelectors(particle);
281
282 m_entryLayerTool->registerParticle(particle);
283 }
284
285 size_t order = simParticles.size(); // FIXME: ugly hack to keep bit-wise identical output with prior FullG4 implementation :(
286
287 for ( auto& particlePtr: simParticles ) {
288 // FIXME: ugly hack to keep bit-wise identical output with prior FullG4 implementation :(
289 if (!m_orderingTool.isEnabled() ) { particlePtr->setOrder(order--); }
290
291 selectAndStore(particlePtr);
292 }
293
294 return StatusCode::SUCCESS;
295}
296
297
300
301 // go throught all SimSelectors and call the endEvent() on them
302 SimSelectorSet::iterator fSimSelIter = m_simSelectorSet.begin();
303 SimSelectorSet::iterator fSimSelIterEnd = m_simSelectorSet.end();
304 for ( ; fSimSelIter != fSimSelIterEnd; ++fSimSelIter )
305 (*fSimSelIter)->endEvent();
306
307 return StatusCode::SUCCESS;
308}
309
310
313 // this call does not make much sense with no given particle
314 assert(particlePtr);
315
316 ISFParticle &particle = *particlePtr;
317
318 if (parentPtr) {
319 //Let's make sure that the new ISFParticle has a valid TruthBinding and HepMcParticleLink
320 //(could happen that the new particles are not saved by the TruthSvc for instance)
321 //or attach pointers to the parent otherwise
322 if (!particlePtr->getTruthBinding()) {
323 ATH_MSG_WARNING("The provided new ISFParticle had no TruthBinding ! Copying over the one from the parent ISFParticle.");
324 particle.setTruthBinding(new TruthBinding(*parentPtr->getTruthBinding()));
325 }
326 }
327
328 // get the particle's next geoID
329 AtlasDetDescr::AtlasRegion geoID = particle.nextGeoID();
330
331 // if GeoID not set (e.g. ISF::fUndefinedGeoID) or a flag is set to always use the GeoIDSvc
332 // -> let the geoIDSvc find the next geoID
333 if ( m_forceGeoIDSvc || !validAtlasRegion(geoID) ) {
334 geoID = m_geoIDSvcQuick->identifyAndRegNextGeoID(particle);
335 }
336 // inform the entry layer tool about this particle
337 ISF::EntryLayer layer = m_entryLayerTool->registerParticle( particle );
338
339 // ---> if validation mode: fill the corresponding entry layer ROOT tree
340 if ( m_validationOutput ) {
341 // fill the push() position TTree
343 // in case particle was added to an entry layer, add it to the corresponding TTree
344 if ( validEntryLayer(layer) ) {
345 fillPosValTree( m_t_entryLayerPos[layer], particle);
346 }
347 }
348 // <--- end validation output
349
350 // validation mode: check whether the particle position corresponds to the GeoID given
351 // by the particle itself
352 if ( m_validateGeoID) {
353 AtlasDetDescr::AtlasRegion identifiedGeoID = m_geoIDSvcQuick->identifyNextGeoID(particle);
354 if ( (geoID!=AtlasDetDescr::fUndefinedAtlasRegion) && (geoID!=identifiedGeoID) ) {
355 ATH_MSG_WARNING("Validating GeoID: GeoIDSvc resolves a particle's position to a different GeoID than stored in the particle:");
356 ATH_MSG_WARNING(" assigned=" << geoID << " GeoIDSvc=" << identifiedGeoID);
357 ATH_MSG_WARNING(" Particle: " << particle);
358 }
359 }
360
361 // only process particles with well defined geoID
362 if ( !validAtlasRegion( geoID) ) {
363 ATH_MSG_ERROR( m_screenOutputPrefix << "Trying to push particle onto the stack with unknown geoID=" << geoID
364 << ". Dropping this particle.");
365 delete particlePtr;
366 return;
367 }
368
369 // (*) let the Selectors select the particle
370 // - if a Selector selects a particle -> it is pushed onto the active stack
371 // - if it is not selected -> particle is dropped (deleted)
372 selectAndStore( particlePtr );
373}
374
377{
378 // delete particles from previous return vector and empty the vector
379 ISF::ISFParticleVector::const_iterator partIt = m_popParticles.begin();
380 ISF::ISFParticleVector::const_iterator partEnd = m_popParticles.end();
381 for ( ; partIt != partEnd; ++partIt) {
382 ISF::ISFParticle *curPart = (*partIt);
383 delete curPart;
384 }
385 m_popParticles.clear();
386
387 // if there are particles in the queue
388 if ( m_particles.size() ) {
389
390 SimSvcID returnID = m_particles.top()->nextSimID();
391 ISFParticleOrderedQueue tempQueue;
392 // loop as long as we have particles in the m_particles queue
393 do {
394 // get the next particle from the ordered queue
395 ISFParticle *curParticle = m_particles.top();
396 SimSvcID curID = curParticle->nextSimID();
397
398 // if this particle has a different SimID, or the maximum size of the return vector is reached
399 // -> don't add any more particles to the m_popParticles std::vector
400 if ( curID != returnID || m_popParticles.size() >= maxVectorSize ) {
401 tempQueue.push(m_particles.top()); //break;
402 }
403 else {
404 // add this particle to the, later returned, m_popParticles std::vector
405 m_popParticles.push_back( curParticle );
406 }
407 // remove this particle from the ordered queue
408 m_particles.pop();
409 } while ( m_particles.size() ) ;
410 m_particles = std::move(tempQueue);
411 }
412 // return the popParticles vector
413 return m_popParticles;
414}
415
416
417/* Dump the stack to the screen */
419{
420 ATH_MSG_INFO( m_screenOutputPrefix << "==== ISF Particle Stack Dump ====");
421 ATH_MSG_INFO( m_screenOutputPrefix << " 'active' particles -> ready to be simulated");
422 ATH_MSG_INFO( m_screenOutputPrefix << " 'onHold' particles -> no sim Selector decision yet, waiting in routing chain");
424 ATH_MSG_INFO( m_screenOutputPrefix << " Number of 'active' particles: " << m_particles.size());
425 for ( int geoID = AtlasDetDescr::fFirstAtlasRegion; geoID < AtlasDetDescr::fNumAtlasRegions; ++geoID) {
426 ATH_MSG_INFO( m_screenOutputPrefix << " --- SimGeoID=" << geoID
427 << " (" << AtlasDetDescr::AtlasRegionHelper::getName(geoID) << ") ---");
428 ATH_MSG_INFO( m_screenOutputPrefix << " Routing Chain has length "
429 << m_simSelector[geoID].size() );
430 }
431 ATH_MSG_INFO( m_screenOutputPrefix << "=================================");
432
433 return StatusCode::SUCCESS;
434}
#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
#define validEntryLayer(layer)
Definition EntryLayer.h:15
static const char * getName(int region)
static unsigned int getBenchReadyPdgCode(const ISFParticle &p)
get PMonUtils::CustomBenchmarkGuard ready PDGCode of the given ISFParticle -> returns abs(pdgCode) if...
The generic ISF particle definition,.
Definition ISFParticle.h:42
const TruthBinding * getTruthBinding() const
pointer to the simulation truth - optional, can be 0
SimSvcID nextSimID() const
the next simulation service the particle will be sent to
virtual void initializeSelector()=0
initialize Selector
StatusCode dump() const
Return the particle stack (not implemented)
virtual StatusCode finalizeEvent()
Finalize the event in the broker service.
void selectAndStore(ISFParticle *p)
go through the chain of SimulationSelectors and let the first one which selects the particle decide w...
StatusCode registerPosValTree(const char *treeName, const char *treeDescr, TTree *&tree)
setup the ROOT TTrees for THistSvc in validation mode
SimSelectorArray m_simSelector[AtlasDetDescr::fNumAtlasRegions]
the simulation selectors per geoID (the actual routing chain)
int m_val_pdg
memory containing the entries for the ROOT tree
PublicToolHandle< IEntryLayerTool > m_entryLayerTool
AthenaTool responsible for writing Calo/Muon Entry/Exit Layer collection.
void updateAllSelectors(const ISFParticle &particle)
update all unfrozen simSelectors with the given particle
BooleanProperty m_validationOutput
validation mode: create ROOT Tree with additional information
ISF::SimSvcID identifySimID(const ISF::ISFParticle *p)
go through the chain of SimulationSelectors and return the SimulatoID of the first SimulationSelector...
std::string m_screenOutputPrefix
Screen output refinement.
SimSelectorSet m_simSelectorSet
used to remove multiple uses of the same selector
ISFParticleVector m_popParticles
the vector of particles returned for simulation (via popVector() )
TTree * m_t_entryLayerPos[ISF::fNumAtlasEntryLayers]
TTree * m_t_pushPosition
the actual validation histograms and ROOT trees
virtual void push(ISFParticle *particle, const ISFParticle *ancestor)
add a new particle to the stack and inherit ISF properties from the given ancestor ISF particel (usua...
StatusCode initializeEvent(ISFParticleContainer &&simParticles)
Initialize the particle broker.
ParticleBrokerDynamicOnReadIn()
Default constructor.
virtual const ISFParticleVector & popVector(size_t maxVectorSize)
Get vectors of ISF particles from the broker.
BooleanProperty m_forceGeoIDSvc
always use GeoIDSvc to determine GeoID of given particles
ServiceHandle< ITHistSvc > m_thistSvc
the histogram service
BooleanProperty m_validateGeoID
always use GeoIDSvc to check correctness of GeoIDs already assigned to particles
StatusCode registerSimSelector(SimSelectorToolArray &simSelectorTools, AtlasDetDescr::AtlasRegion geoID)
Register an array of SimulationSelectors.
StatusCode initialize()
Athena algorithm's interface methods.
PublicToolHandle< IParticleOrderingTool > m_orderingTool
AthenaTool responsible for proritizing the particles and determine their simulation order.
ServiceHandle< IGeoIDSvc > m_geoIDSvc
the geo identifier service used to route the particle into the right SimulationSelector chain
void fillPosValTree(TTree *tree, const ISFParticle &particle)
fill the TTree with the (x,y,z) coordinates of the given ISFParticle
ISFParticleOrderedQueue m_particles
the particle container storing all particles which need to be simulated
IGeoIDSvc * m_geoIDSvcQuick
minimize Gaudi overhead
StringProperty m_validationStream
validation THist stream name
Eigen::Matrix< double, 3, 1 > Vector3D
AtlasRegion
A simple enum of ATLAS regions and sub-detectors.
Definition AtlasRegion.h:21
@ fMaxBenchmarkPDGCode
@ fUndefinedSimID
Definition SimSvcID.h:32
ToolHandleArray< ISimulationSelector > SimSelectorToolArray
typedef for better readable code
std::priority_queue< ISF::ISFParticle *, ISF::ISFParticleVector, ISF::ISFParticleOrdering > ISFParticleOrderedQueue
the actual particle priority_queue
EntryLayer
Identifiers for the TrackRecordCollections on the boundaries between CaloEntry: Inner Detector - Calo...
Definition EntryLayer.h:31
@ fAtlasMuonExit
Definition EntryLayer.h:39
@ fAtlasCaloEntry
Definition EntryLayer.h:37
@ fAtlasMuonEntry
Definition EntryLayer.h:38
uint8_t SimSvcID
Simulation service ID datatype.
Definition SimSvcID.h:28
std::list< ISF::ISFParticle * > ISFParticleContainer
generic ISFParticle container (not necessarily a std::list!)
std::vector< ISF::ISFParticle * > ISFParticleVector
ISFParticle vector.
TChain * tree