From 6ccd10a429d13cdfbda5b49cbf23a1ed78f04b54 Mon Sep 17 00:00:00 2001
From: John Chapman <jchapman@cern.ch>
Date: Wed, 17 Jul 2019 13:31:19 +0200
Subject: [PATCH] Drop G4AtlasSvc from G4AtlasAlg and G4TransportTool to make
 initialization order clearer

---
 .../G4Atlas/G4AtlasAlg/src/G4AtlasAlg.cxx     | 44 +++++++++++++---
 .../G4Atlas/G4AtlasAlg/src/G4AtlasAlg.h       |  7 +--
 .../test_AtlasG4_cosmics_configuration.py     |  8 +--
 .../test/test_AtlasG4_tf_configuration.py     |  8 +--
 .../test/test_TestBeam_tf_configuration.py    |  8 +--
 .../ISF_Geant4Tools/src/TransportTool.cxx     | 50 ++++++++++++++++---
 .../ISF_Geant4Tools/src/TransportTool.h       |  7 +--
 7 files changed, 99 insertions(+), 33 deletions(-)

diff --git a/Simulation/G4Atlas/G4AtlasAlg/src/G4AtlasAlg.cxx b/Simulation/G4Atlas/G4AtlasAlg/src/G4AtlasAlg.cxx
index d477355a63a..3553af7ee50 100644
--- a/Simulation/G4Atlas/G4AtlasAlg/src/G4AtlasAlg.cxx
+++ b/Simulation/G4Atlas/G4AtlasAlg/src/G4AtlasAlg.cxx
@@ -25,6 +25,9 @@
 #include "G4StackManager.hh"
 #include "G4UImanager.hh"
 #include "G4ScoringManager.hh"
+#include "G4VUserPhysicsList.hh"
+#include "G4VModularPhysicsList.hh"
+#include "G4ParallelWorldPhysics.hh"
 
 // CLHEP includes
 #include "CLHEP/Random/RandomEngine.h"
@@ -61,6 +64,7 @@ G4AtlasAlg::G4AtlasAlg(const std::string& name, ISvcLocator* pSvcLocator)
   declareProperty("G4Commands", m_g4commands, "Commands to send to the G4UI");
   // Multi-threading specific settings
   declareProperty("MultiThreading", m_useMT, "Multi-threading specific settings");
+  declareProperty("ActivateParallelWorlds",m_activateParallelGeometries,"Toggle on/off the G4 parallel geometry system");
 
   // Verbosities
   declareProperty("Verbosities", m_verbosities);
@@ -88,9 +92,6 @@ StatusCode G4AtlasAlg::initialize()
   ATH_CHECK( m_rndmGenSvc.retrieve() );
   ATH_CHECK( m_userActionSvc.retrieve() );
 
-  // FIXME TOO EARLY???
-  ATH_CHECK(m_g4atlasSvc.retrieve());
-
   ATH_CHECK(m_senDetTool.retrieve());
   ATH_CHECK(m_fastSimTool.retrieve());
 
@@ -179,10 +180,39 @@ void G4AtlasAlg::initializeOnce()
     commandLog(returnCode, g4command);
   }
 
-  // G4 init moved to PyG4AtlasAlg / G4AtlasEngine
-  /// @todo Reinstate or delete?! This can't actually be called from the Py algs
-  //ATH_MSG_INFO("Firing initialization of G4!!!");
-  //initializeG4();
+  // Code from G4AtlasSvc
+  auto* rm = G4RunManager::GetRunManager();
+  if(!rm) {
+    throw std::runtime_error("Run manager retrieval has failed");
+  }
+  rm->Initialize();     // Initialization differs slightly in multi-threading.
+  // TODO: add more details about why this is here.
+  if(!m_useMT && rm->ConfirmBeamOnCondition()) {
+    rm->RunInitialization();
+  }
+
+  ATH_MSG_INFO( "retireving the Detector Geometry Service" );
+  if(m_detGeoSvc.retrieve().isFailure()) {
+    throw std::runtime_error("Could not initialize ATLAS DetectorGeometrySvc!");
+  }
+
+  if(m_userLimitsSvc.retrieve().isFailure()) {
+    throw std::runtime_error("Could not initialize ATLAS UserLimitsSvc!");
+  }
+
+  if (m_activateParallelGeometries) {
+    G4VModularPhysicsList* thePhysicsList=dynamic_cast<G4VModularPhysicsList*>(m_physListSvc->GetPhysicsList());
+    if (!thePhysicsList) {
+      throw std::runtime_error("Failed dynamic_cast!! this is not a G4VModularPhysicsList!");
+    }
+#if G4VERSION_NUMBER >= 1010
+    std::vector<std::string>& parallelWorldNames=m_detGeoSvc->GetParallelWorldNames();
+    for (auto& it: parallelWorldNames) {
+      thePhysicsList->RegisterPhysics(new G4ParallelWorldPhysics(it,true));
+    }
+#endif
+  }
+
   return;
 }
 
