VMC Version 2.0
Loading...
Searching...
No Matches
TMCManager.cxx
Go to the documentation of this file.
1// -----------------------------------------------------------------------
2// Copyright (C) 2019 CERN and copyright holders of VMC Project.
3// This software is distributed under the terms of the GNU General Public
4// License v3 (GPL Version 3), copied verbatim in the file "LICENSE".
5//
6// See https://github.com/vmc-project/vmc for full licensing information.
7// -----------------------------------------------------------------------
8
9// Authors: Benedikt Volkel 07/03/2019
10
11/*************************************************************************
12 * Copyright (C) 2019, Rene Brun and Fons Rademakers. *
13 * Copyright (C) 2019, ALICE Experiment at CERN. *
14 * All rights reserved. *
15 * *
16 * For the licensing terms see $ROOTSYS/LICENSE. *
17 * For the list of contributors see $ROOTSYS/README/CREDITS. *
18 *************************************************************************/
19
20#include "TError.h"
21#include "TVector3.h"
22#include "TLorentzVector.h"
23#include "TParticle.h"
24#include "TGeoBranchArray.h"
25#include "TGeoNavigator.h"
26
28#include "TVirtualMCStack.h"
29#include "TMCManagerStack.h"
30#include "TMCParticleStatus.h"
31
32#include "TMCManager.h"
33
46TMCThreadLocal TMCManager *TMCManager::fgInstance = nullptr;
47
52
54 : fApplication(nullptr), fCurrentEngine(nullptr), fTotalNPrimaries(0), fTotalNTracks(0), fUserStack(nullptr),
55 fBranchArrayContainer(), fIsInitialized(kFALSE), fIsInitializedUser(kFALSE), fGeometryConstructed(kFALSE)
56{
57 if (fgInstance) {
58 ::Fatal("TMCManager::TMCManager", "Attempt to create two instances of singleton.");
59 }
60 fgInstance = this;
61}
62
67
69{
70 for (auto &mc : fEngines) {
71 delete mc;
72 }
73 fgInstance = nullptr;
74}
75
80
82{
83 return fgInstance;
84}
85
92
94{
95 // Do not register an engine twice.
96 for (auto &currMC : fEngines) {
97 if (currMC == mc) {
98 ::Fatal("TMCManager::RegisterMC", "This engine is already registered.");
99 }
100 }
105 if (!gGeoManager->IsClosed()) {
106 // Setting the top volume is the duty of the user as well as closing it.
107 // Failing here is just an additional cross check. If not closed the user
108 // might have forgotten something.
109 ::Fatal("TMCManager::Register", "The TGeo geometry is not closed. Please check whether you just have to close "
110 "it or whether something was forgotten.");
111 }
112 fGeometryConstructed = kTRUE;
113 }
114 // Set id and register.
115 mc->SetId(fEngines.size());
116 fEngines.push_back(mc);
117 fStacks.emplace_back(new TMCManagerStack());
118 mc->SetStack(fStacks.back().get());
119 mc->SetManagerStack(fStacks.back().get());
120 // Must update engine pointers here since during construction of the concrete TVirtualMC
121 // implementation the static TVirtualMC::GetMC() or defined gMC might be used.
123}
124
130
132{
133 if (fApplication) {
134 ::Fatal("TMCManager::Register", "The application is already registered.");
135 }
136 ::Info("TMCManager::Register", "Register user application and construct geometry");
137 fApplication = application;
138 // TODO Can these 3 functions can be called directly here? Or could any of these depend on an implemented VMC?
139}
140
145
147{
148 return fEngines.size();
149}
150
155
156void TMCManager::GetEngines(std::vector<TVirtualMC *> &engines) const
157{
158 engines.clear();
159 engines.resize(fEngines.size(), nullptr);
160 for (UInt_t i = 0; i < fEngines.size(); i++) {
161 engines[i] = fEngines[i];
162 }
163}
164
169
171{
172 if (id < 0 || id >= static_cast<Int_t>(fEngines.size())) {
173 ::Fatal("TMCManager::GetEngine", "Unknown engine ID.");
174 }
175 return fEngines[id];
176}
177
182
183Int_t TMCManager::GetEngineId(const char *engineName) const
184{
185 for (UInt_t i = 0; i < fEngines.size(); i++) {
186 if (strcmp(engineName, fEngines[i]->GetName()) == 0) {
187 return i;
188 }
189 }
190 ::Warning("TMCManager::GetEngineId", "Unknown engine %s.", engineName);
191 return -1;
192}
193
198
200{
201 return fCurrentEngine;
202}
203
208
210{
211 fConnectedEnginePointers.push_back(mc);
212 if (fCurrentEngine) {
213 *mc = fCurrentEngine;
214 }
215}
216
221
223{
225}
226
231
233{
234 fUserStack = stack;
235}
236
243
244void TMCManager::ForwardTrack(Int_t toBeDone, Int_t trackId, Int_t parentId, TParticle *particle, Int_t engineId)
245{
246 if (engineId < 0 || engineId >= static_cast<Int_t>(fEngines.size())) {
247 ::Fatal("TMCManager::ForwardTrack", "Engine ID %i out of bounds. Have %zu engines.", engineId, fEngines.size());
248 }
249 if (trackId >= static_cast<Int_t>(fParticles.size())) {
250 fParticles.resize(trackId + 1, nullptr);
251 fParticlesStatus.resize(trackId + 1);
252 }
253 fParticles[trackId] = particle;
254 fParticlesStatus[trackId].reset(new TMCParticleStatus());
255 fParticlesStatus[trackId]->fId = trackId;
256 fParticlesStatus[trackId]->fParentId = parentId;
257 fParticlesStatus[trackId]->InitFromParticle(particle);
259 if (particle->IsPrimary()) {
261 }
262
263 if (toBeDone > 0) {
264 if (particle->IsPrimary()) {
265 fStacks[engineId]->PushPrimaryTrackId(trackId);
266 } else {
267 fStacks[engineId]->PushSecondaryTrackId(trackId);
268 }
269 }
270}
271
279
280void TMCManager::ForwardTrack(Int_t toBeDone, Int_t trackId, Int_t parentId, TParticle *particle)
281{
282 ForwardTrack(toBeDone, trackId, parentId, particle, fCurrentEngine->GetId());
283}
284
289
290void TMCManager::TransferTrack(Int_t engineTargetId)
291{
292 if (engineTargetId < 0 || engineTargetId >= static_cast<Int_t>(fEngines.size())) {
293 ::Fatal("TMCManager::TransferTrack",
294 "Target engine ID out of bounds. Have %zu engines. Requested target ID was %i", fEngines.size(),
295 engineTargetId);
296 }
297 TransferTrack(fEngines[engineTargetId]);
298}
299
304
306{
307 // Do nothing if target and current engines are the same
308 if (mc == fCurrentEngine) {
309 return;
310 }
311
312 // Get information on current track and extract status from transporting engine
313 Int_t trackId = fStacks[fCurrentEngine->GetId()]->GetCurrentTrackNumber();
314
315 fCurrentEngine->TrackPosition(fParticlesStatus[trackId]->fPosition);
316 fCurrentEngine->TrackMomentum(fParticlesStatus[trackId]->fMomentum);
317 fCurrentEngine->TrackPolarization(fParticlesStatus[trackId]->fPolarization);
318 fParticlesStatus[trackId]->fStepNumber = fCurrentEngine->StepNumber();
319 fParticlesStatus[trackId]->fTrackLength = fCurrentEngine->TrackLength();
320 fParticlesStatus[trackId]->fWeight = fCurrentEngine->TrackWeight();
321
322 // Store TGeoNavidator's fIsOutside state
323 fParticlesStatus[trackId]->fIsOutside = gGeoManager->IsOutside();
324
325 TGeoBranchArray *geoState = fBranchArrayContainer.GetNewGeoState(fParticlesStatus[trackId]->fGeoStateIndex);
326 geoState->InitFromNavigator(gGeoManager->GetCurrentNavigator());
327
328 // Push only the particle ID
329 if (fParticles[trackId]->IsPrimary()) {
330 fStacks[mc->GetId()]->PushPrimaryTrackId(trackId);
331 } else {
332 fStacks[mc->GetId()]->PushSecondaryTrackId(trackId);
333 }
335}
336
341
342Bool_t TMCManager::RestoreGeometryState(Int_t trackId, Bool_t checkTrackIdRange)
343{
344 if (checkTrackIdRange && (trackId < 0 || trackId >= static_cast<Int_t>(fParticles.size()) || !fParticles[trackId])) {
345 return kFALSE;
346 }
347 UInt_t &geoStateId = fParticlesStatus[trackId]->fGeoStateIndex;
348 if (geoStateId == 0) {
349 return kFALSE;
350 }
351 const TGeoBranchArray *branchArray = fBranchArrayContainer.GetGeoState(geoStateId);
352 branchArray->UpdateNavigator(gGeoManager->GetCurrentNavigator());
354 gGeoManager->SetOutside(fParticlesStatus[trackId]->fIsOutside);
355 geoStateId = 0;
356 return kTRUE;
357}
358
363
365{
366 return RestoreGeometryState(fStacks[fCurrentEngine->GetId()]->GetCurrentTrackNumber(), kFALSE);
367}
368
373
375{
376 if (fIsInitialized) {
377 return;
378 }
379
380 if (!fUserStack) {
381 ::Fatal("TMCManager::Run", "Missing user stack pointer.");
382 }
383 if (fEngines.empty()) {
384 ::Fatal("TMCManager::Run", "No engines registered");
385 }
386
387 for (auto &mc : fEngines) {
388 // Must have geometry handling via TGeo
389 if (!mc->IsRootGeometrySupported()) {
390 ::Fatal("TMCManager::Run", "Engine %s does not support geometry built via ROOT's TGeoManager", mc->GetName());
391 }
392 Int_t currentEngineId = mc->GetId();
393 // To be able to forward info to the user stack
394 fStacks[currentEngineId]->SetUserStack(fUserStack);
395 // Connect the engine's stack to the centrally managed vectors
396 fStacks[currentEngineId]->ConnectTrackContainers(&fParticles, &fParticlesStatus, &fBranchArrayContainer,
398 }
399
400 // Initialize the fBranchArrayContainer to manage and cache TGeoBranchArrays
402
403 fIsInitialized = kTRUE;
404
405 // Send warning if only one engine ==> overhead
406 if (fEngines.size() == 1) {
407 ::Warning("TMCManager::Run", "Only one engine registered. That will lead to overhead in "
408 "the simulation run due to additional hooks and dispatches "
409 "to the TMCManager.");
410 }
411}
412
417
418void TMCManager::Run(Int_t nEvents)
419{
420 if (!fIsInitialized) {
421 ::Fatal("TMCManager::Run", "Engines have not yet been initialized.");
422 }
423
424 // Set user initialize true in any case now so that this cannot happen by accident during a run
425 fIsInitializedUser = kTRUE;
426
427 if (nEvents < 1) {
428 ::Fatal("TMCManager::Run", "Need at least one event to process but %i events specified.", nEvents);
429 }
430
431 // Run 1 event nEvents times
432 for (Int_t i = 0; i < nEvents; i++) {
433 ::Info("TMCManager::Run", "Start event %i", i + 1);
436 // Loop as long as there are tracks in any engine stack
437 while (GetNextEngine()) {
438 fCurrentEngine->ProcessEvent(i, kTRUE);
439 }
441 }
442 TerminateRun();
443}
444
449
451{
453 // Reset in event flag for all engines and clear stacks
454 for (auto &stack : fStacks) {
455 stack->ResetInternals();
456 }
457 for (UInt_t i = 0; i < fParticles.size(); i++) {
458 fParticlesStatus.clear();
459 fParticlesStatus.resize(fParticles.size());
460 fParticles[i] = nullptr;
461 }
462
463 // GeneratePrimaries centrally
465}
466
471
473{
474 // Select next engine based on finite number of particles on the stack
475 for (UInt_t i = 0; i < fStacks.size(); i++) {
476 if (fStacks[i]->GetStackedNtrack() > 0) {
478 return kTRUE;
479 }
480 }
481 // No tracks to be processed.
482 return kFALSE;
483}
484
489
491{
492 fCurrentEngine = mc;
493 for (TVirtualMC **&mcPtr : fConnectedEnginePointers) {
494 *mcPtr = mc;
495 }
496 // Make sure TVirtualMC::GetMC() returns the current engine.
497 TVirtualMC::fgMC = mc;
498}
499
504
506{
507 for (auto &mc : fEngines) {
508 mc->TerminateRun();
509 }
510}
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.
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:43
Int_t GetEngineId(const char *name) const
Get engine ID by its name.
Definition: TMCManager.cxx:183
Bool_t RestoreGeometryState()
Try to restore geometry for the track currently set.
Definition: TMCManager.cxx:364
TVirtualMC * GetCurrentEngine() const
Get the current engine pointer.
Definition: TMCManager.cxx:199
Bool_t fGeometryConstructed
Definition: TMCManager.h:203
void TerminateRun()
Terminate a run in all engines.
Definition: TMCManager.cxx:505
virtual ~TMCManager()
Destructor.
Definition: TMCManager.cxx:68
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:244
std::vector< TParticle * > fParticles
All tracks (persistent)
Definition: TMCManager.h:185
std::vector< TVirtualMC ** > fConnectedEnginePointers
Connected engine pointers which will be updated everytime the current engine changes.
Definition: TMCManager.h:194
Int_t fTotalNPrimaries
Total number of primaries ever pushed.
Definition: TMCManager.h:189
void ConnectEnginePointer(TVirtualMC **mc)
Connect a pointer which is updated whenever the engine is changed.
Definition: TMCManager.cxx:209
void TransferTrack(Int_t engineTargetId)
Transfer track from current engine to engine with engineTargetId.
Definition: TMCManager.cxx:290
Bool_t GetNextEngine()
Find the next engine.
Definition: TMCManager.cxx:472
TVirtualMC * fCurrentEngine
Pointer to current engine.
Definition: TMCManager.h:179
TVirtualMC * GetEngine(Int_t id) const
Get an engine pointer by ID.
Definition: TMCManager.cxx:170
void UpdateEnginePointers(TVirtualMC *mc)
Update all engine pointers connected to the TMCManager.
Definition: TMCManager.cxx:490
void Init()
Initialize engines.
Definition: TMCManager.cxx:374
Bool_t fIsInitializedUser
Flag if specific initialization for engines was done.
Definition: TMCManager.h:202
TVirtualMCApplication * fApplication
Pointer to user application.
Definition: TMCManager.h:177
void PrepareNewEvent()
Do necessary steps before an event is triggered.
Definition: TMCManager.cxx:450
std::vector< std::unique_ptr< TMCManagerStack > > fStacks
Stacks connected to engines.
Definition: TMCManager.h:183
TVirtualMCStack * fUserStack
Pointer to user stack.
Definition: TMCManager.h:196
static TMCThreadLocal TMCManager * fgInstance
Singleton instance.
Definition: TMCManager.h:171
static TMCManager * Instance()
Static access method.
Definition: TMCManager.cxx:81
Int_t fTotalNTracks
Total number of tracks ever pushed.
Definition: TMCManager.h:191
TMCManager()
Default constructor.
Definition: TMCManager.cxx:53
std::vector< std::unique_ptr< TMCParticleStatus > > fParticlesStatus
All particles' status (persistent)
Definition: TMCManager.h:187
void Run(Int_t nEvents)
Run the event loop.
Definition: TMCManager.cxx:418
std::vector< TVirtualMC * > fEngines
Collecting pointers to all instanciated TVirtualMCs.
Definition: TMCManager.h:181
Bool_t fIsInitialized
Flag if engines are initilaized.
Definition: TMCManager.h:200
void SetUserStack(TVirtualMCStack *stack)
Set user stack.
Definition: TMCManager.cxx:232
Int_t NEngines() const
Return the number of registered engines.
Definition: TMCManager.cxx:146
TGeoMCBranchArrayContainer fBranchArrayContainer
Pointer to cache with geometry states.
Definition: TMCManager.h:198
void Register(TVirtualMC *engine)
A TVirtualMC will register itself via this method during construction if a TMCManager was instanciate...
Definition: TMCManager.cxx:93
void GetEngines(std::vector< TVirtualMC * > &engines) const
Get registered engine pointers.
Definition: TMCManager.cxx:156
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:49
virtual Int_t StepNumber() const =0
Return the current step number.
virtual void InterruptTrack()=0
That triggers stopping the transport of the current track without dispatching to common routines like...
virtual Double_t TrackLength() const =0
Return the length of the current track from its origin (in cm)
virtual void ProcessEvent()=0
Process one event.
void SetId(UInt_t id)
Set the VMC id.
Definition: TVirtualMC.cxx:170
virtual void TrackPolarization(Double_t &polX, Double_t &polY, Double_t &polZ) const =0
Get the current polarization.
virtual Double_t TrackWeight() const =0
Get the current weight.
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:129
void SetManagerStack(TMCManagerStack *stack)
Set container holding additional information for transported TParticles.
Definition: TVirtualMC.cxx:179
static TMCThreadLocal TVirtualMC * fgMC
Static TVirtualMC pointer.
Definition: TVirtualMC.h:910
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:881