Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/run/src/G4MTRunManager.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 // G4MTRunManager implementation
 27 //
 28 // Original authors: X.Dong, A.Dotti - February 2013
 29 // --------------------------------------------------------------------
 30 
 31 #include "G4MTRunManager.hh"
 32 
 33 #include "G4AutoLock.hh"
 34 #include "G4CopyRandomState.hh"
 35 #include "G4MTRunManagerKernel.hh"
 36 #include "G4ProductionCutsTable.hh"
 37 #include "G4Run.hh"
 38 #include "G4ScoringManager.hh"
 39 #include "G4StateManager.hh"
 40 #include "G4Timer.hh"
 41 #include "G4TransportationManager.hh"
 42 #include "G4UImanager.hh"
 43 #include "G4UserRunAction.hh"
 44 #include "G4UserWorkerInitialization.hh"
 45 #include "G4UserWorkerThreadInitialization.hh"
 46 #include "G4VUserActionInitialization.hh"
 47 #include "G4WorkerRunManager.hh"
 48 #include "G4WorkerThread.hh"
 49 
 50 G4ScoringManager* G4MTRunManager::masterScM = nullptr;
 51 G4MTRunManager* G4MTRunManager::fMasterRM = nullptr;
 52 G4int G4MTRunManager::seedOncePerCommunication = 0;
 53 G4ThreadId G4MTRunManager::masterThreadId = G4ThisThread::get_id();
 54 
 55 // --------------------------------------------------------------------
 56 namespace
 57 {
 58 G4Mutex cmdHandlingMutex = G4MUTEX_INITIALIZER;
 59 G4Mutex scorerMergerMutex = G4MUTEX_INITIALIZER;
 60 G4Mutex runMergerMutex = G4MUTEX_INITIALIZER;
 61 G4Mutex setUpEventMutex = G4MUTEX_INITIALIZER;
 62 }  // namespace
 63 
 64 // --------------------------------------------------------------------
 65 G4MTRunManager* G4MTRunManager::GetMasterRunManager()
 66 {
 67   return fMasterRM;
 68 }
 69 
 70 // --------------------------------------------------------------------
 71 G4RunManagerKernel* G4MTRunManager::GetMasterRunManagerKernel()
 72 {
 73   return fMasterRM->kernel;
 74 }
 75 
 76 // --------------------------------------------------------------------
 77 G4MTRunManagerKernel* G4MTRunManager::GetMTMasterRunManagerKernel()
 78 {
 79   return fMasterRM->MTkernel;
 80 }
 81 
 82 // --------------------------------------------------------------------
 83 G4ScoringManager* G4MTRunManager::GetMasterScoringManager()
 84 {
 85   return masterScM;
 86 }
 87 
 88 // --------------------------------------------------------------------
 89 G4MTRunManager::masterWorlds_t& G4MTRunManager::GetMasterWorlds()
 90 {
 91   static masterWorlds_t masterWorlds;
 92   return masterWorlds;
 93 }
 94 
 95 // --------------------------------------------------------------------
 96 void G4MTRunManager::addWorld(G4int counter, G4VPhysicalVolume* w)
 97 {
 98   GetMasterWorlds().insert(std::make_pair(counter, w));
 99 }