diff --git a/Simulation/G4Atlas/G4AtlasAlg/src/G4AtlasAlg.h b/Simulation/G4Atlas/G4AtlasAlg/src/G4AtlasAlg.h
index 416ea22cd7f..6275e766845 100644
--- a/Simulation/G4Atlas/G4AtlasAlg/src/G4AtlasAlg.h
+++ b/Simulation/G4Atlas/G4AtlasAlg/src/G4AtlasAlg.h
@@ -25,7 +25,7 @@
 #include "G4AtlasInterfaces/ISensitiveDetectorMasterTool.h"
 #include "G4AtlasInterfaces/IFastSimulationMasterTool.h"
 #include "G4AtlasInterfaces/IPhysicsListSvc.h"
-#include "G4AtlasInterfaces/IG4AtlasSvc.h"
+#include "G4AtlasInterfaces/IUserLimitsSvc.h"
 #include "GeneratorObjects/McEventCollection.h"
 
 // ISF includes
@@ -119,10 +119,11 @@ private:
   std::vector<std::string> m_g4commands;
   /// Activate multi-threading configuration
   bool m_useMT{false};
+  bool m_activateParallelGeometries{false};
   /// Random number service
   ServiceHandle<IAthRNGSvc> m_rndmGenSvc{this, "AtRndmGenSvc", "AthRNGSvc", ""}; // TODO rename property
-  /// G4Atlas Service - handles G4 initialization
-  ServiceHandle<IG4AtlasSvc> m_g4atlasSvc{this, "G4AtlasSvc", "G4AtlasSvc", ""};
+  ///
+  ServiceHandle<IUserLimitsSvc> m_userLimitsSvc{this, "UserLimitsSvc", "UserLimitsSvc", ""};
   /// User Action Service
   ServiceHandle<G4UA::IUserActionSvc> m_userActionSvc{this, "UserActionSvc", "G4UA::UserActionSvc", ""};
   /// Detector Geometry Service (builds G4 Geometry)
diff --git a/Simulation/G4Atlas/G4AtlasApps/test/test_AtlasG4_cosmics_configuration.py b/Simulation/G4Atlas/G4AtlasApps/test/test_AtlasG4_cosmics_configuration.py
index 55260b5f47e..37484ce4240 100755
--- a/Simulation/G4Atlas/G4AtlasApps/test/test_AtlasG4_cosmics_configuration.py
+++ b/Simulation/G4Atlas/G4AtlasApps/test/test_AtlasG4_cosmics_configuration.py
@@ -238,7 +238,7 @@ class TestAtlasG4Cosmics(unittest.TestCase):
 
 
     def test___G4AtlasAlg_ListOfSetProperties(self):
-        expected_list = ['AtRndmGenSvc', 'DetGeoSvc', 'DetStore', 'EvtStore', 'ExtraInputs', 'ExtraOutputs', 'FastSimMasterTool', 'FlagAbortedEvents', 'G4AtlasSvc', 'G4Commands', 'GeoIDSvc', 'InputConverter', 'InputTruthCollection', 'KillAbortedEvents', 'MultiThreading', 'NeededResources', 'OutputTruthCollection', 'PhysicsListSvc', 'RandomGenerator', 'RecordFlux', 'ReleaseGeoModel', 'SenDetMasterTool', 'TruthRecordService', 'UserActionSvc', 'Verbosities']
+        expected_list = ['AtRndmGenSvc', 'DetGeoSvc', 'DetStore', 'EvtStore', 'ExtraInputs', 'ExtraOutputs', 'FastSimMasterTool', 'FlagAbortedEvents', 'G4Commands', 'GeoIDSvc', 'InputConverter', 'InputTruthCollection', 'KillAbortedEvents', 'MultiThreading', 'NeededResources', 'OutputTruthCollection', 'PhysicsListSvc', 'RandomGenerator', 'RecordFlux', 'ReleaseGeoModel', 'SenDetMasterTool', 'TruthRecordService', 'UserActionSvc', 'UserLimitsSvc', 'Verbosities']
         g4atlasalg = self._job_config_dict['G4AtlasAlg']
         actual_list = g4atlasalg.keys()
         expected_property_value_sorted = sorted(expected_list)
