Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4MTRunManager.cc
Go to the documentation of this file.
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"
37#include "G4Run.hh"
38#include "G4ScoringManager.hh"
39#include "G4StateManager.hh"
40#include "G4TiMemory.hh"
41#include "G4Timer.hh"
43#include "G4UImanager.hh"
44#include "G4UserRunAction.hh"
48#include "G4WorkerRunManager.hh"
49#include "G4WorkerThread.hh"
50
55G4ThreadId G4MTRunManager::masterThreadId = G4ThisThread::get_id();
56
57// --------------------------------------------------------------------
58namespace
59{
60G4Mutex cmdHandlingMutex = G4MUTEX_INITIALIZER;
61G4Mutex scorerMergerMutex = G4MUTEX_INITIALIZER;
62G4Mutex runMergerMutex = G4MUTEX_INITIALIZER;
63G4Mutex setUpEventMutex = G4MUTEX_INITIALIZER;
64} // namespace
65
66// --------------------------------------------------------------------
71
72// --------------------------------------------------------------------
77
78// --------------------------------------------------------------------
83
84// --------------------------------------------------------------------
89
90// --------------------------------------------------------------------
95
96// --------------------------------------------------------------------
98{
99 masterWorlds.insert(std::make_pair(counter, w));
100}
101
102// --------------------------------------------------------------------
107
108// --------------------------------------------------------------------
113
114// --------------------------------------------------------------------
119
120// --------------------------------------------------------------------
122{
123 if (fMasterRM != nullptr) {
124 G4Exception("G4MTRunManager::G4MTRunManager", "Run0110", FatalException,
125 "Another instance of a G4MTRunManager already exists.");
126 }
127 fMasterRM = this;
128 masterThreadId = G4ThisThread::get_id();
129 MTkernel = static_cast<G4MTRunManagerKernel*>(kernel);
130#ifndef G4MULTITHREADED
132 msg << "Geant4 code is compiled without multi-threading support"
133 << "(-DG4MULTITHREADED is set to off).\n";
134 msg << "G4MTRunManager can only be used in multi-threaded applications.";
135 G4Exception("G4MTRunManager::G4MTRunManager", "Run0111", FatalException, msg);
136#endif
137
138 G4int numberOfStaticAllocators = kernel->GetNumberOfStaticAllocators();
139 if (numberOfStaticAllocators > 0) {
141 msg1 << "There are " << numberOfStaticAllocators << " static G4Allocator objects detected.\n"
142 << "In multi-threaded mode, all G4Allocator objects must be dynamically "
143 "instantiated.";
144 G4Exception("G4MTRunManager::G4MTRunManager", "Run1035", FatalException, msg1);
145 }
148
149 // Check if a default RandomNumberGenerator has been created by user,
150 // if not create default one
151 // Note this call forces creation of defaults if not already there
152 // G4Random::getTheEngine(); //User did not specify RNG, create defaults
153 // Now remember the master instance of the RNG Engine
154 masterRNGEngine = G4Random::getTheEngine();
155
157
158 char* env = std::getenv("G4FORCENUMBEROFTHREADS");
159 if (env != nullptr) {
160 G4String envS = env;
161 if (envS == "MAX" || envS == "max") {
163 }
164 else {
165 std::istringstream is(env);
166 G4int val = -1;
167 is >> val;
168 if (val > 0) {
169 forcedNwokers = val;
170 }
171 else {
173 msg2 << "Environment variable G4FORCENUMBEROFTHREADS has an invalid "
174 "value <"
175 << envS << ">. It has to be an integer or a word \"max\".\n"
176 << "G4FORCENUMBEROFTHREADS is ignored.";
177 G4Exception("G4MTRunManager::G4MTRunManager", "Run1039", JustWarning, msg2);
178 }
179 }
180 if (forcedNwokers > 0) {
182 if (verboseLevel > 0) {
183 G4cout << "### Number of threads is forced to " << forcedNwokers
184 << " by Environment variable G4FORCENUMBEROFTHREADS." << G4endl;
185 }
186 }
187 }
188}
189
190// --------------------------------------------------------------------
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
198 delete[] randDbl;
199}
200
201// --------------------------------------------------------------------
203{
204 std::ostringstream os;
205 os << randomNumberStatusDir << "G4Master_" << fn << ".rndm";
206 G4Random::saveEngineStatus(os.str().c_str());
207}
208
209// --------------------------------------------------------------------
211{
212 G4int runNumber = 0;
213 if (currentRun != nullptr) runNumber = currentRun->GetRunID();
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// --------------------------------------------------------------------
236{
237 G4Exception("G4MTRunManager::rndmSaveThisEvent", "RUN_RNDM001", FatalException,
238 "This method shall not be invoked !!");
239}
240
241// --------------------------------------------------------------------
243{
244 if (!threads.empty()) {
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) {
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// --------------------------------------------------------------------
264{
266
267 // make sure all worker threads are set up.
268 BeamOn(0);
270}
271
272// --------------------------------------------------------------------
274{
275 // Nothing to do
276}
277
278// --------------------------------------------------------------------
280{
281 // Nothing to do
282}
283
284// --------------------------------------------------------------------
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// --------------------------------------------------------------------
297std::vector<G4String> G4MTRunManager::GetCommandStack()
298{
299 G4AutoLock l(&cmdHandlingMutex);
300 return uiCmdsForWorkers;
301}
302
303// --------------------------------------------------------------------
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);
329 threads.push_back(thread);
330 }
331 }
332 // Signal to threads they can start a new run
334}
335
336// --------------------------------------------------------------------
337void G4MTRunManager::InitializeEventLoop(G4int n_event, const char* macroFile, G4int n_select)
338{
339 MTkernel->SetUpDecayChannels();
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) {
370 if (eventModulo < 1) eventModulo = 1;
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 {
379 if (eventModulo < 1) eventModulo = 1;
380 }
381 if (!InitializeSeeds(n_event) && n_event > 0) {
383 switch (seedOncePerCommunication) {
384 case 0:
385 nSeedsFilled = n_event;
386 break;
387 case 1:
389 break;
390 case 2:
391 nSeedsFilled = n_event / eventModulo + 1;
392 break;
393 default:
395 msgd << "Parameter value <" << seedOncePerCommunication
396 << "> of seedOncePerCommunication is invalid. It is reset to 0.";
397 G4Exception("G4MTRunManager::InitializeEventLoop()", "Run10036", JustWarning, msgd);
399 nSeedsFilled = n_event;
400 }
401
402 // Generates up to nSeedsMax seed pairs only.
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) {
412 }
413
414 // Prepare UI commands for threads
416
417 // Start worker threads
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.
423}
424
425// --------------------------------------------------------------------
427{
429 G4int nFill = 0;
430 switch (seedOncePerCommunication) {
431 case 0:
433 break;
434 case 1:
435 nFill = nworkers - nSeedsFilled;
436 break;
437 case 2:
438 default:
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// --------------------------------------------------------------------
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
457 // Now call base-class methof
460}
461
462// --------------------------------------------------------------------
464{
466 // Call base class stuff...
468
469 masterWorlds.clear();
472 for (G4int iWorld = 0; iWorld < nWorlds; ++iWorld) {
473 addWorld(iWorld, *itrW);
474 ++itrW;
475 }
476}
477
478// --------------------------------------------------------------------
483
484// --------------------------------------------------------------------
489
490// --------------------------------------------------------------------
496
497// --------------------------------------------------------------------
499{
501 // Needed for MT, to be moved in kernel
502}
503
504// --------------------------------------------------------------------
509
510// --------------------------------------------------------------------
512{
513 G4RunManager::SetUserAction(userAction);
514 if (userAction != nullptr) userAction->SetMaster();
515}
516
517// --------------------------------------------------------------------
519{
520 G4Exception("G4MTRunManager::SetUserAction()", "Run0123", FatalException,
521 "For multi-threaded version, define G4VUserPrimaryGeneratorAction in "
522 "G4VUserActionInitialization.");
523}
524
525// --------------------------------------------------------------------
527{
528 G4Exception("G4MTRunManager::SetUserAction()", "Run0124", FatalException,
529 "For multi-threaded version, define G4UserEventAction in "
530 "G4VUserActionInitialization.");
531}
532
533// --------------------------------------------------------------------
535{
536 G4Exception("G4MTRunManager::SetUserAction()", "Run0125", FatalException,
537 "For multi-threaded version, define G4UserStackingAction in "
538 "G4VUserActionInitialization.");
539}
540
541// --------------------------------------------------------------------
543{
544 G4Exception("G4MTRunManager::SetUserAction()", "Run0126", FatalException,
545 "For multi-threaded version, define G4UserTrackingAction in "
546 "G4VUserActionInitialization.");
547}
548
549// --------------------------------------------------------------------
551{
552 G4Exception("G4MTRunManager::SetUserAction()", "Run0127", FatalException,
553 "For multi-threaded version, define G4UserSteppingAction in "
554 "G4VUserActionInitialization.");
555}
556
557// --------------------------------------------------------------------
558void G4MTRunManager::MergeScores(const G4ScoringManager* localScoringManager)
559{
560 G4AutoLock l(&scorerMergerMutex);
561 if (masterScM != nullptr && localScoringManager != nullptr) masterScM->Merge(localScoringManager);
562}
563
564// --------------------------------------------------------------------
565void G4MTRunManager::MergeRun(const G4Run* localRun)
566{
567 G4AutoLock l(&runMergerMutex);
568 if (currentRun != nullptr && localRun != nullptr) currentRun->Merge(localRun);
569}
570
571// --------------------------------------------------------------------
573 G4bool reseedRequired)
574{
575 G4AutoLock l(&setUpEventMutex);
578 if (reseedRequired) {
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;
586 }
588 return true;
589 }
590 return false;
591}
592
593// --------------------------------------------------------------------
595{
596 G4AutoLock l(&setUpEventMutex);
598 G4int nev = eventModulo;
601 }
603 if (reseedRequired) {
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;
613 }
614 }
616 return nev;
617 }
618 return 0;
619}
620
621// --------------------------------------------------------------------
623{
624 // Force workers to execute (if any) all UI commands left in the stack
626 // Ask workers to exit
628 // finalize profiler before shutting down the threads
630 // Now join threads.
631#ifdef G4MULTITHREADED // protect here to prevent warning in compilation
632 while (!threads.empty()) {
633 G4Thread* t = *(threads.begin());
634 threads.pop_front();
636 delete t;
637 }
638#endif
639 threads.clear();
640}
641
642// --------------------------------------------------------------------
644{
645 // This method is valid only for GeomClosed or EventProc state
647 if (currentState == G4State_GeomClosed || currentState == G4State_EventProc) {
648 runAborted = true;
649 MTkernel->BroadcastAbortRun(softAbort);
650 }
651 else {
652 G4cerr << "Run is not in progress. AbortRun() ignored." << G4endl;
653 }
654}
655
656// --------------------------------------------------------------------
658{
659 // nothing to do in the master thread
660}
661
662// --------------------------------------------------------------------
669
670// --------------------------------------------------------------------
675
676// --------------------------------------------------------------------
683
684// --------------------------------------------------------------------
689
690// --------------------------------------------------------------------
692{
694 // nextActionRequest is a shared resource, but there is no
695 // data-race thanks to the barrier: all threads are waiting
696 nextActionRequest = newRequest;
698}
699
700// --------------------------------------------------------------------
706
707// --------------------------------------------------------------------
715
716// --------------------------------------------------------------------
721
722// --------------------------------------------------------------------
724{
725 if (n == 0) {
726 G4Exception("G4MTRunManager::SetPinAffinity", "Run0114", FatalException,
727 "Pin affinity must be >0 or <0.");
728 }
729 pinAffinity = n;
730 return;
731}
G4ApplicationState
@ G4State_EventProc
@ G4State_GeomClosed
Helper function for copying random state files in G4run.
G4bool G4CopyRandomState(const G4fs::path &source, const G4fs::path &dest, const G4String &callsite)
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
std::queue< G4long > G4SeedsQueue
#define G4MUTEX_INITIALIZER
G4Thread::id G4ThreadId
std::mutex G4Mutex
double G4double
Definition G4Types.hh:83
long G4long
Definition G4Types.hh:87
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
virtual void flatArray(const int size, double *vect)=0
void SetEventID(G4int i)
Definition G4Event.hh:85
void ThisWorkerReady()
void ResetCounter()
virtual void WaitForReadyWorkers()
void ReleaseBarrier()
void SetActiveThreads(unsigned int val)
void BroadcastAbortRun(G4bool softAbort)
static G4int SeedOncePerCommunication()
virtual WorkerActionRequest ThisWorkerWaitForNextAction()
static void SetSeedOncePerCommunication(G4int val)
void AbortEvent() override
G4int numberOfEventToBeProcessed
void TerminateOneEvent() override
void SetUserAction(G4UserRunAction *userAction) override
void RunTermination() override
void SetNumberOfThreads(G4int n) override
virtual G4bool InitializeSeeds(G4int)
virtual void WaitForReadyWorkers()
G4MTBarrier beginOfEventLoopBarrier
virtual void CreateAndStartWorkers()
virtual void ThisWorkerProcessCommandsStackDone()
~G4MTRunManager() override
virtual G4int SetUpNEvents(G4Event *, G4SeedsQueue *seedsQueue, G4bool reseedRequired=true)
static void addWorld(G4int counter, G4VPhysicalVolume *w)
virtual void PrepareCommandsStack()
static G4ScoringManager * GetMasterScoringManager()
static G4MTRUN_DLL G4ScoringManager * masterScM
static G4MTRUN_DLL G4MTRunManager * fMasterRM
virtual void ThisWorkerReady()
void Initialize() override
static G4MTRunManagerKernel * GetMTMasterRunManagerKernel()
static G4int seedOncePerCommunication
void ProcessOneEvent(G4int i_event) override
static G4MTRUN_DLL masterWorlds_t masterWorlds
virtual size_t GetNumberActiveThreads() const
static G4MTRunManager * GetMasterRunManager()
virtual void WaitForEndEventLoopWorkers()
void ConstructScoringWorlds() override
WorkerActionRequest nextActionRequest
void SetUserInitialization(G4VUserPhysicsList *userPL) override
std::map< G4int, G4VPhysicalVolume * > masterWorlds_t
virtual void RefillSeeds()
static G4ThreadId masterThreadId
G4MTBarrier processUIBarrier
static G4ThreadId GetMasterThreadId()
void MergeRun(const G4Run *localRun)
G4MTBarrier endOfEventLoopBarrier
G4MTBarrier nextActionRequestBarrier
void AbortRun(G4bool softAbort=false) override
virtual void TerminateWorkers()
static masterWorlds_t & GetMasterWorlds()
virtual void RequestWorkersProcessCommandsStack()
void InitializeEventLoop(G4int n_event, const char *macroFile=nullptr, G4int n_select=-1) override
static G4RunManagerKernel * GetMasterRunManagerKernel()
void MergeScores(const G4ScoringManager *localScoringManager)
void rndmSaveThisRun() override
virtual void NewActionRequest(WorkerActionRequest newRequest)
void SetPinAffinity(G4int n=1)
void rndmSaveThisEvent() override
void StoreRNGStatus(const G4String &filenamePrefix) override
std::vector< G4String > GetCommandStack()
virtual G4bool SetUpAnEvent(G4Event *, G4long &s1, G4long &s2, G4long &s3, G4bool reseedRequired=true)
virtual void ThisWorkerEndEventLoop()
static void Finalize()
G4int GetNumberOfStaticAllocators() const
G4UserWorkerInitialization * userWorkerInitialization
virtual void Initialize()
G4Timer * timer
void SetRunIDCounter(G4int i)
G4UserWorkerThreadInitialization * userWorkerThreadInitialization
G4int numberOfEventProcessed
G4RunManagerKernel * kernel
G4Run * currentRun
G4String msgText
virtual void BeamOn(G4int n_event, const char *macroFile=nullptr, G4int n_select=-1)
G4String selectMacro
virtual void RunTermination()
G4VUserActionInitialization * userActionInitialization
G4String randomNumberStatusDir
virtual void TerminateEventLoop()
virtual void SetUserAction(G4UserRunAction *userAction)
virtual void SetUserInitialization(G4VUserDetectorConstruction *userInit)
G4bool storeRandomNumberStatus
virtual void ConstructScoringWorlds()
Definition G4Run.hh:49
G4int GetRunID() const
Definition G4Run.hh:86
virtual void Merge(const G4Run *)
Definition G4Run.cc:65
void Merge(const G4ScoringManager *scMan)
static G4ScoringManager * GetScoringManagerIfExist()
const G4ApplicationState & GetCurrentState() const
static G4StateManager * GetStateManager()
static G4TemplateRNGHelper< T > * GetInstance()
virtual const T GetSeed(const G4int &sdId)
void Fill(G4double *dbl, G4int nev, G4int nev_tot, G4int nrpe)
void Refill(G4double *dbl, G4int nev)
void Start()
static G4TransportationManager * GetTransportationManager()
std::vector< G4VPhysicalVolume * >::iterator GetWorldsIterator()
std::size_t GetNoWorlds() const
std::vector< G4String > * GetCommandStack()
void SetMasterUIManager(G4bool val)
static G4UImanager * GetUIpointer()
virtual void SetMaster(G4bool val=true)
virtual G4Thread * CreateAndStartWorker(G4WorkerThread *workerThreadContext)
void SetNumberThreads(G4int numnberThreads)
G4int G4GetNumberOfCores()