Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/run/src/G4WorkerRunManager.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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 // G4WorkerRunManager implementation
 27 //
 28 // Original authors: X.Dong, A.Dotti - 2013
 29 // --------------------------------------------------------------------
 30 
 31 #include "G4WorkerRunManager.hh"
 32 
 33 #include "G4AutoLock.hh"
 34 #include "G4CopyRandomState.hh"
 35 #include "G4MTRunManager.hh"
 36 #include "G4ParallelWorldProcess.hh"
 37 #include "G4ParallelWorldProcessStore.hh"
 38 #include "G4RNGHelper.hh"
 39 #include "G4Run.hh"
 40 #include "G4SDManager.hh"
 41 #include "G4ScoringManager.hh"
 42 #include "G4Timer.hh"
 43 #include "G4TransportationManager.hh"
 44 #include "G4UImanager.hh"
 45 #include "G4UserRunAction.hh"
 46 #include "G4UserWorkerInitialization.hh"
 47 #include "G4UserWorkerThreadInitialization.hh"
 48 #include "G4VScoreNtupleWriter.hh"
 49 #include "G4VScoringMesh.hh"
 50 #include "G4VUserActionInitialization.hh"
 51 #include "G4VUserDetectorConstruction.hh"
 52 #include "G4VUserPhysicsList.hh"
 53 #include "G4VUserPrimaryGeneratorAction.hh"
 54 #include "G4VVisManager.hh"
 55 #include "G4WorkerRunManagerKernel.hh"
 56 #include "G4WorkerThread.hh"
 57 
 58 #include "G4GeometryManager.hh"   // For parallel geometry initialisation
 59 
 60 #include <fstream>
 61 #include <sstream>
 62 
 63 // --------------------------------------------------------------------
 64 G4WorkerRunManager* G4WorkerRunManager::GetWorkerRunManager()
 65 {
 66   return static_cast<G4WorkerRunManager*>(G4RunManager::GetRunManager());
 67 }
 68 
 69 // --------------------------------------------------------------------
 70 G4WorkerRunManagerKernel* G4WorkerRunManager::GetWorkerRunManagerKernel()
 71 {
 72   return static_cast<G4WorkerRunManagerKernel*>(GetWorkerRunManager()->kernel);
 73 }
 74 
 75 // --------------------------------------------------------------------
 76 G4WorkerRunManager::G4WorkerRunManager() : G4RunManager(workerRM)
 77 {
 78   // This constructor should never be called in non-multithreaded mode
 79 
 80 #ifndef G4MULTITHREADED
 81   G4ExceptionDescription msg;
 82   msg << "Geant4 code is compiled without multi-threading support "
 83          "(-DG4MULTITHREADED "
 84          "is set to off).";
 85   msg << " This type of RunManager can only be used in mult-threaded "
 86          "applications.";
 87   G4Exception("G4WorkerRunManager::G4WorkerRunManager()", "Run0103", FatalException, msg);
 88 #endif
 89   // G4ParticleTable::GetParticleTable()->WorkerG4ParticleTable();
 90      // WorkerG4ParticleTable() would be performed twice,
 91      // as it is called already from G4ParticleTable::GetParticleTable()
 92      // which is called beforehand by other Geant4 classes
 93   G4ScoringManager* masterScM = G4MTRunManager::GetMasterScoringManager();
 94   if (masterScM != nullptr) G4ScoringManager::GetScoringManager();  // TLS instance for a worker
 95 
 96   // Properly initialise luxury level for Ranlux* engines...
 97   //
 98   if (dynamic_cast<const CLHEP::Ranlux64Engine*>(G4Random::getTheEngine()) != nullptr) {
 99     const auto theEngine = dynamic_cast<const CLHEP::Ranlux64Engine*>(G4Random::getTheEngine());
100     luxury = theEngine->getLuxury();
101   }
102   else if (dynamic_cast<const CLHEP::RanluxEngine*>(G4Random::getTheEngine()) != nullptr) {
103     const auto theEngine = dynamic_cast<const CLHEP::RanluxEngine*>(G4Random::getTheEngine());
104     luxury = theEngine->getLuxury();
105   }
106 
107   G4UImanager::GetUIpointer()->SetIgnoreCmdNotFound(true);
108 
109 #ifdef G4MULTITHREADED
110   G4VVisManager* pVVis = G4VVisManager::GetConcreteInstance();
111   if (pVVis != nullptr) {
112     pVVis->SetUpForAThread();
113     visIsSetUp = true;
114   }
115 #endif
116 }
117 
118 // --------------------------------------------------------------------
119 G4WorkerRunManager::~G4WorkerRunManager()
120 {
121   CleanUpPreviousEvents();
122   // Put these pointers to zero: owned by master thread
123   // If not to zero, the base class destructor will attempt to
124   // delete them
125   userDetector = nullptr;
126   userWorkerInitialization = nullptr;
127   userWorkerThreadInitialization = nullptr;
128   userActionInitialization = nullptr;
129   physicsList->TerminateWorker();
130   physicsList = nullptr;
131   if (verboseLevel > 1) G4cout << "Destroying WorkerRunManager (" << this << ")" << G4endl;
132 }
133 
134 // --------------------------------------------------------------------
135 void G4WorkerRunManager::InitializeGeometry()
136 {
137   if (userDetector == nullptr) {
138     G4Exception("G4RunManager::InitializeGeometry", "Run0033", FatalException,
139                 "G4VUserDetectorConstruction is not defined!");
140     return;
141   }
142 
143   if (fGeometryHasBeenDestroyed) {
144     G4TransportationManager::GetTransportationManager()->ClearParallelWorlds();
145   }
146 
147   // Step 0: Contribute to the voxelisation of the geometry
148   G4GeometryManager* geomManager = G4GeometryManager::GetInstance();
149   if( geomManager->IsParallelOptimisationConfigured() ) {
150     G4cout << "G4RunManager::InitializeGeometry calling GeometryManager's UndertakeOptimisation" 
151            << G4endl;  // TODO - suppress / delete this in final version
152     geomManager->UndertakeOptimisation();
153   }
154   //  A barrier must ensure that all that all threads have finished this work.
155   //  Currently we rely on the (later) barrier at the end of initialisation.
156   
157   // Step1: Get pointer to the physiWorld (note: needs to get the "super
158   // pointer, i.e. the one shared by all threads"
159   G4RunManagerKernel* masterKernel = G4MTRunManager::GetMasterRunManagerKernel();
160   G4VPhysicalVolume* worldVol = masterKernel->GetCurrentWorld();
161   // Step2:, Call a new "WorkerDefineWorldVolume( pointer from 2-, false);
162   kernel->WorkerDefineWorldVolume(worldVol, false);
163   kernel->SetNumberOfParallelWorld(masterKernel->GetNumberOfParallelWorld());
164   // Step3: Call user's ConstructSDandField()
165   userDetector->ConstructSDandField();
166   userDetector->ConstructParallelSD();
167   geometryInitialized = true;
168 }
169 
170 // --------------------------------------------------------------------
171 void G4WorkerRunManager::RunInitialization()
172 {
173 #ifdef G4MULTITHREADED
174   if (!visIsSetUp) {
175     G4VVisManager* pVVis = G4VVisManager::GetConcreteInstance();
176     if (pVVis != nullptr) {
177       pVVis->SetUpForAThread();
178       visIsSetUp = true;
179     }
180   }
181 #endif
182 
183   if (!(kernel->RunInitialization(fakeRun))) return;
184 
185   // Signal this thread can start event loop.
186   // Note this will return only when all threads reach this point
187   G4MTRunManager::GetMasterRunManager()->ThisWorkerReady();
188   if (fakeRun) return;
189 
190   const G4UserWorkerInitialization* uwi =
191     G4MTRunManager::GetMasterRunManager()->GetUserWorkerInitialization();
192   CleanUpPreviousEvents();
193   delete currentRun;
194   currentRun = nullptr;
195 
196   if (fGeometryHasBeenDestroyed) G4ParallelWorldProcessStore::GetInstance()->UpdateWorlds();
197   // Call a user hook: this is guaranteed all threads are "synchronized"
198   if (uwi != nullptr) uwi->WorkerRunStart();
199 
200   if (userRunAction != nullptr) currentRun = userRunAction->GenerateRun();
201   if (currentRun == nullptr) currentRun = new G4Run();
202 
203   currentRun->SetRunID(runIDCounter);
204   currentRun->SetNumberOfEventToBeProcessed(numberOfEventToBeProcessed);
205 
206   currentRun->SetDCtable(DCtable);
207   G4SDManager* fSDM = G4SDManager::GetSDMpointerIfExist();
208   if (fSDM != nullptr) {
209     currentRun->SetHCtable(fSDM->GetHCtable());
210   }
211 
212   if (G4VScoreNtupleWriter::Instance() != nullptr) {
213     auto hce = (fSDM != nullptr) ? fSDM->PrepareNewEvent() : nullptr;
214     isScoreNtupleWriter = G4VScoreNtupleWriter::Instance()->Book(hce);
215     delete hce;
216   }
217 
218   std::ostringstream oss;
219   G4Random::saveFullState(oss);
220   randomNumberStatusForThisRun = oss.str();
221   currentRun->SetRandomNumberStatus(randomNumberStatusForThisRun);
222 
223   for (G4int i_prev = 0; i_prev < n_perviousEventsToBeStored; ++i_prev) {
224     previousEvents->push_back(nullptr);
225   }
226 
227   if (printModulo > 0 || verboseLevel > 0) {
228     G4cout << "### Run " << currentRun->GetRunID() << " starts on worker thread "
229            << G4Threading::G4GetThreadId() << "." << G4endl;
230   }
231   if (userRunAction != nullptr) userRunAction->BeginOfRunAction(currentRun);
232 
233   if (isScoreNtupleWriter) {
234     G4VScoreNtupleWriter::Instance()->OpenFile();
235   }
236 
237   if (storeRandomNumberStatus) {
238     G4String fileN = "currentRun";
239     if (rngStatusEventsFlag) {
240       std::ostringstream os;
241       os << "run" << currentRun->GetRunID();
242       fileN = os.str();
243     }
244     StoreRNGStatus(fileN);
245   }
246 
247   runAborted = false;
248   numberOfEventProcessed = 0;
249 }
250 
251 // --------------------------------------------------------------------
252 void G4WorkerRunManager::DoEventLoop(G4int n_event, const char* macroFile, G4int n_select)
253 {
254   if (userPrimaryGeneratorAction == nullptr) {
255     G4Exception("G4RunManager::GenerateEvent()", "Run0032", FatalException,
256                 "G4VUserPrimaryGeneratorAction is not defined!");
257   }
258 
259   // This is the same as in the sequential case, just the for-loop indexes are
260   // different
261   InitializeEventLoop(n_event, macroFile, n_select);
262 
263   // Reset random number seeds queue
264   while (!seedsQueue.empty()) {
265     seedsQueue.pop();
266   }
267   // for each run, worker should receive at least one set of random number
268   // seeds.
269   runIsSeeded = false;
270 
271   // Event loop
272   eventLoopOnGoing = true;
273   ///////    G4int i_event = workerContext->GetThreadId();
274   G4int i_event = -1;
275   nevModulo = -1;
276   currEvID = -1;
277 
278   while (eventLoopOnGoing) {
279     ProcessOneEvent(i_event);
280     if (eventLoopOnGoing) {
281       TerminateOneEvent();
282       if (runAborted) {
283         eventLoopOnGoing = false;
284       }
285     }
286   }
287 
288   TerminateEventLoop();
289 }
290 
291 // --------------------------------------------------------------------
292 void G4WorkerRunManager::ProcessOneEvent(G4int i_event)
293 {
294   currentEvent = GenerateEvent(i_event);
295   if (eventLoopOnGoing) {
296     eventManager->ProcessOneEvent(currentEvent);
297     AnalyzeEvent(currentEvent);
298     UpdateScoring();
299     if (currentEvent->GetEventID() < n_select_msg)
300       G4UImanager::GetUIpointer()->ApplyCommand(msgText);
301   }
302 }
303 
304 // --------------------------------------------------------------------
305 G4Event* G4WorkerRunManager::GenerateEvent(G4int i_event)
306 {
307   auto anEvent = new G4Event(i_event);
308   G4long s1 = 0;
309   G4long s2 = 0;
310   G4long s3 = 0;
311   G4bool eventHasToBeSeeded = true;
312   if (G4MTRunManager::SeedOncePerCommunication() == 1 && runIsSeeded) {
313     eventHasToBeSeeded = false;
314   }
315 
316   if (i_event < 0) {
317     G4int nevM = G4MTRunManager::GetMasterRunManager()->GetEventModulo();
318     if (nevM == 1) {
319       eventLoopOnGoing = G4MTRunManager::GetMasterRunManager()->SetUpAnEvent(anEvent, s1, s2, s3,
320                                                                              eventHasToBeSeeded);
321       runIsSeeded = true;
322     }
323     else {
324       if (nevModulo <= 0) {
325         G4int nevToDo = G4MTRunManager::GetMasterRunManager()->SetUpNEvents(anEvent, &seedsQueue,
326                                                                             eventHasToBeSeeded);
327         if (nevToDo == 0) {
328           eventLoopOnGoing = false;
329         }
330         else {
331           currEvID = anEvent->GetEventID();
332           nevModulo = nevToDo - 1;
333         }
334       }
335       else {
336         if (G4MTRunManager::SeedOncePerCommunication() > 0) eventHasToBeSeeded = false;
337         anEvent->SetEventID(++currEvID);
338         --nevModulo;
339       }
340       if (eventLoopOnGoing && eventHasToBeSeeded) {
341         s1 = seedsQueue.front();
342         seedsQueue.pop();
343         s2 = seedsQueue.front();
344         seedsQueue.pop();
345       }
346     }
347 
348     if (!eventLoopOnGoing) {
349       delete anEvent;
350       return nullptr;
351     }
352   }
353   else if (eventHasToBeSeeded) {
354     // Need to reseed random number generator
355     G4RNGHelper* helper = G4RNGHelper::GetInstance();
356     s1 = helper->GetSeed(i_event * 2);
357     s2 = helper->GetSeed(i_event * 2 + 1);
358   }
359 
360   if (eventHasToBeSeeded) {
361     G4long seeds[3] = {s1, s2, 0};
362     G4Random::setTheSeeds(seeds, luxury);
363     runIsSeeded = true;
364   }
365 
366   // Read from file seed.
367   // Andrea Dotti 4 November 2015
368   // This is required for strong-reproducibility, in MT mode we have that each
369   // thread produces, for each event a status file, we want to do that.
370   // Search a random file with the format run{%d}evt{%d}.rndm
371 
372   // This is the filename base constructed from run and event
373   const auto filename = [&] {
374     std::ostringstream os;
375     os << "run" << currentRun->GetRunID() << "evt" << anEvent->GetEventID();
376     return os.str();
377   };
378 
379   G4bool RNGstatusReadFromFile = false;
380   if (readStatusFromFile) {
381     // Build full path of RNG status file for this event
382     std::ostringstream os;
383     os << filename() << ".rndm";
384     const G4String& randomStatusFile = os.str();
385     std::ifstream ifile(randomStatusFile.c_str());
386     if (ifile) {  // File valid and readable
387       RNGstatusReadFromFile = true;
388       G4Random::restoreEngineStatus(randomStatusFile.c_str());
389     }
390   }
391 
392   if (storeRandomNumberStatusToG4Event == 1 || storeRandomNumberStatusToG4Event == 3) {
393     std::ostringstream oss;
394     G4Random::saveFullState(oss);
395     randomNumberStatusForThisEvent = oss.str();
396     anEvent->SetRandomNumberStatus(randomNumberStatusForThisEvent);
397   }
398 
399   if (storeRandomNumberStatus && !RNGstatusReadFromFile)
400   {  // If reading from file, avoid to rewrite the same
401     G4String fileN = "currentEvent";
402     if (rngStatusEventsFlag) {
403       fileN = filename();
404     }
405     StoreRNGStatus(fileN);
406   }
407 
408   if (printModulo > 0 && anEvent->GetEventID() % printModulo == 0) {
409     G4cout << "--> Event " << anEvent->GetEventID() << " starts";
410     if (eventHasToBeSeeded) {
411       G4cout << " with initial seeds (" << s1 << "," << s2 << ")";
412     }
413     G4cout << "." << G4endl;
414   }
415   userPrimaryGeneratorAction->GeneratePrimaries(anEvent);
416   return anEvent;
417 }
418 
419 // --------------------------------------------------------------------
420 void G4WorkerRunManager::MergePartialResults(G4bool mergeEvents)
421 {
422   // Merge partial results into global run
423   G4MTRunManager* mtRM = G4MTRunManager::GetMasterRunManager();
424   G4ScoringManager* ScM = G4ScoringManager::GetScoringManagerIfExist();
425   if (ScM != nullptr) mtRM->MergeScores(ScM);
426 #ifdef G4VERBOSE
427   if(mergeEvents && verboseLevel>3) {
428     auto eventVector = currentRun->GetEventVector();
429     if(eventVector!=nullptr || !(eventVector->empty())) {
430       G4cout<<"G4WorkerRunManager::MergePartialResults : merging "
431             <<eventVector->size()<<" events."<<G4endl;
432     }
433   }
434 #endif
435   if(mergeEvents) mtRM->MergeRun(currentRun);
436 }
437 
438 // --------------------------------------------------------------------
439 void G4WorkerRunManager::RunTermination()
440 {
441   if (!fakeRun) {
442     MergePartialResults();
443 
444     // Call a user hook: note this is before the next barrier
445     // so threads execute this method asyncrhonouzly
446     //(TerminateRun allows for synch via G4RunAction::EndOfRun)
447     const G4UserWorkerInitialization* uwi =
448       G4MTRunManager::GetMasterRunManager()->GetUserWorkerInitialization();
449     if (uwi != nullptr) uwi->WorkerRunEnd();
450   }
451 
452   G4RunManager::RunTermination();
453   // Signal this thread has finished envent-loop.
454   // Note this will return only whan all threads reach this point
455   G4MTRunManager::GetMasterRunManager()->ThisWorkerEndEventLoop();
456 }
457 
458 // --------------------------------------------------------------------
459 void G4WorkerRunManager::TerminateEventLoop()
460 {
461   if (verboseLevel > 0 && !fakeRun) {
462     timer->Stop();
463     G4cout << "Thread-local run terminated." << G4endl;
464     G4cout << "Run Summary" << G4endl;
465     if (runAborted) {
466       G4cout << "  Run Aborted after " << numberOfEventProcessed << " events processed." << G4endl;
467     }
468     else {
469       G4cout << "  Number of events processed : " << numberOfEventProcessed << G4endl;
470     }
471     G4cout << "  " << *timer << G4endl;
472   }
473 }
474 
475 // --------------------------------------------------------------------
476 namespace
477 {
478 G4Mutex ConstructScoringWorldsMutex = G4MUTEX_INITIALIZER;
479 }
480 
481 // --------------------------------------------------------------------
482 void G4WorkerRunManager::ConstructScoringWorlds()
483 {
484   using MeshShape = G4VScoringMesh::MeshShape;
485 
486   // Return if unnecessary
487   G4ScoringManager* ScM = G4ScoringManager::GetScoringManagerIfExist();
488   if (ScM == nullptr) return;
489   auto nPar = (G4int)ScM->GetNumberOfMesh();
490   if (nPar < 1) return;
491 
492   // Update thread-local G4TransportationManager of all the world volumes
493   kernel->WorkerUpdateWorldVolume();
494 
495   G4ScoringManager* masterScM = G4MTRunManager::GetMasterScoringManager();
496 
497   auto particleIterator = G4ParticleTable::GetParticleTable()->GetIterator();
498 
499   for (G4int iw = 0; iw < nPar; ++iw) {
500     G4VScoringMesh* mesh = ScM->GetMesh(iw);
501     if (fGeometryHasBeenDestroyed) mesh->GeometryHasBeenDestroyed();
502     G4VPhysicalVolume* pWorld = nullptr;
503     if (mesh->GetShape() != MeshShape::realWorldLogVol) {
504       pWorld =
505         G4TransportationManager::GetTransportationManager()->IsWorldExisting(ScM->GetWorldName(iw));
506       if (pWorld == nullptr) {
507         G4ExceptionDescription ed;
508         ed << "Mesh name <" << ScM->GetWorldName(iw) << "> is not found in the master thread.";
509         G4Exception("G4WorkerRunManager::ConstructScoringWorlds()", "RUN79001", FatalException, ed);
510       }
511     }
512     if ((mesh->GetMeshElementLogical()) == nullptr) {
513       G4AutoLock l(&ConstructScoringWorldsMutex);
514       G4VScoringMesh* masterMesh = masterScM->GetMesh(iw);
515       mesh->SetMeshElementLogical(masterMesh->GetMeshElementLogical());
516       l.unlock();
517 
518       if (mesh->GetShape() != MeshShape::realWorldLogVol) {
519         G4ParallelWorldProcess* theParallelWorldProcess = mesh->GetParallelWorldProcess();
520         if (theParallelWorldProcess != nullptr) {
521           theParallelWorldProcess->SetParallelWorld(ScM->GetWorldName(iw));
522         }
523         else {
524           theParallelWorldProcess = new G4ParallelWorldProcess(ScM->GetWorldName(iw));
525           mesh->SetParallelWorldProcess(theParallelWorldProcess);
526           theParallelWorldProcess->SetParallelWorld(ScM->GetWorldName(iw));
527 
528           particleIterator->reset();
529           while ((*particleIterator)()) {
530             G4ParticleDefinition* particle = particleIterator->value();
531             G4ProcessManager* pmanager = particle->GetProcessManager();
532             if (pmanager != nullptr) {
533               pmanager->AddProcess(theParallelWorldProcess);
534               if (theParallelWorldProcess->IsAtRestRequired(particle)) {
535                 pmanager->SetProcessOrdering(theParallelWorldProcess, idxAtRest, 9900);
536               }
537               pmanager->SetProcessOrderingToSecond(theParallelWorldProcess, idxAlongStep);
538               pmanager->SetProcessOrdering(theParallelWorldProcess, idxPostStep, 9900);
539             }  // if(pmanager)
540           }  // while
541         }
542         theParallelWorldProcess->SetLayeredMaterialFlag(mesh->LayeredMassFlg());
543       }
544     }
545     mesh->WorkerConstruct(pWorld);
546   }
547 }
548 
549 // --------------------------------------------------------------------
550 void G4WorkerRunManager::SetUserInitialization(G4UserWorkerInitialization*)
551 {
552   G4Exception("G4RunManager::SetUserInitialization(G4UserWorkerInitialization*)", "Run0118",
553               FatalException, "This method should be used only with an instance of G4MTRunManager");
554 }
555 
556 // --------------------------------------------------------------------
557 void G4WorkerRunManager::SetUserInitialization(G4UserWorkerThreadInitialization*)
558 {
559   G4Exception("G4RunManager::SetUserInitialization(G4UserWorkerThreadInitialization*)", "Run0119",
560               FatalException, "This method should be used only with an instance of G4MTRunManager");
561 }
562 
563 // --------------------------------------------------------------------
564 void G4WorkerRunManager::SetUserInitialization(G4VUserActionInitialization*)
565 {
566   G4Exception("G4RunManager::SetUserInitialization(G4VUserActionInitialization*)", "Run0120",
567               FatalException, "This method should be used only with an instance of G4MTRunManager");
568 }
569 
570 // --------------------------------------------------------------------
571 void G4WorkerRunManager::SetUserInitialization(G4VUserDetectorConstruction*)
572 {
573   G4Exception("G4RunManager::SetUserInitialization(G4VUserDetectorConstruction*)", "Run0121",
574               FatalException, "This method should be used only with an instance of G4MTRunManager");
575 }
576 
577 // --------------------------------------------------------------------
578 void G4WorkerRunManager::SetUserInitialization(G4VUserPhysicsList* pl)
579 {
580   pl->InitializeWorker();
581   G4RunManager::SetUserInitialization(pl);
582 }
583 
584 // --------------------------------------------------------------------
585 void G4WorkerRunManager::SetUserAction(G4UserRunAction* userAction)
586 {
587   G4RunManager::SetUserAction(userAction);
588   if (userAction != nullptr) userAction->SetMaster(false);
589 }
590 
591 // --------------------------------------------------------------------
592 void G4WorkerRunManager::SetupDefaultRNGEngine()
593 {
594   const CLHEP::HepRandomEngine* mrnge =
595     G4MTRunManager::GetMasterRunManager()->getMasterRandomEngine();
596   const G4UserWorkerThreadInitialization* uwti =
597     G4MTRunManager::GetMasterRunManager()->GetUserWorkerThreadInitialization();
598   uwti->SetupRNGEngine(mrnge);
599 }
600 
601 // Forward calls (avoid GCC compilation warnings)
602 
603 // --------------------------------------------------------------------
604 void G4WorkerRunManager::SetUserAction(G4UserEventAction* ua)
605 {
606   G4RunManager::SetUserAction(ua);
607 }
608 
609 // --------------------------------------------------------------------
610 void G4WorkerRunManager::SetUserAction(G4VUserPrimaryGeneratorAction* ua)
611 {
612   G4RunManager::SetUserAction(ua);
613 }
614 
615 // --------------------------------------------------------------------
616 void G4WorkerRunManager::SetUserAction(G4UserStackingAction* ua)
617 {
618   G4RunManager::SetUserAction(ua);
619 }
620 
621 // --------------------------------------------------------------------
622 void G4WorkerRunManager::SetUserAction(G4UserTrackingAction* ua)
623 {
624   G4RunManager::SetUserAction(ua);
625 }
626 
627 // --------------------------------------------------------------------
628 void G4WorkerRunManager::SetUserAction(G4UserSteppingAction* ua)
629 {
630   G4RunManager::SetUserAction(ua);
631 }
632 
633 // --------------------------------------------------------------------
634 void G4WorkerRunManager::StoreRNGStatus(const G4String& fn)
635 {
636   std::ostringstream os;
637   os << randomNumberStatusDir << "G4Worker" << workerContext->GetThreadId() << "_" << fn << ".rndm";
638   G4Random::saveEngineStatus(os.str().c_str());
639 }
640 
641 // --------------------------------------------------------------------
642 void G4WorkerRunManager::rndmSaveThisRun()
643 {
644   G4int runNumber = 0;
645   if (currentRun != nullptr) runNumber = currentRun->GetRunID();
646   if (!storeRandomNumberStatus) {
647     G4cerr << "Warning from G4RunManager::rndmSaveThisRun():"
648            << " Random number status was not stored prior to this run." << G4endl
649            << "/random/setSavingFlag command must be issued. "
650            << "Command ignored." << G4endl;
651     return;
652   }
653 
654   std::ostringstream oos;
655   oos << "G4Worker" << workerContext->GetThreadId() << "_"
656       << "currentRun.rndm"
657       << "\0";
658   G4fs::path fileIn = randomNumberStatusDir + oos.str();
659 
660   std::ostringstream os;
661   os << "run" << runNumber << ".rndm" << '\0';
662   G4fs::path fileOut = randomNumberStatusDir + os.str();
663 
664   if (G4CopyRandomState(fileIn, fileOut, "G4WorkerRunManager::rndmSaveThisRun()")
665       && verboseLevel > 0)
666   {
667     G4cout << fileIn << " is copied to " << fileOut << G4endl;
668   }
669 }
670 
671 // --------------------------------------------------------------------
672 void G4WorkerRunManager::rndmSaveThisEvent()
673 {
674   if (currentEvent == nullptr) {
675     G4cerr << "Warning from G4RunManager::rndmSaveThisEvent():"
676            << " there is no currentEvent available." << G4endl << "Command ignored." << G4endl;
677     return;
678   }
679 
680   if (!storeRandomNumberStatus) {
681     G4cerr << "Warning from G4RunManager::rndmSaveThisEvent():"
682            << " Random number engine status is not available." << G4endl
683            << "/random/setSavingFlag command must be issued "
684            << "prior to the start of the run. Command ignored." << G4endl;
685     return;
686   }
687 
688   std::ostringstream oos;
689   oos << "G4Worker" << workerContext->GetThreadId() << "_"
690       << "currentEvent.rndm"
691       << "\0";
692   G4fs::path fileIn = randomNumberStatusDir + oos.str();
693 
694   std::ostringstream os;
695   os << "run" << currentRun->GetRunID() << "evt" << currentEvent->GetEventID() << ".rndm" << '\0';
696   G4fs::path fileOut = randomNumberStatusDir + os.str();
697 
698   if (G4CopyRandomState(fileIn, fileOut, "G4WorkerRunManager::rndmSaveThisEvent()")
699       && verboseLevel > 0)
700   {
701     G4cout << fileIn << " is copied to " << fileOut << G4endl;
702   }
703 }
704 
705 // --------------------------------------------------------------------
706 void G4WorkerRunManager::DoWork()
707 {
708   G4MTRunManager* mrm = G4MTRunManager::GetMasterRunManager();
709   G4MTRunManager::WorkerActionRequest nextAction = mrm->ThisWorkerWaitForNextAction();
710   while (nextAction != G4MTRunManager::WorkerActionRequest::ENDWORKER) {
711     if (nextAction == G4MTRunManager::WorkerActionRequest::NEXTITERATION)  // start the next
712                                                                            // run
713     {
714       // The following code deals with changing materials between runs
715       static G4ThreadLocal G4bool skipInitialization = true;
716       if (skipInitialization) {
717         // re-initialization is not necessary for the first run
718         skipInitialization = false;
719       }
720       else {
721         //        ReinitializeGeometry();
722         workerContext->UpdateGeometryAndPhysicsVectorFromMaster();
723       }
724 
725       // Execute UI commands stored in the master UI manager
726       std::vector<G4String> cmds = mrm->GetCommandStack();
727       G4UImanager* uimgr = G4UImanager::GetUIpointer();  // TLS instance
728       for (const auto& cmd : cmds) {
729         uimgr->ApplyCommand(cmd);
730       }
731       // Start this run
732       G4int numevents = mrm->GetNumberOfEventsToBeProcessed();
733       G4String macroFile = mrm->GetSelectMacro();
734       G4int numSelect = mrm->GetNumberOfSelectEvents();
735       if (macroFile.empty() || macroFile == " ") {
736         this->BeamOn(numevents);
737       }
738       else {
739         this->BeamOn(numevents, macroFile, numSelect);
740       }
741     }
742     else if (nextAction == G4MTRunManager::WorkerActionRequest::PROCESSUI) {
743       std::vector<G4String> cmds = mrm->GetCommandStack();
744       G4UImanager* uimgr = G4UImanager::GetUIpointer();  // TLS instance
745       for (const auto& cmd : cmds) {
746         uimgr->ApplyCommand(cmd);
747       }
748       mrm->ThisWorkerProcessCommandsStackDone();
749     }
750     else {
751       G4ExceptionDescription d;
752       d << "Cannot continue, this worker has been requested an unknown action: "
753         << static_cast<std::underlying_type<G4MTRunManager::WorkerActionRequest>::type>(nextAction);
754       G4Exception("G4WorkerRunManager::DoWork", "Run0104", FatalException, d);
755     }
756 
757     // Now wait for master thread to signal new action to be performed
758     nextAction = mrm->ThisWorkerWaitForNextAction();
759   }  // No more actions to perform
760 
761   return;
762 }
763