@@ -282,9 +282,9 @@ class TestAtlasG4Cosmics(unittest.TestCase):
         self._assert_Algorithm_property_equal('G4AtlasAlg', 'SenDetMasterTool', expected_tool_name)
 
 
-    def test___G4AtlasAlg_G4AtlasSvc_setCorrectly(self):
-        expected_service_name = 'G4AtlasSvc'
-        self._assert_Algorithm_property_equal('G4AtlasAlg', 'G4AtlasSvc', expected_service_name)
+    def test___G4AtlasAlg_UserLimitsSvc_setCorrectly(self):
+        expected_service_name = 'UserLimitsSvc'
+        self._assert_Algorithm_property_equal('G4AtlasAlg', 'UserLimitsSvc', expected_service_name)
 
 
     def test___G4AtlasAlg_UserActionSvc_setCorrectly(self):
diff --git a/Simulation/G4Atlas/G4AtlasApps/test/test_AtlasG4_tf_configuration.py b/Simulation/G4Atlas/G4AtlasApps/test/test_AtlasG4_tf_configuration.py
index 6fc74c7b3c6..70be030e872 100755
--- a/Simulation/G4Atlas/G4AtlasApps/test/test_AtlasG4_tf_configuration.py
+++ b/Simulation/G4Atlas/G4AtlasApps/test/test_AtlasG4_tf_configuration.py
@@ -154,7 +154,7 @@ class TestAtlasG4(unittest.TestCase):
 
 
     def test___G4AtlasAlg_ListOfSetProperties(self):
-        expected_list = ['AtRndmGenSvc', 'DetGeoSvc', 'DetStore', 'EvtStore', 'ExtraInputs', 'ExtraOutputs', 'FastSimMasterTool', 'FlagAbortedEvents', 'G4AtlasSvc', 'G4Commands', 'GeoIDSvc', 'InputConverter', 'InputTruthCollection', 'KillAbortedEvents', 'MultiThreading', 'NeededResources', 'OutputTruthCollection', 'PhysicsListSvc', 'RandomGenerator', 'RecordFlux', 'ReleaseGeoModel', 'SenDetMasterTool', 'TruthRecordService', 'UserActionSvc', 'Verbosities']
+        expected_list = ['AtRndmGenSvc', 'DetGeoSvc', 'DetStore', 'EvtStore', 'ExtraInputs', 'ExtraOutputs', 'FastSimMasterTool', 'FlagAbortedEvents', 'G4Commands', 'GeoIDSvc', 'InputConverter', 'InputTruthCollection', 'KillAbortedEvents', 'MultiThreading', 'NeededResources', 'OutputTruthCollection', 'PhysicsListSvc', 'RandomGenerator', 'RecordFlux', 'ReleaseGeoModel', 'SenDetMasterTool', 'TruthRecordService', 'UserActionSvc', 'UserLimitsSvc', 'Verbosities']
         g4atlasalg = self._job_config_dict['G4AtlasAlg']
         actual_list = g4atlasalg.keys()
         expected_property_value_sorted = sorted(expected_list)
@@ -198,9 +198,9 @@ class TestAtlasG4(unittest.TestCase):
         self._assert_Algorithm_property_equal('G4AtlasAlg', 'SenDetMasterTool', expected_tool_name)
 
 
-    def test___G4AtlasAlg_G4AtlasSvc_setCorrectly(self):
-        expected_service_name = 'G4AtlasSvc'
-        self._assert_Algorithm_property_equal('G4AtlasAlg', 'G4AtlasSvc', expected_service_name)
+    def test___G4AtlasAlg_UserLimitsSvc_setCorrectly(self):
+        expected_service_name = 'UserLimitsSvc'
+        self._assert_Algorithm_property_equal('G4AtlasAlg', 'UserLimitsSvc', expected_service_name)
 
 
     def test___G4AtlasAlg_UserActionSvc_setCorrectly(self):
diff --git a/Simulation/G4Atlas/G4AtlasApps/test/test_TestBeam_tf_configuration.py b/Simulation/G4Atlas/G4AtlasApps/test/test_TestBeam_tf_configuration.py
index 7f50108358f..2e759db16d6 100755
--- a/Simulation/G4Atlas/G4AtlasApps/test/test_TestBeam_tf_configuration.py
+++ b/Simulation/G4Atlas/G4AtlasApps/test/test_TestBeam_tf_configuration.py
@@ -174,7 +174,7 @@ class TestTestBeam(unittest.TestCase):
 
 
     def test___G4AtlasAlg_ListOfSetProperties(self):
