39 TMCThreadLocal TMCManager *TMCManager::fgInstance =
nullptr;
46 TMCManager::TMCManager()
47 : fApplication(nullptr), fCurrentEngine(nullptr), fTotalNPrimaries(0), fTotalNTracks(0), fUserStack(nullptr),
48 fBranchArrayContainer(), fIsInitialized(kFALSE), fIsInitializedUser(kFALSE)
51 ::Fatal(
"TMCManager::TMCManager",
"Attempt to create two instances of singleton.");
61 TMCManager::~TMCManager()
63 for (
auto &mc : fEngines) {
74 TMCManager *TMCManager::Instance()
86 void TMCManager::Register(TVirtualMC *mc)
89 for (
auto &currMC : fEngines) {
91 ::Fatal(
"TMCManager::RegisterMC",
"This engine is already registered.");
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());
102 UpdateEnginePointers(mc);
111 void TMCManager::Register(TVirtualMCApplication *application)
114 ::Fatal(
"TMCManager::Register",
"The application is already registered.");
116 ::Info(
"TMCManager::Register",
"Register user application and construct geometry");
117 fApplication = application;
119 fApplication->ConstructGeometry();
120 fApplication->MisalignGeometry();
121 fApplication->ConstructOpGeometry();
122 if (!gGeoManager->IsClosed()) {
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.");
136 Int_t TMCManager::NEngines()
const
138 return fEngines.size();
146 void TMCManager::GetEngines(std::vector<TVirtualMC *> &engines)
const
149 engines.resize(fEngines.size(),
nullptr);
150 for (UInt_t i = 0; i < fEngines.size(); i++) {
151 engines[i] = fEngines[i];
160 TVirtualMC *TMCManager::GetEngine(Int_t
id)
const
162 if (id < 0 || id >= static_cast<Int_t>(fEngines.size())) {
163 ::Fatal(
"TMCManager::GetEngine",
"Unknown engine ID.");
173 Int_t TMCManager::GetEngineId(
const char *engineName)
const
175 for (UInt_t i = 0; i < fEngines.size(); i++) {
176 if (strcmp(engineName, fEngines[i]->GetName()) == 0) {
180 ::Warning(
"TMCManager::GetEngineId",
"Unknown engine %s.", engineName);
189 TVirtualMC *TMCManager::GetCurrentEngine()
const
191 return fCurrentEngine;
199 void TMCManager::ConnectEnginePointer(TVirtualMC **mc)
201 fConnectedEnginePointers.push_back(mc);
202 if (fCurrentEngine) {
203 *mc = fCurrentEngine;
212 void TMCManager::ConnectEnginePointer(TVirtualMC *&mc)
214 ConnectEnginePointer(&mc);
222 void TMCManager::SetUserStack(TVirtualMCStack *stack)
234 void TMCManager::ForwardTrack(Int_t toBeDone, Int_t trackId, Int_t parentId, TParticle *particle, Int_t engineId)
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());
239 if (trackId >= static_cast<Int_t>(fParticles.size())) {
240 fParticles.resize(trackId + 1,
nullptr);
241 fParticlesStatus.resize(trackId + 1);
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()) {
254 if (particle->IsPrimary()) {
255 fStacks[engineId]->PushPrimaryTrackId(trackId);
257 fStacks[engineId]->PushSecondaryTrackId(trackId);
270 void TMCManager::ForwardTrack(Int_t toBeDone, Int_t trackId, Int_t parentId, TParticle *particle)
272 ForwardTrack(toBeDone, trackId, parentId, particle, fCurrentEngine->GetId());
280 void TMCManager::TransferTrack(Int_t engineTargetId)
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(),
287 TransferTrack(fEngines[engineTargetId]);
295 void TMCManager::TransferTrack(TVirtualMC *mc)
298 if (mc == fCurrentEngine) {
303 Int_t trackId = fStacks[fCurrentEngine->GetId()]->GetCurrentTrackNumber();
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();
313 fParticlesStatus[trackId]->fIsOutside = gGeoManager->IsOutside();
315 TGeoBranchArray *geoState = fBranchArrayContainer.GetNewGeoState(fParticlesStatus[trackId]->fGeoStateIndex);
316 geoState->InitFromNavigator(gGeoManager->GetCurrentNavigator());
319 if (fParticles[trackId]->IsPrimary()) {
320 fStacks[mc->GetId()]->PushPrimaryTrackId(trackId);
322 fStacks[mc->GetId()]->PushSecondaryTrackId(trackId);
324 fCurrentEngine->InterruptTrack();
332 Bool_t TMCManager::RestoreGeometryState(Int_t trackId, Bool_t checkTrackIdRange)
334 if (checkTrackIdRange && (trackId < 0 || trackId >= static_cast<Int_t>(fParticles.size()) || !fParticles[trackId])) {
337 UInt_t& geoStateId = fParticlesStatus[trackId]->fGeoStateIndex;
338 if(geoStateId == 0) {
341 const TGeoBranchArray* branchArray = fBranchArrayContainer.GetGeoState(geoStateId);
342 branchArray->UpdateNavigator(gGeoManager->GetCurrentNavigator());
343 fBranchArrayContainer.FreeGeoState(geoStateId);
344 gGeoManager->SetOutside(fParticlesStatus[trackId]->fIsOutside);
354 Bool_t TMCManager::RestoreGeometryState()
356 return RestoreGeometryState(fStacks[fCurrentEngine->GetId()]->GetCurrentTrackNumber(), kFALSE);
364 void TMCManager::Init()
366 if (fIsInitialized) {
371 ::Fatal(
"TMCManager::Run",
"Missing user stack pointer.");
373 if (fEngines.empty()) {
374 ::Fatal(
"TMCManager::Run",
"No engines registered");
377 for (
auto &mc : fEngines) {
379 if (!mc->IsRootGeometrySupported()) {
380 ::Fatal(
"TMCManager::Run",
"Engine %s does not support geometry built via ROOT's TGeoManager", mc->GetName());
382 Int_t currentEngineId = mc->GetId();
384 fStacks[currentEngineId]->SetUserStack(fUserStack);
386 fStacks[currentEngineId]->ConnectTrackContainers(&fParticles, &fParticlesStatus, &fBranchArrayContainer,
387 &fTotalNPrimaries, &fTotalNTracks);
391 fBranchArrayContainer.InitializeFromGeoManager(gGeoManager);
393 fIsInitialized = kTRUE;
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.");
408 void TMCManager::Run(Int_t nEvents)
410 if (!fIsInitialized) {
411 ::Fatal(
"TMCManager::Run",
"Engines have not yet been initialized.");
415 fIsInitializedUser = kTRUE;
418 ::Fatal(
"TMCManager::Run",
"Need at least one event to process but %i events specified.", nEvents);
422 for (Int_t i = 0; i < nEvents; i++) {
423 ::Info(
"TMCManager::Run",
"Start event %i", i + 1);
425 fApplication->BeginEvent();
427 while (GetNextEngine()) {
428 fCurrentEngine->ProcessEvent(i, kTRUE);
430 fApplication->FinishEvent();
440 void TMCManager::PrepareNewEvent()
442 fBranchArrayContainer.FreeGeoStates();
444 for (
auto &stack : fStacks) {
445 stack->ResetInternals();
447 for (UInt_t i = 0; i < fParticles.size(); i++) {
448 fParticlesStatus.clear();
449 fParticlesStatus.resize(fParticles.size());
450 fParticles[i] =
nullptr;
454 fApplication->GeneratePrimaries();
462 Bool_t TMCManager::GetNextEngine()
465 for (UInt_t i = 0; i < fStacks.size(); i++) {
466 if (fStacks[i]->GetStackedNtrack() > 0) {
467 UpdateEnginePointers(fEngines[i]);
480 void TMCManager::UpdateEnginePointers(TVirtualMC *mc)
483 for (TVirtualMC **&mcPtr : fConnectedEnginePointers) {
487 TVirtualMC::fgMC = mc;
495 void TMCManager::TerminateRun()
497 for (
auto &mc : fEngines) {