Logo ROOT  
Reference Guide
TMCManager.cxx
Go to the documentation of this file.
1// @(#)root/vmc:$Id$
2// Authors: Benedikt Volkel 07/03/2019
3
4/*************************************************************************
5 * Copyright (C) 2019, Rene Brun and Fons Rademakers. *
6 * Copyright (C) 2019, ALICE Experiment at CERN. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#include "TError.h"
14#include "TVector3.h"
15#include "TLorentzVector.h"
16#include "TParticle.h"
17#include "TGeoBranchArray.h"
18#include "TGeoNavigator.h"
19
21#include "TVirtualMCStack.h"
22#include "TMCManagerStack.h"
23#include "TMCParticleStatus.h"
24
25#include "TMCManager.h"
26
27/** \class TMCManager
28 \ingroup vmc
29
30Singleton manager class for handling and steering a run with multiple TVirtualMC
31engines sharing events.
32It provides interfaces to transfer tracks between engines and exposes the correct
33stacks to each running engine. A registered user stack is kept up-to-date
34automatically seeing a consistent history.
35Track objects (aka TParticle) are still owned by the user who must forward these to
36the manager after creation. Everything else is done automatically.
37*/
38
40
41////////////////////////////////////////////////////////////////////////////////
42///
43/// Default and standard constructor
44///
45
47 : fApplication(nullptr), fCurrentEngine(nullptr), fTotalNPrimaries(0), fTotalNTracks(0), fUserStack(nullptr),
48 fBranchArrayContainer(), fIsInitialized(kFALSE), fIsInitializedUser(kFALSE)
49{
50 if (fgInstance) {
51 ::Fatal("TMCManager::TMCManager", "Attempt to create two instances of singleton.");
52 }
53 fgInstance = this;
54}
55
56////////////////////////////////////////////////////////////////////////////////
57///
58/// Destructor
59///
60
62{
63 for (auto &mc : fEngines) {
64 delete mc;
65 }
66 fgInstance = nullptr;
67}
68
69////////////////////////////////////////////////////////////////////////////////
70///
71/// Static access method
72///
73
75{
76 return fgInstance;
77}
78
79////////////////////////////////////////////////////////////////////////////////
80///
81/// A TVirtualMC will register itself via this method during construction
82/// if a TMCManager was instanciated before.
83/// The TMCManager will assign an ID to the engines.
84///
85
87{
88 // Do not register an engine twice.
89 for (auto &currMC : fEngines) {
90 if (currMC == mc) {
91 ::Fatal("TMCManager::RegisterMC", "This engine is already registered.");
92 }
93 }
94 // Set id and register.
95 mc->SetId(fEngines.size());
96 fEngines.push_back(mc);
97 fStacks.emplace_back(new TMCManagerStack());
98 mc->SetStack(fStacks.back().get());
99 mc->SetManagerStack(fStacks.back().get());
100 // Must update engine pointers here since during construction of the concrete TVirtualMC
101 // implementation the static TVirtualMC::GetMC() or defined gMC might be used.
103}
104
105////////////////////////////////////////////////////////////////////////////////
106///
107/// The user application will register itself via this method when the
108/// manager was requested.
109///
110
112{
113 if (fApplication) {
114 ::Fatal("TMCManager::Register", "The application is already registered.");
115 }
116 ::Info("TMCManager::Register", "Register user application and construct geometry");
117 fApplication = application;
118 // TODO Can these 3 functions can be called directly here? Or could any of these depend on an implemented VMC?
122 if (!gGeoManager->IsClosed()) {
123 // Setting the top volume is the duty of the user as well as closing it.
124 // Failing here is just an additional cross check. If not closed the user
125 // might have forgotten something.
126 ::Fatal("TMCManager::Register", "The TGeo geometry is not closed. Please check whether you just have to close "
127 "it or whether something was forgotten.");
128 }
129}
130
131////////////////////////////////////////////////////////////////////////////////
132///
133/// Return the number of registered engines.
134///
135
137{
138 return fEngines.size();
139}
140
141////////////////////////////////////////////////////////////////////////////////
142///
143/// Get registered engine pointers
144///
145
146void TMCManager::GetEngines(std::vector<TVirtualMC *> &engines) const
147{
148 engines.clear();
149 engines.resize(fEngines.size(), nullptr);
150 for (UInt_t i = 0; i < fEngines.size(); i++) {
151 engines[i] = fEngines[i];
152 }
153}
154
155////////////////////////////////////////////////////////////////////////////////
156///
157/// Return the number of registered engines.
158///
159
161{
162 if (id < 0 || id >= static_cast<Int_t>(fEngines.size())) {
163 ::Fatal("TMCManager::GetEngine", "Unknown engine ID.");
164 }
165 return fEngines[id];
166}
167
168////////////////////////////////////////////////////////////////////////////////
169///
170/// Get engine ID by its name
171///
172
173Int_t TMCManager::GetEngineId(const char *engineName) const
174{
175 for (UInt_t i = 0; i < fEngines.size(); i++) {
176 if (strcmp(engineName, fEngines[i]->GetName()) == 0) {
177 return i;
178 }
179 }
180 ::Warning("TMCManager::GetEngineId", "Unknown engine %s.", engineName);
181 return -1;
182}
183
184////////////////////////////////////////////////////////////////////////////////
185///
186/// Get the current engine pointer
187///
188
190{
191 return fCurrentEngine;
192}
193
194////////////////////////////////////////////////////////////////////////////////
195///
196/// Connect a pointer which is updated whenever the engine is changed
197///
198
200{
201 fConnectedEnginePointers.push_back(mc);
202 if (fCurrentEngine) {
203 *mc = fCurrentEngine;
204 }
205}
206
207////////////////////////////////////////////////////////////////////////////////
208///
209/// Connect a pointer which is updated whenever the engine is changed
210///
211
213{
215}
216
217////////////////////////////////////////////////////////////////////////////////
218///
219/// Set user stack
220///
221
223{
224 fUserStack = stack;
225}
226
227////////////////////////////////////////////////////////////////////////////////
228///
229/// User interface to forward particle to specifiic engine.
230/// It is assumed that the TParticle is owned by the user. It will not be
231/// modified by the TMCManager.
232///
233
234void TMCManager::ForwardTrack(Int_t toBeDone, Int_t trackId, Int_t parentId, TParticle *particle, Int_t engineId)
235{
236 if (engineId < 0 || engineId >= static_cast<Int_t>(fEngines.size())) {
237 ::Fatal("TMCManager::ForwardTrack", "Engine ID %i out of bounds. Have %zu engines.", engineId, fEngines.size());
238 }
239 if (trackId >= static_cast<Int_t>(fParticles.size())) {
240 fParticles.resize(trackId + 1, nullptr);
241 fParticlesStatus.resize(trackId + 1);
242 }
243 fParticles[trackId] = particle;
244 fParticlesStatus[trackId].reset(new TMCParticleStatus());
245 fParticlesStatus[trackId]->fId = trackId;
246 fParticlesStatus[trackId]->fParentId = parentId;
247 fParticlesStatus[trackId]->InitFromParticle(particle);
249 if (particle->IsPrimary()) {
251 }
252
253 if (toBeDone > 0) {
254 if (particle->IsPrimary()) {
255 fStacks[engineId]->PushPrimaryTrackId(trackId);
256 } else {
257 fStacks[engineId]->PushSecondaryTrackId(trackId);
258 }
259 }
260}
261
262////////////////////////////////////////////////////////////////////////////////
263///
264/// User interface to forward particle to specifiic engine.
265/// It is assumed that the TParticle is owned by the user. It will not be
266/// modified by the TMCManager.
267/// Assume current engine Id
268///
269
270void TMCManager::ForwardTrack(Int_t toBeDone, Int_t trackId, Int_t parentId, TParticle *particle)
271{
272 ForwardTrack(toBeDone, trackId, parentId, particle, fCurrentEngine->GetId());
273}
274
275////////////////////////////////////////////////////////////////////////////////
276///
277/// Transfer track from current engine to engine with engineTargetId
278///
279
281{
282 if (engineTargetId < 0 || engineTargetId >= static_cast<Int_t>(fEngines.size())) {
283 ::Fatal("TMCManager::TransferTrack",
284 "Target engine ID out of bounds. Have %zu engines. Requested target ID was %i", fEngines.size(),
285 engineTargetId);
286 }
287 TransferTrack(fEngines[engineTargetId]);
288}
289
290////////////////////////////////////////////////////////////////////////////////
291///
292/// Transfer track from current engine to target engine mc
293///
294
296{
297 // Do nothing if target and current engines are the same
298 if (mc == fCurrentEngine) {
299 return;
300 }
301
302 // Get information on current track and extract status from transporting engine
303 Int_t trackId = fStacks[fCurrentEngine->GetId()]->GetCurrentTrackNumber();
304
305 fCurrentEngine->TrackPosition(fParticlesStatus[trackId]->fPosition);
306 fCurrentEngine->TrackMomentum(fParticlesStatus[trackId]->fMomentum);
307 fCurrentEngine->TrackPolarization(fParticlesStatus[trackId]->fPolarization);
308 fParticlesStatus[trackId]->fStepNumber = fCurrentEngine->StepNumber();
309 fParticlesStatus[trackId]->fTrackLength = fCurrentEngine->TrackLength();
310 fParticlesStatus[trackId]->fWeight = fCurrentEngine->TrackWeight();
311
312 // Store TGeoNavidator's fIsOutside state
313 fParticlesStatus[trackId]->fIsOutside = gGeoManager->IsOutside();
314
315 TGeoBranchArray *geoState = fBranchArrayContainer.GetNewGeoState(fParticlesStatus[trackId]->fGeoStateIndex);
317
318 // Push only the particle ID
319 if (fParticles[trackId]->IsPrimary()) {
320 fStacks[mc->GetId()]->PushPrimaryTrackId(trackId);
321 } else {
322 fStacks[mc->GetId()]->PushSecondaryTrackId(trackId);
323 }
325}
326
327////////////////////////////////////////////////////////////////////////////////
328///
329/// Try to restore geometry for a given track
330///
331
333{
334 if (checkTrackIdRange && (trackId < 0 || trackId >= static_cast<Int_t>(fParticles.size()) || !fParticles[trackId])) {
335 return kFALSE;
336 }
337 UInt_t& geoStateId = fParticlesStatus[trackId]->fGeoStateIndex;
338 if(geoStateId == 0) {
339 return kFALSE;
340 }
341 const TGeoBranchArray* branchArray = fBranchArrayContainer.GetGeoState(geoStateId);
344 gGeoManager->SetOutside(fParticlesStatus[trackId]->fIsOutside);
345 geoStateId = 0;
346 return kTRUE;
347}
348
349////////////////////////////////////////////////////////////////////////////////
350///
351/// Try to restore geometry for the track currently set
352///
353
355{
356 return RestoreGeometryState(fStacks[fCurrentEngine->GetId()]->GetCurrentTrackNumber(), kFALSE);
357}
358
359////////////////////////////////////////////////////////////////////////////////
360///
361/// Initialize engines
362///
363
365{
366 if (fIsInitialized) {
367 return;
368 }
369
370 if (!fUserStack) {
371 ::Fatal("TMCManager::Run", "Missing user stack pointer.");
372 }
373 if (fEngines.empty()) {
374 ::Fatal("TMCManager::Run", "No engines registered");
375 }
376
377 for (auto &mc : fEngines) {
378 // Must have geometry handling via TGeo
379 if (!mc->IsRootGeometrySupported()) {
380 ::Fatal("TMCManager::Run", "Engine %s does not support geometry built via ROOT's TGeoManager", mc->GetName());
381 }
382 Int_t currentEngineId = mc->GetId();
383 // To be able to forward info to the user stack
384 fStacks[currentEngineId]->SetUserStack(fUserStack);
385 // Connect the engine's stack to the centrally managed vectors
386 fStacks[currentEngineId]->ConnectTrackContainers(&fParticles, &fParticlesStatus, &fBranchArrayContainer,
388 }
389
390 // Initialize the fBranchArrayContainer to manage and cache TGeoBranchArrays
392
394
395 // Send warning if only one engine ==> overhead
396 if (fEngines.size() == 1) {
397 ::Warning("TMCManager::Run", "Only one engine registered. That will lead to overhead in "
398 "the simulation run due to additional hooks and dispatches "
399 "to the TMCManager.");
400 }
401}
402
403////////////////////////////////////////////////////////////////////////////////
404///
405/// Run the event loop
406///
407
409{
410 if (!fIsInitialized) {
411 ::Fatal("TMCManager::Run", "Engines have not yet been initialized.");
412 }
413
414 // Set user initialize true in any case now so that this cannot happen by accident during a run
416
417 if (nEvents < 1) {
418 ::Fatal("TMCManager::Run", "Need at least one event to process but %i events specified.", nEvents);
419 }
420
421 // Run 1 event nEvents times
422 for (Int_t i = 0; i < nEvents; i++) {
423 ::Info("TMCManager::Run", "Start event %i", i + 1);
426 // Loop as long as there are tracks in any engine stack
427 while (GetNextEngine()) {
429 }
431 }
432 TerminateRun();
433}
434
435////////////////////////////////////////////////////////////////////////////////
436///
437/// Choose next engines to be run in the loop
438///
439
441{
443 // Reset in event flag for all engines and clear stacks
444 for (auto &stack : fStacks) {
445 stack->ResetInternals();
446 }
447 for (UInt_t i = 0; i < fParticles.size(); i++) {
448 fParticlesStatus.clear();
449 fParticlesStatus.resize(fParticles.size());
450 fParticles[i] = nullptr;
451 }
452
453 // GeneratePrimaries centrally
455}
456
457////////////////////////////////////////////////////////////////////////////////
458///
459/// Choose next engines to be run in the loop
460///
461
463{
464 // Select next engine based on finite number of particles on the stack
465 for (UInt_t i = 0; i < fStacks.size(); i++) {
466 if (fStacks[i]->GetStackedNtrack() > 0) {
468 return kTRUE;
469 }
470 }
471 // No tracks to be processed.
472 return kFALSE;
473}
474
475////////////////////////////////////////////////////////////////////////////////
476///
477/// Update all engine pointers connected to the TMCManager
478///
479
481{
482 fCurrentEngine = mc;
483 for (TVirtualMC **&mcPtr : fConnectedEnginePointers) {
484 *mcPtr = mc;
485 }
486 // Make sure TVirtualMC::GetMC() returns the current engine.
487 TVirtualMC::fgMC = mc;
488}
489
490////////////////////////////////////////////////////////////////////////////////
491///
492/// Terminate the run for all engines
493///
494
496{
497 for (auto &mc : fEngines) {
498 mc->TerminateRun();
499 }
500}
const Bool_t kFALSE
Definition: RtypesCore.h:90
const Bool_t kTRUE
Definition: RtypesCore.h:89
void Info(const char *location, const char *msgfmt,...)
void Warning(const char *location, const char *msgfmt,...)
void Fatal(const char *location, const char *msgfmt,...)
XFontStruct * id
Definition: TGX11.cxx:108
R__EXTERN TGeoManager * gGeoManager
Definition: TGeoManager.h:600
#define TMCThreadLocal
Definition: TMCtls.h:80
An array of daughter indices making a geometry path.
void UpdateNavigator(TGeoNavigator *nav) const
Update the navigator to reflect the branch.
void InitFromNavigator(TGeoNavigator *nav)
Init the branch array from current navigator state.
TGeoBranchArray * GetNewGeoState(UInt_t &userIndex)
Get a TGeoBranchArray to set to current geo state.
const TGeoBranchArray * GetGeoState(UInt_t userIndex)
Get a TGeoBranchArray to read the current state from.
void InitializeFromGeoManager(TGeoManager *man, UInt_t size=8)
Initialize from TGeoManager to extract maxlevels.
void FreeGeoStates()
Free all geo states at once but keep the container size.
void FreeGeoState(UInt_t userIndex)
Free the index of this geo state such that it can be re-used.
TGeoNavigator * GetCurrentNavigator() const
Returns current navigator for the calling thread.
Bool_t IsClosed() const
Definition: TGeoManager.h:303
void SetOutside(Bool_t flag=kTRUE)
Definition: TGeoManager.h:430
Bool_t IsOutside() const
Definition: TGeoManager.h:426
Concrete implementation of particles stack used by the TMCManager.
Singleton manager class for handling and steering a run with multiple TVirtualMC engines sharing even...
Definition: TMCManager.h:36
Int_t GetEngineId(const char *name) const
Get engine ID by its name.
Definition: TMCManager.cxx:173
Bool_t RestoreGeometryState()
Try to restore geometry for the track currently set.
Definition: TMCManager.cxx:354
TVirtualMC * GetCurrentEngine() const
Get the current engine pointer.
Definition: TMCManager.cxx:189
void TerminateRun()
Terminate a run in all engines.
Definition: TMCManager.cxx:495
virtual ~TMCManager()
Destructor.
Definition: TMCManager.cxx:61
void ForwardTrack(Int_t toBeDone, Int_t trackId, Int_t parentId, TParticle *particle, Int_t engineId)
User interface to forward particle to specifiic engine.
Definition: TMCManager.cxx:234
std::vector< TParticle * > fParticles
All tracks (persistent)
Definition: TMCManager.h:178
std::vector< TVirtualMC ** > fConnectedEnginePointers
Connected engine pointers which will be updated everytime the current engine changes.
Definition: TMCManager.h:187
Int_t fTotalNPrimaries
Total number of primaries ever pushed.
Definition: TMCManager.h:182
void ConnectEnginePointer(TVirtualMC **mc)
Connect a pointer which is updated whenever the engine is changed.
Definition: TMCManager.cxx:199
void TransferTrack(Int_t engineTargetId)
Transfer track from current engine to engine with engineTargetId.
Definition: TMCManager.cxx:280
Bool_t GetNextEngine()
Find the next engine.
Definition: TMCManager.cxx:462
TVirtualMC * fCurrentEngine
Pointer to current engine.
Definition: TMCManager.h:172
TVirtualMC * GetEngine(Int_t id) const
Get an engine pointer by ID.
Definition: TMCManager.cxx:160
void UpdateEnginePointers(TVirtualMC *mc)
Update all engine pointers connected to the TMCManager.
Definition: TMCManager.cxx:480
void Init()
Initialize engines.
Definition: TMCManager.cxx:364
Bool_t fIsInitializedUser
Flag if specific initialization for engines was done.
Definition: TMCManager.h:195
TVirtualMCApplication * fApplication
Pointer to user application.
Definition: TMCManager.h:170
void PrepareNewEvent()
Do necessary steps before an event is triggered.
Definition: TMCManager.cxx:440
std::vector< std::unique_ptr< TMCManagerStack > > fStacks
Stacks connected to engines.
Definition: TMCManager.h:176
TVirtualMCStack * fUserStack
Pointer to user stack.
Definition: TMCManager.h:189
static TMCThreadLocal TMCManager * fgInstance
Singleton instance.
Definition: TMCManager.h:164
static TMCManager * Instance()
Static access method.
Definition: TMCManager.cxx:74
Int_t fTotalNTracks
Total number of tracks ever pushed.
Definition: TMCManager.h:184
TMCManager()
Default constructor.
Definition: TMCManager.cxx:46
std::vector< std::unique_ptr< TMCParticleStatus > > fParticlesStatus
All particles' status (persistent)
Definition: TMCManager.h:180
void Run(Int_t nEvents)
Run the event loop.
Definition: TMCManager.cxx:408
std::vector< TVirtualMC * > fEngines
Collecting pointers to all instanciated TVirtualMCs.
Definition: TMCManager.h:174
Bool_t fIsInitialized
Flag if engines are initilaized.
Definition: TMCManager.h:193
void SetUserStack(TVirtualMCStack *stack)
Set user stack.
Definition: TMCManager.cxx:222
Int_t NEngines() const
Return the number of registered engines.
Definition: TMCManager.cxx:136
TGeoMCBranchArrayContainer fBranchArrayContainer
Pointer to cache with geometry states.
Definition: TMCManager.h:191
void Register(TVirtualMC *engine)
A TVirtualMC will register itself via this method during construction if a TMCManager was instanciate...
Definition: TMCManager.cxx:86
void GetEngines(std::vector< TVirtualMC * > &engines) const
Get registered engine pointers.
Definition: TMCManager.cxx:146
Description of the dynamic properties of a particle.
Definition: TParticle.h:26
Bool_t IsPrimary() const
Definition: TParticle.h:87
Interface to a user Monte Carlo application.
virtual void GeneratePrimaries()=0
Generate primary particles.
virtual void ConstructGeometry()=0
Construct user geometry.
virtual Bool_t MisalignGeometry()
Misalign user geometry (optional)
virtual void ConstructOpGeometry()
Define parameters for optical processes (optional)
virtual void BeginEvent()=0
Define actions at the beginning of the event.
virtual void FinishEvent()=0
Define actions at the end of the event.
Interface to a user defined particles stack.
Abstract Monte Carlo interface.
Definition: TVirtualMC.h:42
virtual Double_t TrackLength() const =0
Return the length of the current track from its origin (in cm)
virtual void TrackPolarization(Double_t &polX, Double_t &polY, Double_t &polZ) const
Get the current polarization.
Definition: TVirtualMC.cxx:176
virtual Int_t StepNumber() const
Return the current step number.
Definition: TVirtualMC.cxx:154
virtual void InterruptTrack()
That triggers stopping the transport of the current track without dispatching to common routines like...
Definition: TVirtualMC.cxx:237
void SetId(UInt_t id)
Set the VMC id.
Definition: TVirtualMC.cxx:202
virtual void ProcessEvent(Int_t eventId)
Process one event.
Definition: TVirtualMC.cxx:144
virtual void TrackPosition(TLorentzVector &position) const =0
Return the current position in the master reference frame of the track being transported.
virtual void SetStack(TVirtualMCStack *stack)
Set the particle stack.
Definition: TVirtualMC.cxx:93
void SetManagerStack(TMCManagerStack *stack)
Set container holding additional information for transported TParticles.
Definition: TVirtualMC.cxx:211
virtual Double_t TrackWeight() const
Get the current weight.
Definition: TVirtualMC.cxx:165
static TMCThreadLocal TVirtualMC * fgMC
Static TVirtualMC pointer.
Definition: TVirtualMC.h:897
virtual void TrackMomentum(TLorentzVector &momentum) const =0
Return the direction and the momentum (GeV/c) of the track currently being transported.
Int_t GetId() const
Return the VMC's ID.
Definition: TVirtualMC.h:868