-        expected_list = ['AtRndmGenSvc', 'DetGeoSvc', 'DetStore', 'EvtStore', 'ExtraInputs', 'ExtraOutputs', 'FastSimMasterTool', 'G4AtlasSvc', 'G4Commands', 'GeoIDSvc', 'InputConverter', 'InputTruthCollection', 'MultiThreading', 'NeededResources', 'OutputTruthCollection', 'PhysicsListSvc', 'RandomGenerator', 'RecordFlux', 'ReleaseGeoModel', 'SenDetMasterTool', 'TruthRecordService', 'UserActionSvc', 'Verbosities']
+        expected_list = ['AtRndmGenSvc', 'DetGeoSvc', 'DetStore', 'EvtStore', 'ExtraInputs', 'ExtraOutputs', 'FastSimMasterTool', 'G4Commands', 'GeoIDSvc', 'InputConverter', 'InputTruthCollection', 'MultiThreading', 'NeededResources', 'OutputTruthCollection', 'PhysicsListSvc', 'RandomGenerator', 'RecordFlux', 'ReleaseGeoModel', 'SenDetMasterTool', 'TruthRecordService', 'UserActionSvc', 'UserLimitsSvc', 'Verbosities']
         g4atlasalg = self._job_config_dict['G4AtlasAlg']
         actual_list = g4atlasalg.keys()
         expected_property_value_sorted = sorted(expected_list)
@@ -218,9 +218,9 @@ class TestTestBeam(unittest.TestCase):
         self._assert_Algorithm_property_equal('G4AtlasAlg', 'SenDetMasterTool', expected_tool_name)
 
 
-    def test___G4AtlasAlg_G4AtlasSvc_setCorrectly(self):
-        expected_service_name = 'G4AtlasSvc'
-        self._assert_Algorithm_property_equal('G4AtlasAlg', 'G4AtlasSvc', expected_service_name)
+    def test___G4AtlasAlg_UserLimitsSvc_setCorrectly(self):
+        expected_service_name = 'UserLimitsSvc'
+        self._assert_Algorithm_property_equal('G4AtlasAlg', 'UserLimitsSvc', expected_service_name)
 
 
     def test___G4AtlasAlg_UserActionSvc_setCorrectly(self):
diff --git a/Simulation/ISF/ISF_Geant4/ISF_Geant4Tools/src/TransportTool.cxx b/Simulation/ISF/ISF_Geant4/ISF_Geant4Tools/src/TransportTool.cxx
index 45b164a2b6d..66b0e0bdb16 100644
--- a/Simulation/ISF/ISF_Geant4/ISF_Geant4Tools/src/TransportTool.cxx
+++ b/Simulation/ISF/ISF_Geant4/ISF_Geant4Tools/src/TransportTool.cxx
@@ -38,6 +38,9 @@
 #include "G4ScoringManager.hh"
 #include "G4Timer.hh"
 #include "G4SDManager.hh"
+#include "G4VUserPhysicsList.hh"
+#include "G4VModularPhysicsList.hh"
+#include "G4ParallelWorldPhysics.hh"
 
 #include "AtlasDetDescr/AtlasRegionHelper.h"
 
@@ -63,6 +66,7 @@ iGeant4::G4TransportTool::G4TransportTool(const std::string& type,
   //declareProperty("KillAllNeutrinos",      m_KillAllNeutrinos=true);
   //declareProperty("KillLowEPhotons",       m_KillLowEPhotons=-1.);
   declareProperty("PrintTimingInfo",      m_doTiming       );
+  declareProperty("ActivateParallelWorlds",m_activateParallelGeometries,"Toggle on/off the G4 parallel geometry system");
 
 }
 
@@ -84,9 +88,10 @@ StatusCode iGeant4::G4TransportTool::initialize()
     m_runTimer->Start();
   }
 
-  ATH_CHECK(m_inputConverter.retrieve());
+  // Create the scoring manager if requested
+  if (m_recordFlux) G4ScoringManager::GetScoringManager();
 
- // One-time initialization
+  // One-time initialization
   try {
     std::call_once(initializeOnceFlag, &iGeant4::G4TransportTool::initializeOnce, this);
   }
@@ -98,15 +103,11 @@ StatusCode iGeant4::G4TransportTool::initialize()
   ATH_CHECK( m_rndmGenSvc.retrieve() );
   ATH_CHECK( m_userActionSvc.retrieve() );
 
