Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/run/src/G4TaskRunManager.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 //
 27 
 28 #include "G4TaskRunManager.hh"
 29 
 30 #include "G4AutoLock.hh"
 31 #include "G4EnvironmentUtils.hh"
 32 #include "G4ProductionCutsTable.hh"
 33 #include "G4Run.hh"
 34 #include "G4ScoringManager.hh"
 35 #include "G4StateManager.hh"
 36 #include "G4Task.hh"
 37 #include "G4TaskGroup.hh"
 38 #include "G4TaskManager.hh"
 39 #include "G4TaskRunManagerKernel.hh"
 40 #include "G4ThreadLocalSingleton.hh"
 41 #include "G4ThreadPool.hh"
 42 #include "G4Threading.hh"
 43 #include "G4Timer.hh"
 44 #include "G4TransportationManager.hh"
 45 #include "G4UImanager.hh"
 46 #include "G4UserRunAction.hh"
 47 #include "G4UserTaskInitialization.hh"
 48 #include "G4UserTaskQueue.hh"
 49 #include "G4UserTaskThreadInitialization.hh"
 50 #include "G4VUserActionInitialization.hh"
 51 #include "G4WorkerTaskRunManager.hh"
 52 #include "G4WorkerThread.hh"
 53 
 54 #include <cstdlib>
 55 #include <cstring>
 56 #include <iterator>
 57 
 58 //============================================================================//
 59 
 60 namespace
 61 {
 62 G4Mutex scorerMergerMutex;
 63 G4Mutex runMergerMutex;
 64 G4Mutex setUpEventMutex;
 65 }  // namespace
 66 
 67 //============================================================================//
 68 
 69 G4TaskRunManagerKernel* G4TaskRunManager::GetMTMasterRunManagerKernel()
 70 {
 71   return GetMasterRunManager()->MTkernel;
 72 }
 73 
 74 //============================================================================//
 75 
 76 G4TaskRunManager::G4TaskRunManager(G4VUserTaskQueue* task_queue, G4bool useTBB, G4int grainsize)
 77   : PTL::TaskRunManager(useTBB), eventGrainsize(grainsize)
 78 {
 79   if (task_queue != nullptr) taskQueue = task_queue;
 80 
 81   // override default of 2 from G4MTRunManager
 82   nworkers = G4Threading::G4GetNumberOfCores();
 83   fMasterRM = this;
 84   MTkernel = static_cast<G4TaskRunManagerKernel*>(kernel);
 85 
 86   G4int numberOfStaticAllocators = kernel->GetNumberOfStaticAllocators();
 87   if (numberOfStaticAllocators > 0) {
 88     G4ExceptionDescription msg1;
 89     msg1 << "There are " << numberOfStaticAllocators << " static G4Allocator objects detected.\n"
 90          << "In multi-threaded mode, all G4Allocator objects must "
 91          << "be dynamicly instantiated.";
 92     G4Exception("G4TaskRunManager::G4TaskRunManager", "Run1035", FatalException, msg1);
 93   }
 94 
 95   G4UImanager::GetUIpointer()->SetMasterUIManager(true);
 96   masterScM = G4ScoringManager::GetScoringManagerIfExist();
 97 
 98   // use default RandomNumberGenerator if created by user, or create default
 99   masterRNGEngine = G4Random::getTheEngine();
100 
101   numberOfEventToBeProcessed = 0;
102   randDbl = new G4double[nSeedsPerEvent * nSeedsMax];
103 
104   //------------------------------------------------------------------------//
105   //      handle threading
106   //------------------------------------------------------------------------//
107   auto _nthread_env = G4GetEnv<G4String>("G4FORCENUMBEROFTHREADS", "");
108   for (auto& itr : _nthread_env)
109     itr = (char)std::tolower(itr);
110 
111   if (_nthread_env == "max")
112     forcedNwokers = G4Threading::G4GetNumberOfCores();
113   else if (!_nthread_env.empty()) {
114     std::stringstream ss;
115     G4int _nthread_val = -1;
116     ss << _nthread_env;
117     ss >> _nthread_val;
118     if (_nthread_val > 0) forcedNwokers = _nthread_val;
119 
120     if (forcedNwokers > 0) nworkers = forcedNwokers;
121   }
122 
123   //------------------------------------------------------------------------//
124   //      option for forcing TBB
125   //------------------------------------------------------------------------//
126 #ifdef GEANT4_USE_TBB
127   G4int _useTBB = G4GetEnv<G4int>("G4FORCE_TBB", (G4int)useTBB);
128   if (_useTBB > 0) useTBB = true;
129 #else
130   if (useTBB) {
131     G4ExceptionDescription msg;
132     msg << "TBB was requested but Geant4 was not built with TBB support";
133     G4Exception("G4TaskRunManager::G4TaskRunManager(...)", "Run0131", JustWarning, msg);
134   }
135   useTBB = false;
136 #endif
137 }
138 
139 //============================================================================//
140 
141 G4TaskRunManager::G4TaskRunManager(G4bool useTBB) : G4TaskRunManager(nullptr, useTBB, 0) {}
142 
143 //============================================================================//
144 
145 G4TaskRunManager::~G4TaskRunManager()
146 {
147   // terminate all the workers
148   G4TaskRunManager::TerminateWorkers();
149 
150   // trigger all G4AutoDelete instances
151   G4ThreadLocalSingleton<void>::Clear();
152 
153   // delete the task-group
154   delete workTaskGroup;
155   workTaskGroup = nullptr;
156 
157   // destroy the thread-pool
158   if (threadPool != nullptr) threadPool->destroy_threadpool();
159 
160   PTL::TaskRunManager::Terminate();
161 }
162 
163 //============================================================================//
164 
165 G4ThreadId G4TaskRunManager::GetMasterThreadId()
166 {
167   return G4MTRunManager::GetMasterThreadId();
168 }
169 
170 //============================================================================//
171 
172 void G4TaskRunManager::StoreRNGStatus(const G4String& fn)
173 {
174   std::ostringstream os;
175   os << randomNumberStatusDir << "G4Master_" << fn << ".rndm";
176   G4Random::saveEngineStatus(os.str().c_str());
177 }
178 
179 //============================================================================//
180 
181 void G4TaskRunManager::SetNumberOfThreads(G4int n)
182 {
183   if (forcedNwokers > 0) {
184     if (verboseLevel > 0) {
185       G4ExceptionDescription msg;
186       msg << "\n### Number of threads is forced to " << forcedNwokers
187           << " by G4FORCENUMBEROFTHREADS environment variable. G4TaskRunManager::" << __FUNCTION__
188           << "(" << n << ") ignored ###";
189       G4Exception("G4TaskRunManager::SetNumberOfThreads(G4int)", "Run0132", JustWarning, msg);
190     }
191     nworkers = forcedNwokers;
192   }
193   else {
194     nworkers = n;
195     if (poolInitialized) {
196       if (verboseLevel > 0) {
197         std::stringstream ss;
198         ss << "\n### Thread-pool already initialized. Resizing  to " << nworkers << "threads ###";
199         G4cout << ss.str() << "\n" << G4endl;
200       }
201       GetThreadPool()->resize(n);
202     }
203   }
204 }
205 
206 //============================================================================//
207 
208 G4int G4TaskRunManager::GetNumberOfThreads() const
209 {
210   // If the ThreadPool isn't initialized, it will return 0 even if we've already
211   // set nworkers
212   return poolInitialized ? PTL::TaskRunManager::GetNumberOfThreads() : nworkers;
213 }
214 
215 //============================================================================//
216 
217 void G4TaskRunManager::Initialize()
218 {
219   G4bool firstTime = (threadPool == nullptr);
220   if (firstTime) InitializeThreadPool();
221 
222   G4RunManager::Initialize();
223 
224   // make sure all worker threads are set up.
225   G4RunManager::BeamOn(0);
226   if (firstTime) G4RunManager::SetRunIDCounter(0);
227   // G4UImanager::GetUIpointer()->SetIgnoreCmdNotFound(true);
228 }
229 
230 //============================================================================//
231 
232 void G4TaskRunManager::InitializeThreadPool()
233 {
234   if (poolInitialized && (threadPool != nullptr) && (workTaskGroup != nullptr)) {
235     G4Exception("G4TaskRunManager::InitializeThreadPool", "Run1040", JustWarning,
236                 "Threadpool already initialized. Ignoring...");
237     return;
238   }
239 
240   PTL::TaskRunManager::Initialize(nworkers);
241 
242   // create the joiners
243   if (workTaskGroup == nullptr) {
244     workTaskGroup = new RunTaskGroup(threadPool);
245   }
246 
247   if (verboseLevel > 0) {
248     std::stringstream ss;
249     ss.fill('=');
250     ss << std::setw(90) << "";
251     G4cout << "\n" << ss.str() << G4endl;
252 
253     if (threadPool->is_tbb_threadpool()) {
254       G4cout << "G4TaskRunManager :: Using TBB..." << G4endl;
255     }
256     else {
257       G4cout << "G4TaskRunManager :: Using G4ThreadPool..." << G4endl;
258     }
259 
260     G4cout << ss.str() << "\n" << G4endl;
261   }
262 }
263 
264 //============================================================================//
265 
266 void G4TaskRunManager::ProcessOneEvent(G4int)
267 {
268   // Nothing to do
269 }
270 
271 //============================================================================//
272 
273 void G4TaskRunManager::TerminateOneEvent()
274 {
275   // Nothing to do
276 }
277 
278 //============================================================================//
279 
280 void G4TaskRunManager::ComputeNumberOfTasks()
281 {
282   G4int grainSize = (eventGrainsize == 0) ? (G4int)threadPool->size() : eventGrainsize;
283   grainSize = G4GetEnv<G4int>("G4FORCE_GRAINSIZE", grainSize, "Forcing grainsize...");
284   if (grainSize == 0) grainSize = 1;
285 
286   G4int nEvtsPerTask =
287     (numberOfEventToBeProcessed > grainSize) ? (numberOfEventToBeProcessed / grainSize) : 1;
288 
289   if (eventModuloDef > 0) {
290     eventModulo = eventModuloDef;
291   }
292   else {
293     eventModulo = G4int(std::sqrt(G4double(numberOfEventToBeProcessed)));
294     if (eventModulo < 1) eventModulo = 1;
295   }
296   if (eventModulo > nEvtsPerTask) {
297     G4int oldMod = eventModulo;
298     eventModulo = nEvtsPerTask;
299 
300     G4ExceptionDescription msgd;
301     msgd << "Event modulo is reduced to " << eventModulo << " (was " << oldMod << ")"
302          << " to distribute events to all threads.";
303     G4Exception("G4TaskRunManager::InitializeEventLoop()", "Run10035", JustWarning, msgd);
304   }
305   nEvtsPerTask = eventModulo;
306 
307   if (fakeRun)
308     nEvtsPerTask = G4GetEnv<G4int>("G4FORCE_EVENTS_PER_TASK", nEvtsPerTask,
309                                    "Forcing number of events per task (overrides grainsize)...");
310   else
311     nEvtsPerTask = G4GetEnv<G4int>("G4FORCE_EVENTS_PER_TASK", nEvtsPerTask);
312 
313   if (nEvtsPerTask < 1) nEvtsPerTask = 1;
314 
315   numberOfTasks = numberOfEventToBeProcessed / nEvtsPerTask;
316   numberOfEventsPerTask = nEvtsPerTask;
317   eventModulo = numberOfEventsPerTask;
318 
319   if (fakeRun && verboseLevel > 2) {
320     std::stringstream msg;
321     msg << "--> G4TaskRunManager::ComputeNumberOfTasks() --> " << numberOfTasks << " tasks with "
322         << numberOfEventsPerTask << " events/task...";
323 
324     std::stringstream ss;
325     ss.fill('=');
326     ss << std::setw((G4int)msg.str().length()) << "";
327     G4cout << "\n" << ss.str() << "\n" << msg.str() << "\n" << ss.str() << "\n" << G4endl;
328   }
329 }
330 
331 //============================================================================//
332 
333 void G4TaskRunManager::CreateAndStartWorkers()
334 {
335   // Now loop on requested number of workers
336   // This will also start the workers
337   // Currently we do not allow to change the
338   // number of threads: threads area created once
339   // Instead of pthread based workers, create tbbTask
340   static bool initializeStarted = false;
341 
342   ComputeNumberOfTasks();
343 
344   if (fakeRun) {
345     if (initializeStarted) {
346       auto initCmdStack = GetCommandStack();
347       if (!initCmdStack.empty()) {
348         threadPool->execute_on_all_threads([cmds = std::move(initCmdStack)]() {
349           for (auto& itr : cmds)
350             G4UImanager::GetUIpointer()->ApplyCommand(itr);
351           G4WorkerTaskRunManager::GetWorkerRunManager()->DoWork();
352         });
353       }
354     }
355     else {
356       std::stringstream msg;
357       msg << "--> G4TaskRunManager::CreateAndStartWorkers() --> "
358           << "Initializing workers...";
359 
360       std::stringstream ss;
361       ss.fill('=');
362       ss << std::setw((G4int)msg.str().length()) << "";
363       G4cout << "\n" << ss.str() << "\n" << msg.str() << "\n" << ss.str() << "\n" << G4endl;
364 
365       G4TaskRunManagerKernel::InitCommandStack() = GetCommandStack();
366       threadPool->execute_on_all_threads([]() { G4TaskRunManagerKernel::InitializeWorker(); });
367     }
368     initializeStarted = true;
369   }
370   else {
371     auto initCmdStack = GetCommandStack();
372     if (!initCmdStack.empty()) {
373       threadPool->execute_on_all_threads([cmds = std::move(initCmdStack)]() {
374         for (auto& itr : cmds)
375           G4UImanager::GetUIpointer()->ApplyCommand(itr);
376       });
377     }
378 
379     // cleans up a previous run and events in case a thread
380     // does not execute any tasks
381     threadPool->execute_on_all_threads([]() { G4TaskRunManagerKernel::ExecuteWorkerInit(); });
382 
383     {
384       std::stringstream msg;
385       msg << "--> G4TaskRunManager::CreateAndStartWorkers() --> "
386           << "Creating " << numberOfTasks << " tasks with " << numberOfEventsPerTask
387           << " events/task...";
388 
389       std::stringstream ss;
390       ss.fill('=');
391       ss << std::setw((G4int)msg.str().length()) << "";
392       G4cout << "\n" << ss.str() << "\n" << msg.str() << "\n" << ss.str() << "\n" << G4endl;
393     }
394 
395     G4int remaining = numberOfEventToBeProcessed;
396     for (G4int nt = 0; nt < numberOfTasks + 1; ++nt) {
397       if (remaining > 0) AddEventTask(nt);
398       remaining -= numberOfEventsPerTask;
399     }
400     workTaskGroup->wait();
401   }
402 }
403 
404 //============================================================================//
405 
406 void G4TaskRunManager::AddEventTask(G4int nt)
407 {
408   if (verboseLevel > 3) G4cout << "Adding task " << nt << " to task-group..." << G4endl;
409   workTaskGroup->exec([this, nt]() {
410     if (verboseLevel > 3) G4cout << "Starting task " << nt << "..." << G4endl;
411     G4TaskRunManagerKernel::ExecuteWorkerTask();
412   });
413 }
414 
415 //============================================================================//
416 
417 void G4TaskRunManager::RefillSeeds()
418 {
419   G4RNGHelper* helper = G4RNGHelper::GetInstance();
420   G4int nFill = 0;
421   switch (SeedOncePerCommunication()) {
422     case 0:
423       nFill = numberOfEventToBeProcessed - nSeedsFilled;
424       break;
425     case 1:
426       nFill = numberOfTasks - nSeedsFilled;
427       break;
428     case 2:
429     default:
430       nFill = (numberOfEventToBeProcessed - nSeedsFilled * eventModulo) / eventModulo + 1;
431   }
432   // Generates up to nSeedsMax seed pairs only.
433   if (nFill > nSeedsMax) nFill = nSeedsMax;
434   masterRNGEngine->flatArray(nSeedsPerEvent * nFill, randDbl);
435   helper->Refill(randDbl, nFill);
436   nSeedsFilled += nFill;
437 }
438 
439 //============================================================================//
440 
441 void G4TaskRunManager::InitializeEventLoop(G4int n_event, const char* macroFile, G4int n_select)
442 {
443   MTkernel->SetUpDecayChannels();
444   numberOfEventToBeProcessed = n_event;
445   numberOfEventProcessed = 0;
446 
447   if (!fakeRun) {
448     nSeedsUsed = 0;
449     nSeedsFilled = 0;
450 
451     if (verboseLevel > 0) timer->Start();
452 
453     n_select_msg = n_select;
454     if (macroFile != nullptr) {
455       if (n_select_msg < 0) n_select_msg = n_event;
456 
457       msgText = "/control/execute ";
458       msgText += macroFile;
459       selectMacro = macroFile;
460     }
461     else {
462       n_select_msg = -1;
463       selectMacro = "";
464     }
465 
466     ComputeNumberOfTasks();
467 
468     // initialize seeds
469     // If user did not implement InitializeSeeds,
470     // use default: nSeedsPerEvent seeds per event
471 
472     if (n_event > 0) {
473       G4bool _overload = InitializeSeeds(n_event);
474       G4bool _functor = false;
475       if (!_overload) _functor = initSeedsCallback(n_event, nSeedsPerEvent, nSeedsFilled);
476       if (!_overload && !_functor) {
477         G4RNGHelper* helper = G4RNGHelper::GetInstance();
478         switch (SeedOncePerCommunication()) {
479           case 0:
480             nSeedsFilled = n_event;
481             break;
482           case 1:
483             nSeedsFilled = numberOfTasks;
484             break;
485           case 2:
486             nSeedsFilled = n_event / eventModulo + 1;
487             break;
488           default:
489             G4ExceptionDescription msgd;
490             msgd << "Parameter value <" << SeedOncePerCommunication()
491                  << "> of seedOncePerCommunication is invalid. It is reset "
492                     "to 0.";
493             G4Exception("G4TaskRunManager::InitializeEventLoop()", "Run10036", JustWarning, msgd);
494             SetSeedOncePerCommunication(0);
495             nSeedsFilled = n_event;
496         }
497 
498         // Generates up to nSeedsMax seed pairs only.
499         if (nSeedsFilled > nSeedsMax) nSeedsFilled = nSeedsMax;
500         masterRNGEngine->flatArray(nSeedsPerEvent * nSeedsFilled, randDbl);
501         helper->Fill(randDbl, nSeedsFilled, n_event, nSeedsPerEvent);
502       }
503     }
504   }
505 
506   // Now initialize workers. Check if user defined a WorkerThreadInitialization
507   if (userWorkerThreadInitialization == nullptr)
508     userWorkerThreadInitialization = new G4UserTaskThreadInitialization();
509 
510   // Prepare UI commands for threads
511   PrepareCommandsStack();
512 
513   // Start worker threads
514   CreateAndStartWorkers();
515 }
516 
517 //============================================================================//
518 
519 void G4TaskRunManager::RunTermination()
520 {
521   // Wait for all worker threads to have finished the run
522   // i.e. wait for them to return from RunTermination()
523   // This guarantee that userrunaction for workers has been called
524 
525   // Wait now for all threads to finish event-loop
526   WaitForEndEventLoopWorkers();
527   // Now call base-class methof
528   G4RunManager::TerminateEventLoop();
529   G4RunManager::RunTermination();
530 }
531 
532 //============================================================================//
533 
534 void G4TaskRunManager::ConstructScoringWorlds()
535 {
536   masterScM = G4ScoringManager::GetScoringManagerIfExist();
537   // Call base class stuff...
538   G4RunManager::ConstructScoringWorlds();
539 
540   GetMasterWorlds().clear();
541   auto nWorlds = (G4int)G4TransportationManager::GetTransportationManager()->GetNoWorlds();
542   auto itrW = G4TransportationManager::GetTransportationManager()->GetWorldsIterator();
543   for (G4int iWorld = 0; iWorld < nWorlds; ++iWorld) {
544     addWorld(iWorld, *itrW);
545     ++itrW;
546   }
547 }
548 
549 //============================================================================//
550 
551 void G4TaskRunManager::MergeScores(const G4ScoringManager* localScoringManager)
552 {
553   G4AutoLock l(&scorerMergerMutex);
554   if (masterScM != nullptr) masterScM->Merge(localScoringManager);
555 }
556 
557 //============================================================================//
558 
559 void G4TaskRunManager::MergeRun(const G4Run* localRun)
560 {
561   G4AutoLock l(&runMergerMutex);
562   if (currentRun != nullptr) currentRun->Merge(localRun);
563 }
564 
565 //============================================================================//
566 
567 G4bool G4TaskRunManager::SetUpAnEvent(G4Event* evt, G4long& s1, G4long& s2, G4long& s3,
568                                       G4bool reseedRequired)
569 {
570   G4AutoLock l(&setUpEventMutex);
571   if (numberOfEventProcessed < numberOfEventToBeProcessed) {
572     evt->SetEventID(numberOfEventProcessed);
573     if (reseedRequired) {
574       G4RNGHelper* helper = G4RNGHelper::GetInstance();
575       G4int idx_rndm = nSeedsPerEvent * nSeedsUsed;
576       s1 = helper->GetSeed(idx_rndm);
577       s2 = helper->GetSeed(idx_rndm + 1);
578       if (nSeedsPerEvent == 3) s3 = helper->GetSeed(idx_rndm + 2);
579       ++nSeedsUsed;
580       if (nSeedsUsed == nSeedsFilled) RefillSeeds();
581     }
582     numberOfEventProcessed++;
583     return true;
584   }
585   return false;
586 }
587 
588 //============================================================================//
589 
590 G4int G4TaskRunManager::SetUpNEvents(G4Event* evt, G4SeedsQueue* seedsQueue, G4bool reseedRequired)
591 {
592   G4AutoLock l(&setUpEventMutex);
593   if (numberOfEventProcessed < numberOfEventToBeProcessed && !runAborted) {
594     G4int nevt = numberOfEventsPerTask;
595     G4int nmod = eventModulo;
596     if (numberOfEventProcessed + nevt > numberOfEventToBeProcessed) {
597       nevt = numberOfEventToBeProcessed - numberOfEventProcessed;
598       nmod = numberOfEventToBeProcessed - numberOfEventProcessed;
599     }
600     evt->SetEventID(numberOfEventProcessed);
601 
602     if (reseedRequired) {
603       G4RNGHelper* helper = G4RNGHelper::GetInstance();
604       G4int nevRnd = nmod;
605       if (SeedOncePerCommunication() > 0) nevRnd = 1;
606       for (G4int i = 0; i < nevRnd; ++i) {
607         seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed));
608         seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed + 1));
609         if (nSeedsPerEvent == 3) seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed + 2));
610         nSeedsUsed++;
611         if (nSeedsUsed == nSeedsFilled) RefillSeeds();
612       }
613     }
614     numberOfEventProcessed += nevt;
615     return nevt;
616   }
617   return 0;
618 }
619 
620 //============================================================================//
621 
622 void G4TaskRunManager::TerminateWorkers()
623 {
624   // Force workers to execute (if any) all UI commands left in the stack
625   RequestWorkersProcessCommandsStack();
626 
627   if (workTaskGroup != nullptr) {
628     workTaskGroup->join();
629     if (!fakeRun)
630       threadPool->execute_on_all_threads([]() { G4TaskRunManagerKernel::TerminateWorker(); });
631   }
632 }
633 
634 //============================================================================//
635 
636 void G4TaskRunManager::AbortRun(G4bool softAbort)
637 {
638   // This method is valid only for GeomClosed or EventProc state
639   G4ApplicationState currentState = G4StateManager::GetStateManager()->GetCurrentState();
640   if (currentState == G4State_GeomClosed || currentState == G4State_EventProc) {
641     runAborted = true;
642     MTkernel->BroadcastAbortRun(softAbort);
643   }
644   else {
645     G4cerr << "Run is not in progress. AbortRun() ignored." << G4endl;
646   }
647 }
648 
649 //============================================================================//
650 
651 void G4TaskRunManager::AbortEvent()
652 {
653   // nothing to do in the master thread
654 }
655 
656 //============================================================================//
657 
658 void G4TaskRunManager::WaitForEndEventLoopWorkers()
659 {
660   if (workTaskGroup != nullptr) {
661     workTaskGroup->join();
662     if (!fakeRun)
663       threadPool->execute_on_all_threads(
664         []() { G4TaskRunManagerKernel::TerminateWorkerRunEventLoop(); });
665   }
666 }
667 
668 //============================================================================//
669 
670 void G4TaskRunManager::RequestWorkersProcessCommandsStack()
671 {
672   PrepareCommandsStack();
673 
674   auto process_commands_stack = []() {
675     G4MTRunManager* mrm = G4MTRunManager::GetMasterRunManager();
676     if (mrm != nullptr) {
677       auto cmds = mrm->GetCommandStack();
678       for (const auto& itr : cmds)
679         G4UImanager::GetUIpointer()->ApplyCommand(itr);  // TLS instance
680       mrm->ThisWorkerProcessCommandsStackDone();
681     }
682   };
683 
684   if (threadPool != nullptr) threadPool->execute_on_all_threads(process_commands_stack);
685 }
686 
687 //============================================================================//
688 
689 void G4TaskRunManager::ThisWorkerProcessCommandsStackDone() {}
690 
691 //============================================================================//
692