100 
101 // --------------------------------------------------------------------
102 G4ThreadId G4MTRunManager::GetMasterThreadId()
103 {
104   return masterThreadId;
105 }
106 
107 // --------------------------------------------------------------------
108 G4int G4MTRunManager::SeedOncePerCommunication()
109 {
110   return seedOncePerCommunication;
111 }
112 
113 // --------------------------------------------------------------------
114 void G4MTRunManager::SetSeedOncePerCommunication(G4int val)
115 {
116   seedOncePerCommunication = val;
117 }
118 
119 // --------------------------------------------------------------------
120 G4MTRunManager::G4MTRunManager() : G4RunManager(masterRM)
121 {
122   if (fMasterRM != nullptr) {
123     G4Exception("G4MTRunManager::G4MTRunManager", "Run0110", FatalException,
124                 "Another instance of a G4MTRunManager already exists.");
125   }
126   fMasterRM = this;
127   masterThreadId = G4ThisThread::get_id();
128   MTkernel = static_cast<G4MTRunManagerKernel*>(kernel);
129 #ifndef G4MULTITHREADED
130   G4ExceptionDescription msg;
131   msg << "Geant4 code is compiled without multi-threading support"
132       << "(-DG4MULTITHREADED is set to off).\n";
133   msg << "G4MTRunManager can only be used in multi-threaded applications.";
134   G4Exception("G4MTRunManager::G4MTRunManager", "Run0111", FatalException, msg);
135 #endif
136 
137   G4int numberOfStaticAllocators = kernel->GetNumberOfStaticAllocators();
138   if (numberOfStaticAllocators > 0) {
139     G4ExceptionDescription msg1;
140     msg1 << "There are " << numberOfStaticAllocators << " static G4Allocator objects detected.\n"
141          << "In multi-threaded mode, all G4Allocator objects must be dynamically "
142             "instantiated.";
143     G4Exception("G4MTRunManager::G4MTRunManager", "Run1035", FatalException, msg1);
144   }
145   G4UImanager::GetUIpointer()->SetMasterUIManager(true);
146   masterScM = G4ScoringManager::GetScoringManagerIfExist();
147 
148   // Check if a default RandomNumberGenerator has been created by user,
149   // if not create default one
150   // Note this call forces creation of defaults if not already there
151   // G4Random::getTheEngine(); //User did not specify RNG, create defaults
152   // Now remember the master instance of the RNG Engine
153   masterRNGEngine = G4Random::getTheEngine();
154 
155   randDbl = new G4double[nSeedsPerEvent * nSeedsMax];
156 
157   char* env = std::getenv("G4FORCENUMBEROFTHREADS");
158   if (env != nullptr) {
159     G4String envS = env;
160     if (envS == "MAX" || envS == "max") {
161       forcedNwokers = G4Threading::G4GetNumberOfCores();
162     }
163     else {
164       std::istringstream is(env);
165       G4int val = -1;
166       is >> val;
167       if (val > 0) {
168         forcedNwokers = val;
169       }
170       else {
171         G4ExceptionDescription msg2;
172         msg2 << "Environment variable G4FORCENUMBEROFTHREADS has an invalid "
173                 "value <"
174              << envS << ">. It has to be an integer or a word \"max\".\n"
175              << "G4FORCENUMBEROFTHREADS is ignored.";
176         G4Exception("G4MTRunManager::G4MTRunManager", "Run1039", JustWarning, msg2);
177       }
178     }
179     if (forcedNwokers > 0) {
180       nworkers = forcedNwokers;
181       if (verboseLevel > 0) {
182         G4cout << "### Number of threads is forced to " << forcedNwokers
183                << " by Environment variable G4FORCENUMBEROFTHREADS." << G4endl;
184       }
185     }
186   }
187   G4UImanager::GetUIpointer()->SetAlias("RunMode eventParallel");
188 }
189 
190 // --------------------------------------------------------------------
191 G4MTRunManager::~G4MTRunManager()
192 {
193   // TODO: Currently does not work due to concurrent deletion of something
194   //      that is shared:
195   // G4ProcessTable::DeleteMessenger from ~G4RunManager
196   // G4cout<<"Destroy MTRunManager"<<G4endl;//ANDREA
197   TerminateWorkers();
198   delete[] randDbl;
199 }
200 
201 // --------------------------------------------------------------------
202 void G4MTRunManager::StoreRNGStatus(const G4String& fn)
203 {
204   std::ostringstream os;
205   os << randomNumberStatusDir << "G4Master_" << fn << ".rndm";
206   G4Random::saveEngineStatus(os.str().c_str());
207 }
208 
209 // --------------------------------------------------------------------
210 void G4MTRunManager::rndmSaveThisRun()
211 {
212   G4int runNumber = 0;
213   if (currentRun != nullptr) runNumber = currentRun->GetRunID();
214   if (!storeRandomNumberStatus) {
215     G4cerr << "Warning from G4RunManager::rndmSaveThisRun():"
216            << " Random number status was not stored prior to this run." << G4endl
217            << "/random/setSavingFlag command must be issued. "
218            << "Command ignored." << G4endl;
219     return;
220   }
221 
222   G4fs::path fileIn = randomNumberStatusDir + "G4Worker_currentRun.rndm";
223 
224   std::ostringstream os;
225   os << "run" << runNumber << ".rndm" << '\0';
226   G4fs::path fileOut = randomNumberStatusDir + os.str();
227 
228   if (G4CopyRandomState(fileIn, fileOut, "G4MTRunManager::rndmSaveThisRun()") && verboseLevel > 0)
229   {
230     G4cout << fileIn << " is copied to " << fileOut << G4endl;
231   } 
232 }
233 
234 // --------------------------------------------------------------------
235 void G4MTRunManager::rndmSaveThisEvent()
236 {
237   G4Exception("G4MTRunManager::rndmSaveThisEvent", "RUN_RNDM001", FatalException,
238               "This method shall not be invoked !!");
239 }
240 
241 // --------------------------------------------------------------------
242 void G4MTRunManager::SetNumberOfThreads(G4int n)
243 {
244   if (!threads.empty()) {
245     G4ExceptionDescription msg;
246     msg << "Number of threads cannot be changed at this moment \n"
247         << "(old threads are still alive). Method ignored.";
248     G4Exception("G4MTRunManager::SetNumberOfThreads(G4int)", "Run0112", JustWarning, msg);
249   }
250   else if (forcedNwokers > 0) {
251     G4ExceptionDescription msg;
252     msg << "Number of threads is forced to " << forcedNwokers
253         << " by G4FORCENUMBEROFTHREADS shell variable.\n"
254         << "Method ignored.";
255     G4Exception("G4MTRunManager::SetNumberOfThreads(G4int)", "Run0113", JustWarning, msg);
256   }
257   else {
258     nworkers = n;
259   }
260 }
261 
262 // --------------------------------------------------------------------
263 void G4MTRunManager::Initialize()
264 {
265   G4RunManager::Initialize();
266 
267   // make sure all worker threads are set up.
268   BeamOn(0);
269   SetRunIDCounter(0);
270 }
271 
272 // --------------------------------------------------------------------
273 void G4MTRunManager::ProcessOneEvent(G4int)
274 {
275   // Nothing to do
276 }
277 
278 // --------------------------------------------------------------------
279 void G4MTRunManager::TerminateOneEvent()
280 {
281   // Nothing to do
282 }
283 
284 // --------------------------------------------------------------------
285 void G4MTRunManager::PrepareCommandsStack()
286 {
287   G4AutoLock l(&cmdHandlingMutex);
288   uiCmdsForWorkers.clear();
289   std::vector<G4String>* cmdCopy = G4UImanager::GetUIpointer()->GetCommandStack();
290   for (const auto& it : *cmdCopy)
291     uiCmdsForWorkers.push_back(it);
292   cmdCopy->clear();
293   delete cmdCopy;
294 }
295 
296 // --------------------------------------------------------------------
297 std::vector<G4String> G4MTRunManager::GetCommandStack()
298 {
299   G4AutoLock l(&cmdHandlingMutex);
300   return uiCmdsForWorkers;
301 }
302 
303 // --------------------------------------------------------------------
304 void G4MTRunManager::CreateAndStartWorkers()
305 {
306   // Now loop on requested number of workers
307   // This will also start the workers
308   // Currently we do not allow to change the
309   // number of threads: threads area created once
310   if (threads.empty()) {
311     if (verboseLevel > 0) {
312       // for consistency with G4TaskRunManager
313       std::stringstream msg;
314       msg << "--> G4MTRunManager::CreateAndStartWorkers() --> "
315           << "Initializing workers...";
316 
317       std::stringstream ss;
318       ss.fill('=');
319       ss << std::setw(G4int(msg.str().length())) << "";
320       G4cout << "\n" << ss.str() << "\n" << msg.str() << "\n" << ss.str() << "\n" << G4endl;
321     }
322 
323     for (G4int nw = 0; nw < nworkers; ++nw) {
324       // Create a new worker and remember it
325       auto context = new G4WorkerThread;
326       context->SetNumberThreads(nworkers);
327       context->SetThreadId(nw);
328       G4Thread* thread = userWorkerThreadInitialization->CreateAndStartWorker(context);
329       threads.push_back(thread);
330     }
331   }
332   // Signal to threads they can start a new run
333   NewActionRequest(WorkerActionRequest::NEXTITERATION);
334 }
335 
336 // --------------------------------------------------------------------
337 void G4MTRunManager::InitializeEventLoop(G4int n_event, const char* macroFile, G4int n_select)
338 {
339   MTkernel->SetUpDecayChannels();
340   numberOfEventToBeProcessed = n_event;
341   numberOfEventProcessed = 0;
342 
343   if (!fakeRun) {
344     nSeedsUsed = 0;
345     nSeedsFilled = 0;
346 
347     if (verboseLevel > 0) {
348       timer->Start();
349     }
350 
351     n_select_msg = n_select;
352     if (macroFile != nullptr) {
353       if (n_select_msg < 0) n_select_msg = n_event;
354       msgText = "/control/execute ";
355       msgText += macroFile;
356       selectMacro = macroFile;
357     }
358     else {
359       n_select_msg = -1;
360       selectMacro = "";
361     }
362 
363     // initialize seeds
364     // If user did not implement InitializeSeeds,
365     // use default: nSeedsPerEvent seeds per event
366     if (eventModuloDef > 0) {
367       eventModulo = eventModuloDef;
368       if (eventModulo > numberOfEventToBeProcessed / nworkers) {
369         eventModulo = numberOfEventToBeProcessed / nworkers;
370         if (eventModulo < 1) eventModulo = 1;
371         G4ExceptionDescription msgd;
372         msgd << "Event modulo is reduced to " << eventModulo
373              << " to distribute events to all threads.";
374         G4Exception("G4MTRunManager::InitializeEventLoop()", "Run10035", JustWarning, msgd);
375       }
376     }
377     else {
378       eventModulo = G4int(std::sqrt(G4double(numberOfEventToBeProcessed / nworkers)));
379       if (eventModulo < 1) eventModulo = 1;
380     }
381     if (!InitializeSeeds(n_event) && n_event > 0) {
382       G4RNGHelper* helper = G4RNGHelper::GetInstance();
383       switch (seedOncePerCommunication) {
384         case 0:
385           nSeedsFilled = n_event;
386           break;
387         case 1:
388           nSeedsFilled = nworkers;
389           break;
390         case 2:
391           nSeedsFilled = n_event / eventModulo + 1;
392           break;
393         default:
394           G4ExceptionDescription msgd;
395           msgd << "Parameter value <" << seedOncePerCommunication
396                << "> of seedOncePerCommunication is invalid. It is reset to 0.";
397           G4Exception("G4MTRunManager::InitializeEventLoop()", "Run10036", JustWarning, msgd);
398           seedOncePerCommunication = 0;
399           nSeedsFilled = n_event;
400       }
401 
402       // Generates up to nSeedsMax seed pairs only.
403       if (nSeedsFilled > nSeedsMax) nSeedsFilled = nSeedsMax;
404       masterRNGEngine->flatArray(nSeedsPerEvent * nSeedsFilled, randDbl);
405       helper->Fill(randDbl, nSeedsFilled, n_event, nSeedsPerEvent);
406     }
407   }
408 
409   // Now initialize workers. Check if user defined a WorkerThreadInitialization
410   if (userWorkerThreadInitialization == nullptr) {
411     userWorkerThreadInitialization = new G4UserWorkerThreadInitialization();
412   }
413 
414   // Prepare UI commands for threads
415   PrepareCommandsStack();
416 
417   // Start worker threads
418   CreateAndStartWorkers();
419 
420   // We need a barrier here. Wait for workers to start event loop.
421   // This will return only when all workers have started processing events.
422   WaitForReadyWorkers();
423 }
424 
425 // --------------------------------------------------------------------
426 void G4MTRunManager::RefillSeeds()
427 {
428   G4RNGHelper* helper = G4RNGHelper::GetInstance();
429   G4int nFill = 0;
430   switch (seedOncePerCommunication) {
431     case 0:
432       nFill = numberOfEventToBeProcessed - nSeedsFilled;
433       break;
434     case 1:
435       nFill = nworkers - nSeedsFilled;
436       break;
437     case 2:
438     default:
439       nFill = (numberOfEventToBeProcessed - nSeedsFilled * eventModulo) / eventModulo + 1;
440   }
441   // Generates up to nSeedsMax seed pairs only.
442   if (nFill > nSeedsMax) nFill = nSeedsMax;
443   masterRNGEngine->flatArray(nSeedsPerEvent * nFill, randDbl);
444   helper->Refill(randDbl, nFill);
445   nSeedsFilled += nFill;
446 }
447 
448 // --------------------------------------------------------------------
449 void G4MTRunManager::RunTermination()
450 {
451   // Wait for all worker threads to have finished the run
452   // i.e. wait for them to return from RunTermination()
453   // This guarantee that userrunaction for workers has been called
454 
455   // Wait now for all threads to finish event-loop
456   WaitForEndEventLoopWorkers();
457   // Now call base-class methof
458   G4RunManager::TerminateEventLoop();
459   G4RunManager::RunTermination();
460 }
461 
462 // --------------------------------------------------------------------
463 void G4MTRunManager::ConstructScoringWorlds()
464 {
465   masterScM = G4ScoringManager::GetScoringManagerIfExist();
466   // Call base class stuff...
467   G4RunManager::ConstructScoringWorlds();
468 
469   GetMasterWorlds().clear();
470   auto nWorlds = (G4int)G4TransportationManager::GetTransportationManager()->GetNoWorlds();
471   auto itrW = G4TransportationManager::GetTransportationManager()->GetWorldsIterator();
472   for (G4int iWorld = 0; iWorld < nWorlds; ++iWorld) {
473     addWorld(iWorld, *itrW);
474     ++itrW;
475   }
476 }
477 
478 // --------------------------------------------------------------------
479 void G4MTRunManager::SetUserInitialization(G4UserWorkerInitialization* userInit)
480 {
481   userWorkerInitialization = userInit;
482 }
483 
484 // --------------------------------------------------------------------
485 void G4MTRunManager::SetUserInitialization(G4UserWorkerThreadInitialization* userInit)
486 {
487   userWorkerThreadInitialization = userInit;
488 }
489 
490 // --------------------------------------------------------------------
491 void G4MTRunManager::SetUserInitialization(G4VUserActionInitialization* userInit)
492 {
493   userActionInitialization = userInit;
494   userActionInitialization->BuildForMaster();
495 }
496 
497 // --------------------------------------------------------------------
498 void G4MTRunManager::SetUserInitialization(G4VUserPhysicsList* userPL)
499 {
500   G4RunManager::SetUserInitialization(userPL);
501   // Needed for MT, to be moved in kernel
502 }
503 
504 // --------------------------------------------------------------------
505 void G4MTRunManager::SetUserInitialization(G4VUserDetectorConstruction* userDC)
506 {
507   G4RunManager::SetUserInitialization(userDC);
508 }
509 
510 // --------------------------------------------------------------------
511 void G4MTRunManager::SetUserAction(G4UserRunAction* userAction)
512 {
513   G4RunManager::SetUserAction(userAction);
514   if (userAction != nullptr) userAction->SetMaster();
515 }
516 
517 // --------------------------------------------------------------------
518 void G4MTRunManager::SetUserAction(G4VUserPrimaryGeneratorAction* /*userAction*/)
519 {
520   G4Exception("G4MTRunManager::SetUserAction()", "Run0123", FatalException,
521               "For multi-threaded version, define G4VUserPrimaryGeneratorAction in "
522               "G4VUserActionInitialization.");
523 }
524 
525 // --------------------------------------------------------------------
526 void G4MTRunManager::SetUserAction(G4UserEventAction* /*userAction*/)
527 {
528   G4Exception("G4MTRunManager::SetUserAction()", "Run0124", FatalException,
529               "For multi-threaded version, define G4UserEventAction in "
530               "G4VUserActionInitialization.");
531 }
532 
533 // --------------------------------------------------------------------
534 void G4MTRunManager::SetUserAction(G4UserStackingAction* /*userAction*/)
535 {
536   G4Exception("G4MTRunManager::SetUserAction()", "Run0125", FatalException,
537               "For multi-threaded version, define G4UserStackingAction in "
538               "G4VUserActionInitialization.");
539 }
540 
541 // --------------------------------------------------------------------
542 void G4MTRunManager::SetUserAction(G4UserTrackingAction* /*userAction*/)
543 {
544   G4Exception("G4MTRunManager::SetUserAction()", "Run0126", FatalException,
545               "For multi-threaded version, define G4UserTrackingAction in "
546               "G4VUserActionInitialization.");
547 }
548 
549 // --------------------------------------------------------------------
550 void G4MTRunManager::SetUserAction(G4UserSteppingAction* /*userAction*/)
551 {
552   G4Exception("G4MTRunManager::SetUserAction()", "Run0127", FatalException,
553               "For multi-threaded version, define G4UserSteppingAction in "
554               "G4VUserActionInitialization.");
555 }
556 
557 // --------------------------------------------------------------------
558 void G4MTRunManager::MergeScores(const G4ScoringManager* localScoringManager)
559 {
560   G4AutoLock l(&scorerMergerMutex);
561   if (masterScM != nullptr && localScoringManager != nullptr) masterScM->Merge(localScoringManager);
562 }
563 
564 // --------------------------------------------------------------------
565 void G4MTRunManager::MergeRun(const G4Run* localRun)
566 {
567   G4AutoLock l(&runMergerMutex);
568   if (currentRun != nullptr && localRun != nullptr) currentRun->Merge(localRun);
569 }
570 
571 // --------------------------------------------------------------------
572 G4bool G4MTRunManager::SetUpAnEvent(G4Event* evt, G4long& s1, G4long& s2, G4long& s3,
573                                     G4bool reseedRequired)
574 {
575   G4AutoLock l(&setUpEventMutex);
576   if (numberOfEventProcessed < numberOfEventToBeProcessed) {
577     evt->SetEventID(numberOfEventProcessed);
578     if (reseedRequired) {
579       G4RNGHelper* helper = G4RNGHelper::GetInstance();
580       G4int idx_rndm = nSeedsPerEvent * nSeedsUsed;
581       s1 = helper->GetSeed(idx_rndm);
582       s2 = helper->GetSeed(idx_rndm + 1);
583       if (nSeedsPerEvent == 3) s3 = helper->GetSeed(idx_rndm + 2);
584       ++nSeedsUsed;
585       if (nSeedsUsed == nSeedsFilled) RefillSeeds();
586     }
587     ++numberOfEventProcessed;
588     return true;
589   }
590   return false;
591 }
592 
593 // --------------------------------------------------------------------
594 G4int G4MTRunManager::SetUpNEvents(G4Event* evt, G4SeedsQueue* seedsQueue, G4bool reseedRequired)
595 {
596   G4AutoLock l(&setUpEventMutex);
597   if (numberOfEventProcessed < numberOfEventToBeProcessed && !runAborted) {
598     G4int nev = eventModulo;
599     if (numberOfEventProcessed + nev > numberOfEventToBeProcessed) {
600       nev = numberOfEventToBeProcessed - numberOfEventProcessed;
601     }
602     evt->SetEventID(numberOfEventProcessed);
603     if (reseedRequired) {
604       G4RNGHelper* helper = G4RNGHelper::GetInstance();
605       G4int nevRnd = nev;
606       if (seedOncePerCommunication > 0) nevRnd = 1;
607       for (G4int i = 0; i < nevRnd; ++i) {
608         seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed));
609         seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed + 1));
610         if (nSeedsPerEvent == 3) seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed + 2));
611         ++nSeedsUsed;
612         if (nSeedsUsed == nSeedsFilled) RefillSeeds();
613       }
614     }
615     numberOfEventProcessed += nev;
616     return nev;
617   }
618   return 0;
619 }
620 
621 // --------------------------------------------------------------------
622 void G4MTRunManager::TerminateWorkers()
623 {
624   // Force workers to execute (if any) all UI commands left in the stack
625   RequestWorkersProcessCommandsStack();
626   // Ask workers to exit
627   NewActionRequest(WorkerActionRequest::ENDWORKER);
628   // Now join threads.
629 #ifdef G4MULTITHREADED  // protect here to prevent warning in compilation
630   while (!threads.empty()) {
631     G4Thread* t = *(threads.begin());
632     threads.pop_front();
633     userWorkerThreadInitialization->JoinWorker(t);
634     delete t;
635   }
636 #endif
637   threads.clear();
638 }
639 
640 // --------------------------------------------------------------------
641 void G4MTRunManager::AbortRun(G4bool softAbort)
642 {
643   // This method is valid only for GeomClosed or EventProc state
644   G4ApplicationState currentState = G4StateManager::GetStateManager()->GetCurrentState();
645   if (currentState == G4State_GeomClosed || currentState == G4State_EventProc) {
646     runAborted = true;
647     MTkernel->BroadcastAbortRun(softAbort);
648   }
649   else {
650     G4cerr << "Run is not in progress. AbortRun() ignored." << G4endl;
651   }
652 }
653 
654 // --------------------------------------------------------------------
655 void G4MTRunManager::AbortEvent()
656 {
657   // nothing to do in the master thread
658 }
659 
660 // --------------------------------------------------------------------
661 void G4MTRunManager::WaitForReadyWorkers()
662 {
663   beginOfEventLoopBarrier.Wait((G4int)GetNumberActiveThreads());
664   endOfEventLoopBarrier.ResetCounter();
665   beginOfEventLoopBarrier.ReleaseBarrier();
666 }
667 
668 // --------------------------------------------------------------------
669 void G4MTRunManager::ThisWorkerReady()
670 {
671   beginOfEventLoopBarrier.ThisWorkerReady();
672 }
673 
674 // --------------------------------------------------------------------
675 void G4MTRunManager::WaitForEndEventLoopWorkers()
676 {
677   endOfEventLoopBarrier.Wait((G4int)GetNumberActiveThreads());
678   beginOfEventLoopBarrier.ResetCounter();
679   endOfEventLoopBarrier.ReleaseBarrier();
680 }
681 
682 // --------------------------------------------------------------------
683 void G4MTRunManager::ThisWorkerEndEventLoop()
684 {
685   endOfEventLoopBarrier.ThisWorkerReady();
686 }
687 
688 // --------------------------------------------------------------------
689 void G4MTRunManager::NewActionRequest(G4MTRunManager::WorkerActionRequest newRequest)
690 {
691   nextActionRequestBarrier.Wait((G4int)GetNumberActiveThreads());
692   // nextActionRequest is a shared resource, but there is no
693   // data-race thanks to the barrier: all threads are waiting
694   nextActionRequest = newRequest;
695   nextActionRequestBarrier.ReleaseBarrier();
696 }
697 
698 // --------------------------------------------------------------------
699 G4MTRunManager::WorkerActionRequest G4MTRunManager::ThisWorkerWaitForNextAction()
700 {
701   nextActionRequestBarrier.ThisWorkerReady();
702   return nextActionRequest;
703 }
704 
705 // --------------------------------------------------------------------
706 void G4MTRunManager::RequestWorkersProcessCommandsStack()
707 {
708   PrepareCommandsStack();
709   NewActionRequest(WorkerActionRequest::PROCESSUI);
710   processUIBarrier.SetActiveThreads((G4int)GetNumberActiveThreads());
711   processUIBarrier.WaitForReadyWorkers();
712 }
713 
714 // --------------------------------------------------------------------
715 void G4MTRunManager::ThisWorkerProcessCommandsStackDone()
716 {
717   processUIBarrier.ThisWorkerReady();
718 }
719 
720 // --------------------------------------------------------------------
721 void G4MTRunManager::SetPinAffinity(G4int n)
722 {
723   if (n == 0) {
724     G4Exception("G4MTRunManager::SetPinAffinity", "Run0114", FatalException,
725                 "Pin affinity must be >0 or <0.");
726   }
727   pinAffinity = n;
728   return;
729 }
730