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) {