Geant4 Cross Reference |
1 // 2 // ******************************************************************** 3 // * License and Disclaimer * 4 // * * 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. * 10 // * * 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitation of liability. * 17 // * * 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************************************** 25 // 26 27 #include "G4TaskRunManagerKernel.hh" 28 29 #include "G4AutoLock.hh" 30 #include "G4DecayTable.hh" 31 #include "G4LogicalVolume.hh" 32 #include "G4Material.hh" 33 #include "G4MaterialTable.hh" 34 #include "G4PVParameterised.hh" 35 #include "G4PVReplica.hh" 36 #include "G4ParticleDefinition.hh" 37 #include "G4ParticleTable.hh" 38 #include "G4ParticleTableIterator.hh" 39 #include "G4PhysicalVolumeStore.hh" 40 #include "G4PhysicsVector.hh" 41 #include "G4PolyconeSide.hh" 42 #include "G4PolyhedraSide.hh" 43 #include "G4Region.hh" 44 #include "G4RegionStore.hh" 45 #include "G4Run.hh" 46 #include "G4StateManager.hh" 47 #include "G4TaskManager.hh" 48 #include "G4UImanager.hh" 49 #include "G4UserWorkerInitialization.hh" 50 #include "G4UserWorkerThreadInitialization.hh" 51 #include "G4VDecayChannel.hh" 52 #include "G4VModularPhysicsList.hh" 53 #include "G4VPhysicalVolume.hh" 54 #include "G4VPhysicsConstructor.hh" 55 #include "G4VUserActionInitialization.hh" 56 #include "G4VUserPhysicsList.hh" 57 #include "G4WorkerTaskRunManager.hh" 58 #include "G4WorkerThread.hh" 59 60 #include <atomic> 61 #include <memory> 62 63 //============================================================================// 64 65 std::vector<G4String> G4TaskRunManagerKernel::initCmdStack = {}; 66 67 //============================================================================// 68 69 G4TaskRunManagerKernel::G4TaskRunManagerKernel() : G4RunManagerKernel(masterRMK) 70 { 71 // This version of the constructor should never be called in sequential mode! 72 #ifndef G4MULTITHREADED 73 G4ExceptionDescription msg; 74 msg << "Geant4 code is compiled without multi-threading support " 75 "(-DG4MULTITHREADED " 76 "is set to off)."; 77 msg << " This type of RunManager can only be used in mult-threaded " 78 "applications."; 79 G4Exception("G4RunManagerKernel::G4RunManagerKernel()", "Run0109", FatalException, msg); 80 #endif 81 // Set flag that a MT-type kernel has been instantiated 82 G4Threading::SetMultithreadedApplication(true); 83 } 84 85 //============================================================================// 86 87 void G4TaskRunManagerKernel::SetupShadowProcess() const 88 { 89 // Behavior is the same as base class (sequential mode) 90 // ShadowProcess pointer == process poitner 91 G4RunManagerKernel::SetupShadowProcess(); 92 } 93 94 //============================================================================// 95 96 namespace 97 { 98 using WorkerRunManPtr_t = std::unique_ptr<G4WorkerTaskRunManager>; 99 using WorkerThreadPtr_t = std::unique_ptr<G4WorkerThread>; 100 101 WorkerRunManPtr_t& workerRM() 102 { 103 G4ThreadLocalStatic WorkerRunManPtr_t _instance{nullptr}; 104 return _instance; 105 } 106 107 WorkerThreadPtr_t& context() 108 { 109 G4ThreadLocalStatic WorkerThreadPtr_t _instance{nullptr}; 110 return _instance; 111 } 112 113 } // namespace 114 115 //============================================================================// 116 117 G4WorkerThread* G4TaskRunManagerKernel::GetWorkerThread() 118 { 119 return context().get(); 120 } 121 122 //============================================================================// 123 124 void G4TaskRunManagerKernel::InitializeWorker() 125 { 126 if (context() && workerRM()) return; 127 128 G4TaskRunManager* mrm = G4TaskRunManager::GetMasterRunManager(); 129 if (G4MTRunManager::GetMasterThreadId() == G4ThisThread::get_id()) { 130 G4TaskManager* taskManager = mrm->GetTaskManager(); 131 auto _fut = taskManager->async(InitializeWorker); 132 _fut->wait(); 133 return; 134 } 135 136 //!!!!!!!!!!!!!!!!!!!!!!!!!! 137 //!!!!!! IMPORTANT !!!!!!!!! 138 //!!!!!!!!!!!!!!!!!!!!!!!!!! 139 // Here is not sequential anymore and G4UserWorkerThreadInitialization is 140 // a shared user initialization class 141 // This means this method cannot use data memebers of G4RunManagerKernel 142 // unless they are invariant ("read-only") and can be safely shared. 143 // All the rest that is not invariant should be incapsualted into 144 // the context (or, as for wThreadContext be G4ThreadLocal) 145 //!!!!!!!!!!!!!!!!!!!!!!!!!! 146 147 G4Threading::WorkerThreadJoinsPool(); 148 context() = std::make_unique<G4WorkerThread>(); 149 150 //============================ 151 // Step-0: Thread ID 152 //============================ 153 // Initliazie per-thread stream-output 154 // The following line is needed before we actually do IO initialization 155 // becasue the constructor of UI manager resets the IO destination. 156 context()->SetNumberThreads((G4int)mrm->GetThreadPool()->size()); 157 context()->SetThreadId(G4int(G4ThreadPool::get_this_thread_id() - 1)); 158 G4int thisID = context()->GetThreadId(); 159 G4Threading::G4SetThreadId(thisID); 160 G4UImanager::GetUIpointer()->SetUpForAThread(thisID); 161 162 //============================ 163 // Optimization: optional 164 //============================ 165 // Enforce thread affinity if requested 166 context()->SetPinAffinity(mrm->GetPinAffinity()); 167 168 //============================ 169 // Step-1: Random number engine 170 //============================ 171 // RNG Engine needs to be initialized by "cloning" the master one. 172 const CLHEP::HepRandomEngine* masterEngine = mrm->getMasterRandomEngine(); 173 mrm->GetUserWorkerThreadInitialization()->SetupRNGEngine(masterEngine); 174 175 //============================ 176 // Step-2: Initialize worker thread 177 //============================ 178 if (mrm->GetUserWorkerInitialization() != nullptr) 179 mrm->GetUserWorkerInitialization()->WorkerInitialize(); 180 181 if (mrm->GetUserActionInitialization() != nullptr) { 182 G4VSteppingVerbose* sv = mrm->GetUserActionInitialization()->InitializeSteppingVerbose(); 183 if (sv != nullptr) G4VSteppingVerbose::SetInstance(sv); 184 } 185 // Now initialize worker part of shared objects (geometry/physics) 186 G4WorkerThread::BuildGeometryAndPhysicsVector(); 187 workerRM().reset(static_cast<G4WorkerTaskRunManager*>( 188 mrm->GetUserWorkerThreadInitialization()->CreateWorkerRunManager())); 189 auto& wrm = workerRM(); 190 wrm->SetWorkerThread(context().get()); 191 192 //================================ 193 // Step-3: Setup worker run manager 194 //================================ 195 // Set the detector and physics list to the worker thread. Share with master 196 const G4VUserDetectorConstruction* detector = mrm->GetUserDetectorConstruction(); 197 wrm->G4RunManager::SetUserInitialization(const_cast<G4VUserDetectorConstruction*>(detector)); 198 const G4VUserPhysicsList* physicslist = mrm->GetUserPhysicsList(); 199 wrm->SetUserInitialization(const_cast<G4VUserPhysicsList*>(physicslist)); 200 201 //================================ 202 // Step-4: Initialize worker run manager 203 //================================ 204 if (mrm->GetUserActionInitialization() != nullptr) 205 mrm->GetNonConstUserActionInitialization()->Build(); 206 if (mrm->GetUserWorkerInitialization() != nullptr) 207 mrm->GetUserWorkerInitialization()->WorkerStart(); 208 209 workerRM()->Initialize(); 210 211 for (auto& itr : initCmdStack) 212 G4UImanager::GetUIpointer()->ApplyCommand(itr); 213 214 wrm->ProcessUI(); 215 } 216 217 //============================================================================// 218 219 void G4TaskRunManagerKernel::ExecuteWorkerInit() 220 { 221 // because of TBB 222 if (G4MTRunManager::GetMasterThreadId() == G4ThisThread::get_id()) { 223 G4TaskManager* taskManager = G4TaskRunManager::GetMasterRunManager()->GetTaskManager(); 224 auto _fut = taskManager->async(ExecuteWorkerInit); 225 return _fut->get(); 226 } 227 228 // this check is for TBB as there is not a way to run an initialization 229 // routine on each thread 230 if (!workerRM()) InitializeWorker(); 231 232 auto& wrm = workerRM(); 233 assert(wrm.get() != nullptr); 234 wrm->DoCleanup(); 235 } 236 237 //============================================================================// 238 239 void G4TaskRunManagerKernel::ExecuteWorkerTask() 240 { 241 // because of TBB 242 if (G4MTRunManager::GetMasterThreadId() == G4ThisThread::get_id()) { 243 G4TaskManager* taskManager = G4TaskRunManager::GetMasterRunManager()->GetTaskManager(); 244 auto _fut = taskManager->async(ExecuteWorkerTask); 245 return _fut->get(); 246 } 247 248 // this check is for TBB as there is not a way to run an initialization 249 // routine on each thread 250 if (!workerRM()) InitializeWorker(); 251 252 auto& wrm = workerRM(); 253 assert(wrm.get() != nullptr); 254 wrm->DoWork(); 255 } 256 257 //============================================================================// 258 259 void G4TaskRunManagerKernel::TerminateWorkerRunEventLoop() 260 { 261 if (workerRM()) TerminateWorkerRunEventLoop(workerRM().get()); 262 } 263 264 //============================================================================// 265 266 void G4TaskRunManagerKernel::TerminateWorker() 267 { 268 //=============================== 269 // Step-6: Terminate worker thread 270 //=============================== 271 G4TaskRunManager* mrm = G4TaskRunManager::GetMasterRunManager(); 272 if ((mrm != nullptr) && (mrm->GetUserWorkerInitialization() != nullptr)) 273 mrm->GetUserWorkerInitialization()->WorkerStop(); 274 275 workerRM().reset(); 276 context().reset(); 277 278 G4WorkerThread::DestroyGeometryAndPhysicsVector(); 279 280 G4Threading::WorkerThreadLeavesPool(); 281 } 282 283 //============================================================================// 284 285 void G4TaskRunManagerKernel::TerminateWorkerRunEventLoop(G4WorkerTaskRunManager* wrm) 286 { 287 if (wrm == nullptr) return; 288 289 wrm->TerminateEventLoop(); 290 wrm->RunTermination(); 291 } 292 293 //============================================================================// 294 295 std::vector<G4String>& G4TaskRunManagerKernel::InitCommandStack() 296 { 297 return initCmdStack; 298 } 299 300 //============================================================================// 301 302 void G4TaskRunManagerKernel::SetUpDecayChannels() 303 { 304 G4ParticleTable::G4PTblDicIterator* pItr = G4ParticleTable::GetParticleTable()->GetIterator(); 305 pItr->reset(); 306 while ((*pItr)()) { 307 G4DecayTable* dt = pItr->value()->GetDecayTable(); 308 if (dt != nullptr) { 309 G4int nCh = dt->entries(); 310 for (G4int i = 0; i < nCh; i++) { 311 dt->GetDecayChannel(i)->GetDaughter(0); 312 } 313 } 314 } 315 } 316 317 //============================================================================// 318 319 void G4TaskRunManagerKernel::BroadcastAbortRun(G4bool softAbort) 320 { 321 G4ConsumeParameters(softAbort); 322 } 323 324 //============================================================================// 325