From bad94e42f1337fd2c2ef7b1f29c1bc4b89c9b2fb Mon Sep 17 00:00:00 2001
From: Steve Farrell <sfarrell@cern.ch>
Date: Thu, 14 Sep 2017 03:02:10 +0200
Subject: [PATCH] Adding G4ThreadInitTool implementation.

Relocating this tool from G4HiveEx (named G4InitTool) to G4AtlasTools
with some minor changes, including improved method of assigning G4
thread ID and replacing some usages of 'auto'.
---
 .../G4AtlasTools/src/G4ThreadInitTool.cxx     | 119 ++++++++++++++++++
 .../G4AtlasTools/src/G4ThreadInitTool.h       |  47 +++++++
 .../src/components/G4AtlasTools_entries.cxx   |   2 +
 3 files changed, 168 insertions(+)
 create mode 100644 Simulation/G4Atlas/G4AtlasTools/src/G4ThreadInitTool.cxx
 create mode 100644 Simulation/G4Atlas/G4AtlasTools/src/G4ThreadInitTool.h

diff --git a/Simulation/G4Atlas/G4AtlasTools/src/G4ThreadInitTool.cxx b/Simulation/G4Atlas/G4AtlasTools/src/G4ThreadInitTool.cxx
new file mode 100644
index 00000000000..ce2d101c3d0
--- /dev/null
+++ b/Simulation/G4Atlas/G4AtlasTools/src/G4ThreadInitTool.cxx
@@ -0,0 +1,119 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// Main header include
+#include "G4ThreadInitTool.h"
+
+// Geant4 includes
+#include "G4WorkerRunManager.hh"
+#include "G4UImanager.hh"
+#include "G4MTRunManager.hh"
+#include "G4WorkerThread.hh"
+#include "G4UserWorkerThreadInitialization.hh"
+#include "G4RunManager.hh"
+#include "G4VUserActionInitialization.hh"
+#include "G4UserWorkerInitialization.hh"
+#include "G4AutoDelete.hh"
+
+// System includes
+#include <unistd.h>
+#include <sys/syscall.h>
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+G4ThreadInitTool::G4ThreadInitTool(const std::string& type,
+                                   const std::string& name,
+                                   const IInterface* parent)
+  : base_class(type, name, parent),
+    m_nInitThreads(0)
+{}
+
+//-----------------------------------------------------------------------------
+// Worker thread initialization.
+// This code is modeled after G4MTRunManagerKernel::StartThread.
+//-----------------------------------------------------------------------------
+void G4ThreadInitTool::initThread()
+{
+  ATH_MSG_INFO("==> tbb thread started with id: 0x" <<
+               std::hex << pthread_self() << std::dec);
+
+  // Define the G4 worker thread context and setup its cleanup mechanism.
+  auto wThreadContext = new G4WorkerThread;
+  G4AutoDelete::Register(wThreadContext);
+
+  // Assign the thread ID
+  static std::atomic_uint tid(0);
+  wThreadContext->SetThreadId( tid++ );
+  G4Threading::G4SetThreadId( wThreadContext->GetThreadId() );
+
+  // Setup thread-local geometry and physics
+  wThreadContext->BuildGeometryAndPhysicsVector();
+
+  // Retrieve the master thread run manager
+  G4MTRunManager* masterRM = G4MTRunManager::GetMasterRunManager();
+  // Worker thread initialization object
+  const G4UserWorkerThreadInitialization* workerInitializer =
+    masterRM->GetUserWorkerThreadInitialization();
+
+  // Random number setup.
+  // TODO: revisit this once MT AthRNGSvc is available.
+  const CLHEP::HepRandomEngine* masterEngine = masterRM->getMasterRandomEngine();
+  workerInitializer->SetupRNGEngine(masterEngine);
+
+  // Create the thread-local worker run manager (G4AtlasWorkerRunManager)
+  ATH_MSG_INFO("Creating worker RM");
+  G4WorkerRunManager* wrm = workerInitializer->CreateWorkerRunManager();
+  wrm->SetWorkerThread(wThreadContext);
+
+  // Share detector from master with worker.
+  ATH_MSG_INFO("Assigning detector construction");
+  const G4VUserDetectorConstruction* detector =
+    masterRM->GetUserDetectorConstruction();
+  // I don't want to const-cast here, but this is what they do in G4's
+  // StartThread function, so there is likely no alternative.
+  wrm->G4RunManager::SetUserInitialization
+    (const_cast<G4VUserDetectorConstruction*>(detector));
+  // Share physics list from master with worker.
+  const G4VUserPhysicsList* physicslist = masterRM->GetUserPhysicsList();
+  wrm->SetUserInitialization(const_cast<G4VUserPhysicsList*>(physicslist));
+
+  // Build thread-local user actions - NOT CURRENTLY USED.
+  if(masterRM->GetUserActionInitialization()) {
+    masterRM->GetNonConstUserActionInitialization()->Build();
+  }
+
+  // Start user worker initialization
+  if(masterRM->GetUserWorkerInitialization()) {
+    masterRM->GetUserWorkerInitialization()->WorkerStart();
+  }
+
+  // Initialize the worker run manager
+  ATH_MSG_INFO("Initializing worker RM");
+  wrm->Initialize();
+
+  // Copy the UI commands to the worker
+  std::vector<G4String> cmds = masterRM->GetCommandStack();
+  ATH_MSG_INFO (cmds.size() << " commands in UI stack");
+  G4UImanager* uimgr = G4UImanager::GetUIpointer();
+  for(const auto& it : cmds) {
+    ATH_MSG_INFO ("Adding command to worker: " << it);
+    uimgr->ApplyCommand(it);
+  }
+
+  // Atomic increment number of initialized threads
+  m_nInitThreads++;
+
+  ATH_MSG_INFO("==> tbb thread end of initThread with id: 0x" <<
+               std::hex << pthread_self() << std::dec);
+}
+
+//-----------------------------------------------------------------------------
+// Worker thread termination
+//-----------------------------------------------------------------------------
+void G4ThreadInitTool::terminateThread()
+{
+  // Atomic decrement number of initialized threads
+  m_nInitThreads--;
+}
diff --git a/Simulation/G4Atlas/G4AtlasTools/src/G4ThreadInitTool.h b/Simulation/G4Atlas/G4AtlasTools/src/G4ThreadInitTool.h
new file mode 100644
index 00000000000..b1e2ce119f3
--- /dev/null
+++ b/Simulation/G4Atlas/G4AtlasTools/src/G4ThreadInitTool.h
@@ -0,0 +1,47 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef G4ATLASTOOLS_G4THREADINITTOOL_H
+#define G4ATLASTOOLS_G4THREADINITTOOL_H
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/IThreadInitTool.h"
+
+#include <string>
+#include <atomic>
+
+/// @class G4ThreadInitTool
+/// @brief A tool which sets up the worker-thread-local workspace for Geant4.
+///
+/// @author Steve Farrell <Steven.Farrell@cern.ch>
+///
+class G4ThreadInitTool : virtual public extends1<AthAlgTool, IThreadInitTool>
+{
+
+  public:
+
+    /// Standard tool constructor
+    G4ThreadInitTool(const std::string&, const std::string&, const IInterface*);
+
+    /// Set up the Geant4 workspace for this worker thread
+    virtual void initThread() override final;
+
+    /// Tear down the Geant4 workspace for this worker thread
+    virtual void terminateThread() override final;
+
+    /// Counter used for barrier mechanism in thread initialization.
+    /// This number needs to be correctly reported to properly ensure
+    /// scheduling of thread-initialization tasks on every thread.
+    virtual unsigned int nInit() const override final {
+      return m_nInitThreads;
+    }
+
+  private:
+
+    /// Counter of threads that have been initialized
+    std::atomic_uint m_nInitThreads;
+
+}; // class G4ThreadInitTool
+
+#endif // G4ATLASTOOLS_G4THREADINITTOOL_H
diff --git a/Simulation/G4Atlas/G4AtlasTools/src/components/G4AtlasTools_entries.cxx b/Simulation/G4Atlas/G4AtlasTools/src/components/G4AtlasTools_entries.cxx
index c74a873e541..e19ec7de5c5 100644
--- a/Simulation/G4Atlas/G4AtlasTools/src/components/G4AtlasTools_entries.cxx
+++ b/Simulation/G4Atlas/G4AtlasTools/src/components/G4AtlasTools_entries.cxx
@@ -14,6 +14,7 @@
 #include "../FastSimulationMasterTool.h"
 #include "G4AtlasTools/GlobalFieldManagerTool.h"
 #include "G4AtlasTools/DetectorFieldManagerTool.h"
+#include "../G4ThreadInitTool.h"
 
 DECLARE_TOOL_FACTORY( PhysicsListToolBase )
 DECLARE_TOOL_FACTORY( DetectorGeometryBase )
@@ -29,3 +30,4 @@ DECLARE_TOOL_FACTORY( FastSimulationMasterTool )
 DECLARE_TOOL_FACTORY( AddPhysicsDecayTool )
 DECLARE_TOOL_FACTORY( GlobalFieldManagerTool )
 DECLARE_TOOL_FACTORY( DetectorFieldManagerTool )
+DECLARE_TOOL_FACTORY( G4ThreadInitTool )
-- 
GitLab