-  ATH_CHECK(m_g4atlasSvc.retrieve());
-
-  if (m_recordFlux) G4ScoringManager::GetScoringManager();
-
-  ATH_CHECK (m_detGeoSvc.retrieve());
-
   ATH_CHECK(m_senDetTool.retrieve());
   ATH_CHECK(m_fastSimTool.retrieve());
 
+  ATH_CHECK(m_inputConverter.retrieve());
+
   return StatusCode::SUCCESS;
 }
 
@@ -167,6 +168,39 @@ void iGeant4::G4TransportTool::initializeOnce()
     commandLog(returnCode, g4command);
   }
 
+  // Code from G4AtlasSvc
+  auto* rm = G4RunManager::GetRunManager();
+  if(!rm) {
+    throw std::runtime_error("Run manager retrieval has failed");
+  }
+  rm->Initialize();     // Initialization differs slightly in multi-threading.
+  // TODO: add more details about why this is here.
+  if(!m_useMT && rm->ConfirmBeamOnCondition()) {
+    rm->RunInitialization();
+  }
+
+  ATH_MSG_INFO( "retireving the Detector Geometry Service" );
+  if(m_detGeoSvc.retrieve().isFailure()) {
+    throw std::runtime_error("Could not initialize ATLAS DetectorGeometrySvc!");
+  }
+
+  if(m_userLimitsSvc.retrieve().isFailure()) {
+    throw std::runtime_error("Could not initialize ATLAS UserLimitsSvc!");
+  }
+
+  if (m_activateParallelGeometries) {
+    G4VModularPhysicsList* thePhysicsList=dynamic_cast<G4VModularPhysicsList*>(m_physListSvc->GetPhysicsList());
+    if (!thePhysicsList) {
+      throw std::runtime_error("Failed dynamic_cast!! this is not a G4VModularPhysicsList!");
+    }
+#if G4VERSION_NUMBER >= 1010
+    std::vector<std::string>& parallelWorldNames=m_detGeoSvc->GetParallelWorldNames();
+    for (auto& it: parallelWorldNames) {
+      thePhysicsList->RegisterPhysics(new G4ParallelWorldPhysics(it,true));
+    }
+#endif
+  }
+
   return;
 }
 
diff --git a/Simulation/ISF/ISF_Geant4/ISF_Geant4Tools/src/TransportTool.h b/Simulation/ISF/ISF_Geant4/ISF_Geant4Tools/src/TransportTool.h
index df087174245..ee3fcd76682 100644
--- a/Simulation/ISF/ISF_Geant4/ISF_Geant4Tools/src/TransportTool.h
+++ b/Simulation/ISF/ISF_Geant4/ISF_Geant4Tools/src/TransportTool.h
@@ -19,12 +19,12 @@
 // Athena headers
 #include "AthenaKernel/IAthRNGSvc.h"
 #include "AthenaKernel/SlotSpecificObj.h"
-#include "G4AtlasInterfaces/IG4AtlasSvc.h"
 #include "G4AtlasInterfaces/IUserActionSvc.h"
 #include "G4AtlasInterfaces/IDetectorGeometrySvc.h"
 #include "G4AtlasInterfaces/ISensitiveDetectorMasterTool.h"
 #include "G4AtlasInterfaces/IFastSimulationMasterTool.h"
 #include "G4AtlasInterfaces/IPhysicsListSvc.h"
+#include "G4AtlasInterfaces/IUserLimitsSvc.h"
 #include "CxxUtils/checker_macros.h"
 
 // ISF includes
@@ -134,10 +134,11 @@ namespace iGeant4
     std::vector<std::string> m_g4commands;
     /// Activate multi-threading configuration
     bool m_useMT{false};
+    bool m_activateParallelGeometries{false};
     // Random number service
     ServiceHandle<IAthRNGSvc> m_rndmGenSvc{this, "RandomNumberService", "AthRNGSvc", ""};
-    /// G4AtlasSvc
-    ServiceHandle<IG4AtlasSvc> m_g4atlasSvc{this, "G4AtlasSvc", "G4AtlasSvc", ""};
+    ///
+    ServiceHandle<IUserLimitsSvc> m_userLimitsSvc{this, "UserLimitsSvc", "UserLimitsSvc", ""};
     /// user action service
     ServiceHandle<G4UA::IUserActionSvc> m_userActionSvc{this, "UserActionSvc", "", ""};
     /// Detector Geometry Service (builds G4 Geometry)
-- 
GitLab