ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4WorkerRunManager.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4WorkerRunManager.cc
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 "G4WorkerRunManager.hh"
30 #include "G4UImanager.hh"
32 #include "G4MTRunManager.hh"
33 #include "G4ScoringManager.hh"
36 #include "G4WorkerThread.hh"
37 #include "G4VUserPhysicsList.hh"
41 #include "G4UserRunAction.hh"
42 #include "G4RNGHelper.hh"
43 #include "G4Run.hh"
45 #include "G4VVisManager.hh"
46 #include "G4SDManager.hh"
47 #include "G4VScoreNtupleWriter.hh"
48 #include "G4VScoringMesh.hh"
49 #include "G4Timer.hh"
50 #include "G4TiMemory.hh"
51 #include <sstream>
52 #include <fstream>
53 
55 { return static_cast<G4WorkerRunManager*>(G4RunManager::GetRunManager()); }
56 
58 { return static_cast<G4WorkerRunManagerKernel*>(GetWorkerRunManager()->kernel); }
59 
61 {
62  // This constructor should never be called in non-multithreaded mode
63 
64 #ifndef G4MULTITHREADED
66  msg<<"Geant4 code is compiled without multi-threading support (-DG4MULTITHREADED is set to off).";
67  msg<<" This type of RunManager can only be used in mult-threaded applications.";
68  G4Exception("G4WorkerRunManager::G4WorkerRunManager()","Run0103",FatalException,msg);
69 #endif
72  if(masterScM) G4ScoringManager::GetScoringManager(); //TLS instance for a worker
73 
74  eventLoopOnGoing = false;
75  runIsSeeded = false;
76  nevModulo = -1;
77  currEvID = -1;
78  workerContext = 0;
79  readStatusFromFile = false;
80 
81  // Properly initialise luxury level for Ranlux* engines...
82  //
83  if ( dynamic_cast<const CLHEP::Ranlux64Engine*>(G4Random::getTheEngine()) )
84  {
85  const CLHEP::Ranlux64Engine* theEngine = dynamic_cast<const CLHEP::Ranlux64Engine*>(G4Random::getTheEngine());
86  luxury = theEngine->getLuxury();
87  }
88  else if ( dynamic_cast<const CLHEP::RanluxEngine*>(G4Random::getTheEngine()) )
89  {
90  const CLHEP::RanluxEngine* theEngine = dynamic_cast<const CLHEP::RanluxEngine*>(G4Random::getTheEngine());
91  luxury = theEngine->getLuxury();
92  }
93  else
94  {
95  luxury = -1;
96  }
97 
99 
100 #ifdef G4MULTITHREADED
102  if(pVVis)
103  {
104  pVVis->SetUpForAThread();
105  visIsSetUp = true;
106  }
107  else
108  { visIsSetUp = false; }
109 #endif
110 }
111 
112 #include "G4MTRunManager.hh"
113 
115 {
116  // Delete thread-local data process manager objects
118 // physicsList->RemoveProcessManager();
119 
120  //Put these pointers to zero: owned by master thread
121  //If not to zero, the base class destructor will attempt to
122  //delete them
123  userDetector = 0;
127  physicsList = 0;
128  if(verboseLevel>0) G4cout<<"Destroying WorkerRunManager ("<<this<<")"<<G4endl;
129 }
130 
131 
133  if(!userDetector)
134  {
135  G4Exception("G4RunManager::InitializeGeometry", "Run0033",
136  FatalException, "G4VUserDetectorConstruction is not defined!");
137  return;
138  }
141 
142  //Step1: Get pointer to the physiWorld (note: needs to get the "super pointer, i.e. the one shared by all threads"
144  G4VPhysicalVolume* worldVol = masterKernel->GetCurrentWorld();
145  //Step2:, Call a new "WorkerDefineWorldVolume( pointer from 2-, false);
146  kernel->WorkerDefineWorldVolume(worldVol,false);
148  //Step3: Call user's ConstructSDandField()
151  geometryInitialized = true;
152 }
153 
155 
157 {
159 #ifdef G4MULTITHREADED
160  if(!visIsSetUp)
161  {
163  if(pVVis)
164  {
165  pVVis->SetUpForAThread();
166  visIsSetUp = true;
167  }
168  }
169 #endif
170 
171  if(!(kernel->RunInitialization(fakeRun))) return;
172 
173  //Signal this thread can start event loop.
174  //Note this will return only when all threads reach this point
176  if(fakeRun) return;
177 
178  const G4UserWorkerInitialization* uwi
181  if(currentRun) delete currentRun;
182  currentRun = 0;
183 
185  //Call a user hook: this is guaranteed all threads are "synchronized"
186  if(uwi) uwi->WorkerRunStart();
187 
189  if(!currentRun) currentRun = new G4Run();
190 
193 
196  if(fSDM)
197  { currentRun->SetHCtable(fSDM->GetHCtable()); }
198 
200  {
201  auto hce = fSDM->PrepareNewEvent();
203  delete hce;
204  }
205 
206  std::ostringstream oss;
207  G4Random::saveFullState(oss);
208  randomNumberStatusForThisRun = oss.str();
210 
211  for(G4int i_prev=0;i_prev<n_perviousEventsToBeStored;i_prev++)
212  { previousEvents->push_back((G4Event*)0); }
213 
214  if(printModulo>0 || verboseLevel>0)
215  {
216  G4cout << "### Run " << currentRun->GetRunID() << " starts on worker thread "
217  << G4Threading::G4GetThreadId() << "." << G4endl;
218  }
220 
221  if (isScoreNtupleWriter) {
223  }
224 
226  G4String fileN = "currentRun";
227  if ( rngStatusEventsFlag ) {
228  std::ostringstream os;
229  os << "run" << currentRun->GetRunID();
230  fileN = os.str();
231  }
232  StoreRNGStatus(fileN);
233  }
234 
235  runAborted = false;
237 }
238 
239 void G4WorkerRunManager::DoEventLoop(G4int n_event, const char* macroFile , G4int n_select)
240 {
243  {
244  G4Exception("G4RunManager::GenerateEvent()", "Run0032", FatalException,
245  "G4VUserPrimaryGeneratorAction is not defined!");
246  }
247 
248  //This is the same as in the sequential case, just the for-loop indexes are
249  //different
250  InitializeEventLoop(n_event,macroFile,n_select);
251 
252  // Reset random number seeds queue
253  while(seedsQueue.size()>0)
254  { seedsQueue.pop(); }
255  // for each run, worker should receive at least one set of random number seeds.
256  runIsSeeded = false;
257 
258  // Event loop
259  eventLoopOnGoing = true;
261  G4int i_event = -1;
262  nevModulo = -1;
263  currEvID = -1;
264 
265  while(eventLoopOnGoing)
266  {
267  ProcessOneEvent(i_event);
268  if(eventLoopOnGoing)
269  {
271  if(runAborted)
272  { eventLoopOnGoing = false; }
278  }
279  }
280 
282 }
283 
285 {
287  currentEvent = GenerateEvent(i_event);
288  if(eventLoopOnGoing)
289  {
292  UpdateScoring();
294  }
295 }
296 
298 {
300  G4Event* anEvent = new G4Event(i_event);
301  long s1 = 0;
302  long s2 = 0;
303  long s3 = 0;
304  G4bool eventHasToBeSeeded = true;
306  { eventHasToBeSeeded = false; }
307 
308  if(i_event<0)
309  {
311  if(nevM==1)
312  {
314  ->SetUpAnEvent(anEvent,s1,s2,s3,eventHasToBeSeeded);
315  runIsSeeded = true;
316  }
317  else
318  {
319  if(nevModulo<=0)
320  {
322  ->SetUpNEvents(anEvent,&seedsQueue,eventHasToBeSeeded);
323  if(nevToDo==0)
324  { eventLoopOnGoing = false; }
325  else
326  {
327  currEvID = anEvent->GetEventID();
328  nevModulo = nevToDo - 1;
329  }
330  }
331  else
332  {
333  if(G4MTRunManager::SeedOncePerCommunication()>0) eventHasToBeSeeded = false;
334  anEvent->SetEventID(++currEvID);
335  nevModulo--;
336  }
337  if(eventLoopOnGoing && eventHasToBeSeeded)
338  {
339  s1 = seedsQueue.front(); seedsQueue.pop();
340  s2 = seedsQueue.front(); seedsQueue.pop();
341  }
342  }
343 
344  if(!eventLoopOnGoing)
345  {
346  delete anEvent;
347  return 0;
348  }
349  }
350  else if(eventHasToBeSeeded)
351  {
352  //Need to reseed random number generator
354  s1 = helper->GetSeed(i_event*2);
355  s2 = helper->GetSeed(i_event*2+1);
356  }
357 
358  if(eventHasToBeSeeded)
359  {
360  long seeds[3] = { s1, s2, 0 };
361  G4Random::setTheSeeds(seeds,luxury);
362  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 
394  {
395  std::ostringstream oss;
396  G4Random::saveFullState(oss);
397  randomNumberStatusForThisEvent = oss.str();
399  }
400 
401  if(storeRandomNumberStatus && ! RNGstatusReadFromFile ) { //If reading from file, avoid to rewrite the same
402  G4String fileN = "currentEvent";
403  if ( rngStatusEventsFlag ) {
404  fileN = filename();
405  }
406  StoreRNGStatus(fileN);
407  }
408 
409  if(printModulo > 0 && anEvent->GetEventID()%printModulo == 0 )
410  {
411  G4cout << "--> Event " << anEvent->GetEventID() << " starts";
412  if(eventHasToBeSeeded)
413  { G4cout << " with initial seeds (" << s1 << "," << s2 << ")"; }
414  G4cout << "." << G4endl;
415  }
417  return anEvent;
418 }
419 
421 {
422  //Merge partial results into global run
425  if(ScM) mtRM->MergeScores(ScM);
426  mtRM->MergeRun(currentRun);
427 }
428 
430 {
431  if(!fakeRun)
432  {
434 
435  //Call a user hook: note this is before the next barrier
436  //so threads execute this method asyncrhonouzly
437  //(TerminateRun allows for synch via G4RunAction::EndOfRun)
438  const G4UserWorkerInitialization* uwi
440  if(uwi) uwi->WorkerRunEnd();
441  }
442 
444  //Signal this thread has finished envent-loop.
445  //Note this will return only whan all threads reach this point
447 
448 }
449 
451 {
452  if(verboseLevel>0 && !fakeRun)
453  {
454  timer->Stop();
455  G4cout << "Thread-local run terminated." << G4endl;
456  G4cout << "Run Summary" << G4endl;
457  if(runAborted)
458  { G4cout << " Run Aborted after " << numberOfEventProcessed << " events processed." << G4endl; }
459  else
460  { G4cout << " Number of events processed : " << numberOfEventProcessed << G4endl; }
461  G4cout << " " << *timer << G4endl;
462  }
463 }
464 
465 /****************************
466 void G4WorkerRunManager::BeamOn(G4int n_event,const char* macroFile,G4int n_select)
467 {
468  if(n_event>0)
469  { G4RunManager::BeamOn(n_event,macroFile,n_select); }
470  else
471  {
472  // fake BeamOn.
473  G4MTRunManager::GetMasterRunManager()->ThisWorkerReady();
474  G4MTRunManager::GetMasterRunManager()->ThisWorkerEndEventLoop();
475  }
476 }
477 ******************************/
478 
479 #include "G4AutoLock.hh"
480 namespace { G4Mutex ConstructScoringWorldsMutex = G4MUTEX_INITIALIZER; }
482 {
483  using MeshShape = G4VScoringMesh::MeshShape;
484 
485  // Return if unnecessary
487  if(!ScM) return;
488  G4int nPar = ScM->GetNumberOfMesh();
489  if(nPar<1) return;
490 
491  // Update thread-local G4TransportationManager of all the world volumes
493 
495  assert( masterScM != NULL );
496 
499 
500  for(G4int iw=0;iw<nPar;iw++)
501  {
502  G4VScoringMesh* mesh = ScM->GetMesh(iw);
504  G4VPhysicalVolume* pWorld = nullptr;
505  if(mesh->GetShape()!=MeshShape::realWorldLogVol)
506  {
508  if(!pWorld)
509  {
511  ed<<"Mesh name <"<<ScM->GetWorldName(iw)<<"> is not found in the master thread.";
512  G4Exception("G4WorkerRunManager::ConstructScoringWorlds()","RUN79001",FatalException,ed);
513  }
514  }
515  if(!(mesh->GetMeshElementLogical()))
516  {
517  G4AutoLock l(&ConstructScoringWorldsMutex);
518  G4VScoringMesh* masterMesh = masterScM->GetMesh(iw);
519  mesh->SetMeshElementLogical(masterMesh->GetMeshElementLogical());
520  l.unlock();
521 
522  if(mesh->GetShape()!=MeshShape::realWorldLogVol)
523  {
524  G4ParallelWorldProcess* theParallelWorldProcess = mesh->GetParallelWorldProcess();
525  if(theParallelWorldProcess)
526  { theParallelWorldProcess->SetParallelWorld(ScM->GetWorldName(iw)); }
527  else
528  {
529  theParallelWorldProcess = new G4ParallelWorldProcess(ScM->GetWorldName(iw));
530  mesh->SetParallelWorldProcess(theParallelWorldProcess);
531  theParallelWorldProcess->SetParallelWorld(ScM->GetWorldName(iw));
532 
533  particleIterator->reset();
534  while( (*particleIterator)() ){
535  G4ParticleDefinition* particle = particleIterator->value();
536  G4ProcessManager* pmanager = particle->GetProcessManager();
537  if(pmanager)
538  {
539  pmanager->AddProcess(theParallelWorldProcess);
540  if(theParallelWorldProcess->IsAtRestRequired(particle))
541  { pmanager->SetProcessOrdering(theParallelWorldProcess, idxAtRest, 9900); }
542  pmanager->SetProcessOrderingToSecond(theParallelWorldProcess, idxAlongStep);
543  pmanager->SetProcessOrdering(theParallelWorldProcess, idxPostStep, 9900);
544  } //if(pmanager)
545  }//while
546  }
547  }
548  }
549  mesh->WorkerConstruct(pWorld);
550  }
551 }
552 
554 {
555  G4Exception("G4RunManager::SetUserInitialization(G4UserWorkerInitialization*)", "Run0118",
556  FatalException, "This method should be used only with an instance of G4MTRunManager");
557 }
558 
560 {
561  G4Exception("G4RunManager::SetUserInitialization(G4UserWorkerThreadInitialization*)", "Run0119",
562  FatalException, "This method should be used only with an instance of G4MTRunManager");
563 }
564 
566 {
567  G4Exception("G4RunManager::SetUserInitialization(G4VUserActionInitialization*)", "Run0120",
568  FatalException, "This method should be used only with an instance of G4MTRunManager");
569 }
570 
572 {
573  G4Exception("G4RunManager::SetUserInitialization(G4VUserDetectorConstruction*)", "Run0121",
574  FatalException, "This method should be used only with an instance of G4MTRunManager");
575 }
576 
578 {
579  pl->InitializeWorker();
581 }
582 
584 {
585  G4RunManager::SetUserAction(userAction);
586  if(userAction) userAction->SetMaster(false);
587 }
588 
590 {
592  assert(mrnge);//Master has created RNG
595  uwti->SetupRNGEngine(mrnge);
596 }
597 
598 
599 //Forward calls (avoid GCC compilation warnings)
601 {
603 }
604 
606 {
608 }
609 
611 {
613 }
614 
616 {
618 }
619 
621 {
623 }
624 
626 {
627  std::ostringstream os;
628  os << randomNumberStatusDir << "G4Worker"<<workerContext->GetThreadId()<<"_"<<fn <<".rndm";
629  G4Random::saveEngineStatus(os.str().c_str());
630 }
631 
633 {
634  G4int runNumber = 0;
635  if(currentRun) runNumber = currentRun->GetRunID();
637  {
638  G4cerr << "Warning from G4RunManager::rndmSaveThisRun():"
639  << " Random number status was not stored prior to this run."
640  << G4endl << "/random/setSavingFlag command must be issued. "
641  << "Command ignored." << G4endl;
642  return;
643  }
644 
645  std::ostringstream oos;
646  oos << "G4Worker" << workerContext->GetThreadId()
647  << "_" << "currentRun.rndm" << "\0";
648  G4String fileIn = randomNumberStatusDir + oos.str();
649 
650  std::ostringstream os;
651  os << "run" << runNumber << ".rndm" << '\0';
652  G4String fileOut = randomNumberStatusDir + os.str();
653 
654 #ifdef WIN32
655  G4String copCmd = "/control/shell copy " + fileIn + " " + fileOut;
656 #else
657  G4String copCmd = "/control/shell cp " + fileIn + " " + fileOut;
658 #endif
660  if(verboseLevel > 0)
661  { G4cout << fileIn << " is copied to " << fileOut << G4endl; }
662 }
663 
665 {
666  if(currentEvent == 0)
667  {
668  G4cerr
669  << "Warning from G4RunManager::rndmSaveThisEvent():"
670  << " there is no currentEvent available."
671  << G4endl << "Command ignored." << G4endl;
672  return;
673  }
674 
676  {
677  G4cerr
678  << "Warning from G4RunManager::rndmSaveThisEvent():"
679  << " Random number engine status is not available."
680  << G4endl << "/random/setSavingFlag command must be issued "
681  << "prior to the start of the run. Command ignored." << G4endl;
682  return;
683  }
684 
685  std::ostringstream oos;
686  oos << "G4Worker" << workerContext->GetThreadId()
687  << "_" << "currentEvent.rndm" << "\0";
688  G4String fileIn = randomNumberStatusDir + oos.str();
689 
690  std::ostringstream os;
691  os << "run" << currentRun->GetRunID() << "evt" << currentEvent->GetEventID()
692  << ".rndm" << '\0';
693  G4String fileOut = randomNumberStatusDir + os.str();
694 #ifdef WIN32
695  G4String copCmd = "/control/shell copy " + fileIn + " " + fileOut;
696 #else
697  G4String copCmd = "/control/shell cp " + fileIn + " " + fileOut;
698 #endif
700  if(verboseLevel > 0)
701  { G4cout << fileIn << " is copied to " << fileOut << G4endl; }
702 }
703 
705 {
709  while( nextAction != G4MTRunManager::WorkerActionRequest::ENDWORKER )
710  {
711  if( nextAction == G4MTRunManager::WorkerActionRequest::NEXTITERATION ) // start the next run
712  {
713  //The following code deals with changing materials between runs
714  static G4ThreadLocal G4bool skipInitialization = true;
715  if(skipInitialization)
716  {
717  // re-initialization is not necessary for the first run
718  skipInitialization = false;
719  }
720  else
721  {
722 // ReinitializeGeometry();
724  }
725 
726  // Execute UI commands stored in the master UI manager
727  std::vector<G4String> cmds = mrm->GetCommandStack();
728  G4UImanager* uimgr = G4UImanager::GetUIpointer(); //TLS instance
729  std::vector<G4String>::const_iterator it = cmds.begin();
730  for(;it!=cmds.end();it++)
731  { uimgr->ApplyCommand(*it); }
732  //Start this run
733  G4int numevents = mrm->GetNumberOfEventsToBeProcessed();
734  G4String macroFile = mrm->GetSelectMacro();
735  G4int numSelect = mrm->GetNumberOfSelectEvents();
736  if ( macroFile == "" || macroFile == " " )
737  {
738  this->BeamOn(numevents);
739  }
740  else
741  {
742  this->BeamOn(numevents,macroFile,numSelect);
743  }
744  }
745  else if (nextAction == G4MTRunManager::WorkerActionRequest::PROCESSUI ) {
746  std::vector<G4String> cmds = mrm->GetCommandStack();
747  G4UImanager* uimgr = G4UImanager::GetUIpointer(); //TLS instance
748  std::vector<G4String>::const_iterator it = cmds.begin();
749  for(;it!=cmds.end();it++)
750  { uimgr->ApplyCommand(*it); }
752  }
753  else
754  {
756  d<<"Cannot continue, this worker has been requested an unknown action: "
757  <<static_cast<std::underlying_type<G4MTRunManager::WorkerActionRequest>::type>(nextAction);
758  G4Exception("G4WorkerRunManager::DoWork","Run0104",FatalException,d);
759  }
760 
761  //Now wait for master thread to signal new action to be performed
762  nextAction = mrm->ThisWorkerWaitForNextAction();
763  } //No more actions to perform
764 
765  return;
766 }