Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/run/src/G4WorkerTaskRunManager.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 "G4WorkerTaskRunManager.hh"
 29 
 30 #include "G4AutoLock.hh"
 31 #include "G4MTRunManager.hh"
 32 #include "G4ParallelWorldProcess.hh"
 33 #include "G4ParallelWorldProcessStore.hh"
 34 #include "G4RNGHelper.hh"
 35 #include "G4Run.hh"
 36 #include "G4SDManager.hh"
 37 #include "G4ScoringManager.hh"
 38 #include "G4TaskRunManager.hh"
 39 #include "G4Timer.hh"
 40 #include "G4TransportationManager.hh"
 41 #include "G4UImanager.hh"
 42 #include "G4UserRunAction.hh"
 43 #include "G4UserWorkerInitialization.hh"
 44 #include "G4UserWorkerThreadInitialization.hh"
 45 #include "G4VScoreNtupleWriter.hh"
 46 #include "G4VScoringMesh.hh"
 47 #include "G4VUserActionInitialization.hh"
 48 #include "G4VUserDetectorConstruction.hh"
 49 #include "G4VUserPhysicsList.hh"
 50 #include "G4VUserPrimaryGeneratorAction.hh"
 51 #include "G4VVisManager.hh"
 52 #include "G4WorkerTaskRunManagerKernel.hh"
 53 #include "G4WorkerThread.hh"
 54 
 55 #include <fstream>
 56 #include <sstream>
 57 
 58 //============================================================================//
 59 
 60 G4WorkerTaskRunManager* G4WorkerTaskRunManager::GetWorkerRunManager()
 61 {
 62   return static_cast<G4WorkerTaskRunManager*>(G4RunManager::GetRunManager());
 63 }
 64 
 65 //============================================================================//
 66 
 67 G4WorkerTaskRunManagerKernel* G4WorkerTaskRunManager::GetWorkerRunManagerKernel()
 68 {
 69   return static_cast<G4WorkerTaskRunManagerKernel*>(GetWorkerRunManager()->kernel);
 70 }
 71 
 72 //============================================================================//
 73 
 74 void G4WorkerTaskRunManager::RunInitialization()
 75 {
 76 #ifdef G4MULTITHREADED
 77   if (!visIsSetUp) {
 78     G4VVisManager* pVVis = G4VVisManager::GetConcreteInstance();
 79     if (pVVis != nullptr) {
 80       pVVis->SetUpForAThread();
 81       visIsSetUp = true;
 82     }
 83   }
 84 #endif
 85   runIsSeeded = false;
 86 
 87   if (!(kernel->RunInitialization(fakeRun))) return;
 88 
 89   // Signal this thread can start event loop.
 90   // Note this will return only when all threads reach this point
 91   G4MTRunManager::GetMasterRunManager()->ThisWorkerReady();
 92   if (fakeRun) return;
 93 
 94   const G4UserWorkerInitialization* uwi =
 95     G4MTRunManager::GetMasterRunManager()->GetUserWorkerInitialization();
 96 
 97   CleanUpPreviousEvents();
 98 
 99   delete currentRun;
100 
101   currentRun = nullptr;
102 
103   if (IfGeometryHasBeenDestroyed()) G4ParallelWorldProcessStore::GetInstance()->UpdateWorlds();
104 
105   // Call a user hook: this is guaranteed all threads are "synchronized"
106   if (uwi != nullptr) uwi->WorkerRunStart();
107 
108   if (userRunAction != nullptr) currentRun = userRunAction->GenerateRun();
109   if (currentRun == nullptr) currentRun = new G4Run();
110 
111   currentRun->SetRunID(runIDCounter);
112   G4TaskRunManager* mrm = G4TaskRunManager::GetMasterRunManager();
113   numberOfEventToBeProcessed = mrm->GetNumberOfEventsToBeProcessed();
114   currentRun->SetNumberOfEventToBeProcessed(numberOfEventToBeProcessed);
115 
116   currentRun->SetDCtable(DCtable);
117   G4SDManager* fSDM = G4SDManager::GetSDMpointerIfExist();
118   if (fSDM != nullptr) {
119     currentRun->SetHCtable(fSDM->GetHCtable());
120   }
121 
122   if (G4VScoreNtupleWriter::Instance() != nullptr) {
123     auto hce = (fSDM != nullptr) ? fSDM->PrepareNewEvent() : nullptr;
124     isScoreNtupleWriter = G4VScoreNtupleWriter::Instance()->Book(hce);
125     delete hce;
126   }
127 
128   std::ostringstream oss;
129   G4Random::saveFullState(oss);
130   randomNumberStatusForThisRun = oss.str();
131   currentRun->SetRandomNumberStatus(randomNumberStatusForThisRun);
132 
133   for (G4int i_prev = 0; i_prev < n_perviousEventsToBeStored; ++i_prev)
134     previousEvents->push_back(nullptr);
135 
136   if (printModulo > 0 || verboseLevel > 0) {
137     G4cout << "### Run " << currentRun->GetRunID() << " starts on worker thread "
138            << G4Threading::G4GetThreadId() << "." << G4endl;
139   }
140 
141   if (userRunAction != nullptr) userRunAction->BeginOfRunAction(currentRun);
142 
143   if (isScoreNtupleWriter) {
144     G4VScoreNtupleWriter::Instance()->OpenFile();
145   }
146 
147   if (storeRandomNumberStatus) {
148     G4String fileN = "currentRun";
149     if (rngStatusEventsFlag) {
150       std::ostringstream os;
151       os << "run" << currentRun->GetRunID();
152       fileN = os.str();
153     }
154     StoreRNGStatus(fileN);
155   }
156 
157   runAborted = false;
158   numberOfEventProcessed = 0;
159 }
160 
161 //============================================================================//
162 
163 void G4WorkerTaskRunManager::DoEventLoop(G4int n_event, const char* macroFile, G4int n_select)
164 {
165   if (userPrimaryGeneratorAction == nullptr) {
166     G4Exception("G4RunManager::GenerateEvent()", "Run0032", FatalException,
167                 "G4VUserPrimaryGeneratorAction is not defined!");
168   }
169 
170   // This is the same as in the sequential case, just the for-loop indexes are
171   // different
172   InitializeEventLoop(n_event, macroFile, n_select);
173 
174   // Reset random number seeds queue
175   while (!seedsQueue.empty())
176     seedsQueue.pop();
177   // for each run, worker should receive at least one set of random number
178   // seeds.
179   // runIsSeeded = false;
180 
181   // Event loop
182   eventLoopOnGoing = true;
183   G4int i_event = -1;
184   nevModulo = -1;
185   currEvID = -1;
186 
187   for (G4int evt = 0; evt < n_event; ++evt) {
188     ProcessOneEvent(i_event);
189     if (eventLoopOnGoing) {
190       TerminateOneEvent();
191       if (runAborted) eventLoopOnGoing = false;
192     }
193     if (!eventLoopOnGoing) break;
194   }
195 }
196 
197 //============================================================================//
198 
199 void G4WorkerTaskRunManager::ProcessOneEvent(G4int i_event)
200 {
201   currentEvent = GenerateEvent(i_event);
202   if (eventLoopOnGoing) {
203     eventManager->ProcessOneEvent(currentEvent);
204     AnalyzeEvent(currentEvent);
205     UpdateScoring();
206     if (currentEvent->GetEventID() < n_select_msg) {
207       G4cout << "Applying command \"" << msgText << "\" @ " << __FUNCTION__ << ":" << __LINE__
208              << G4endl;
209       G4UImanager::GetUIpointer()->ApplyCommand(msgText);
210     }
211   }
212 }
213 
214 //============================================================================//
215 
216 G4Event* G4WorkerTaskRunManager::GenerateEvent(G4int i_event)
217 {
218   auto anEvent = new G4Event(i_event);
219   G4long s1 = 0;
220   G4long s2 = 0;
221   G4long s3 = 0;
222   G4bool eventHasToBeSeeded = true;
223   if (G4MTRunManager::SeedOncePerCommunication() == 1 && runIsSeeded) eventHasToBeSeeded = false;
224 
225   if (i_event < 0) {
226     G4int nevM = G4MTRunManager::GetMasterRunManager()->GetEventModulo();
227     if (nevM == 1) {
228       eventLoopOnGoing = G4MTRunManager::GetMasterRunManager()->SetUpAnEvent(anEvent, s1, s2, s3,
229                                                                              eventHasToBeSeeded);
230       runIsSeeded = true;
231     }
232     else {
233       if (nevModulo <= 0) {
234         G4int nevToDo = G4MTRunManager::GetMasterRunManager()->SetUpNEvents(anEvent, &seedsQueue,
235                                                                             eventHasToBeSeeded);
236         if (nevToDo == 0)
237           eventLoopOnGoing = false;
238         else {
239           currEvID = anEvent->GetEventID();
240           nevModulo = nevToDo - 1;
241         }
242       }
243       else {
244         if (G4MTRunManager::SeedOncePerCommunication() > 0) eventHasToBeSeeded = false;
245         anEvent->SetEventID(++currEvID);
246         nevModulo--;
247       }
248       if (eventLoopOnGoing && eventHasToBeSeeded) {
249         s1 = seedsQueue.front();
250         seedsQueue.pop();
251         s2 = seedsQueue.front();
252         seedsQueue.pop();
253       }
254     }
255 
256     if (!eventLoopOnGoing) {
257       anEvent->ScoresRecorded();
258       delete anEvent;
259       return nullptr;
260     }
261   }
262   else if (eventHasToBeSeeded) {
263     // Need to reseed random number generator
264     G4RNGHelper* helper = G4RNGHelper::GetInstance();
265     s1 = helper->GetSeed(i_event * 2);
266     s2 = helper->GetSeed(i_event * 2 + 1);
267   }
268 
269   if (eventHasToBeSeeded) {
270     G4long seeds[3] = {s1, s2, 0};
271     G4Random::setTheSeeds(seeds, -1);
272     runIsSeeded = true;
273   }
274 
275   // Read from file seed.
276   // Andrea Dotti 4 November 2015
277   // This is required for strong-reproducibility, in MT mode we have that each
278   // thread produces, for each event a status file, we want to do that.
279   // Search a random file with the format run{%d}evt{%d}.rndm
280 
281   // This is the filename base constructed from run and event
282   const auto filename = [&] {
283     std::ostringstream os;
284     os << "run" << currentRun->GetRunID() << "evt" << anEvent->GetEventID();
285     return os.str();
286   };
287 
288   G4bool RNGstatusReadFromFile = false;
289   if (readStatusFromFile) {
290     // Build full path of RNG status file for this event
291     std::ostringstream os;
292     os << filename() << ".rndm";
293     const G4String& randomStatusFile = os.str();
294     std::ifstream ifile(randomStatusFile.c_str());
295     if (ifile) {
296       // File valid and readable
297       RNGstatusReadFromFile = true;
298       G4Random::restoreEngineStatus(randomStatusFile.c_str());
299     }
300   }
301 
302   if (storeRandomNumberStatusToG4Event == 1 || storeRandomNumberStatusToG4Event == 3) {
303     std::ostringstream oss;
304     G4Random::saveFullState(oss);
305     randomNumberStatusForThisEvent = oss.str();
306     anEvent->SetRandomNumberStatus(randomNumberStatusForThisEvent);
307   }
308 
309   if (storeRandomNumberStatus && !RNGstatusReadFromFile) {
310     // If reading from file, avoid to rewrite the same
311     G4String fileN = "currentEvent";
312     if (rngStatusEventsFlag) fileN = filename();
313     StoreRNGStatus(fileN);
314   }
315 
316   if (printModulo > 0 && anEvent->GetEventID() % printModulo == 0) {
317     G4cout << "--> Event " << anEvent->GetEventID() << " starts";
318     if (eventHasToBeSeeded) G4cout << " with initial seeds (" << s1 << "," << s2 << ")";
319     G4cout << "." << G4endl;
320   }
321   userPrimaryGeneratorAction->GeneratePrimaries(anEvent);
322   return anEvent;
323 }
324 
325 //============================================================================//
326 
327 void G4WorkerTaskRunManager::RunTermination()
328 {
329   if (!fakeRun && (currentRun != nullptr)) {
330     MergePartialResults();
331 
332     // Call a user hook: note this is before the next barrier
333     // so threads execute this method asyncrhonouzly
334     //(TerminateRun allows for synch via G4RunAction::EndOfRun)
335     const G4UserWorkerInitialization* uwi =
336       G4MTRunManager::GetMasterRunManager()->GetUserWorkerInitialization();
337     if (uwi != nullptr) uwi->WorkerRunEnd();
338   }
339 
340   if (currentRun != nullptr) {
341     G4RunManager::RunTermination();
342   }
343   // Signal this thread has finished envent-loop.
344   // Note this will return only whan all threads reach this point
345   G4MTRunManager::GetMasterRunManager()->ThisWorkerEndEventLoop();
346 }
347 
348 //============================================================================//
349 
350 void G4WorkerTaskRunManager::TerminateEventLoop()
351 {
352   if (verboseLevel > 0 && !fakeRun) {
353     timer->Stop();
354     // prefix with thread # info due to how TBB calls this function
355     G4String prefix = "[thread " + std::to_string(workerContext->GetThreadId()) + "] ";
356     G4cout << prefix << "Thread-local run terminated." << G4endl;
357     G4cout << prefix << "Run Summary" << G4endl;
358     if (runAborted)
359       G4cout << prefix << "  Run Aborted after " << numberOfEventProcessed << " events processed."
360              << G4endl;
361     else
362       G4cout << prefix << "  Number of events processed : " << numberOfEventProcessed << G4endl;
363     G4cout << prefix << "  " << *timer << G4endl;
364   }
365 }
366 
367 //============================================================================//
368 
369 void G4WorkerTaskRunManager::SetupDefaultRNGEngine()
370 {
371   const CLHEP::HepRandomEngine* mrnge =
372     G4MTRunManager::GetMasterRunManager()->getMasterRandomEngine();
373   assert(mrnge);  // Master has created RNG
374   const G4UserWorkerThreadInitialization* uwti =
375     G4MTRunManager::GetMasterRunManager()->GetUserWorkerThreadInitialization();
376   uwti->SetupRNGEngine(mrnge);
377 }
378 
379 //============================================================================//
380 
381 void G4WorkerTaskRunManager::StoreRNGStatus(const G4String& fn)
382 {
383   std::ostringstream os;
384   os << randomNumberStatusDir << "G4Worker" << workerContext->GetThreadId() << "_" << fn << ".rndm";
385   G4Random::saveEngineStatus(os.str().c_str());
386 }
387 
388 //============================================================================//
389 
390 void G4WorkerTaskRunManager::ProcessUI()
391 {
392   G4TaskRunManager* mrm = G4TaskRunManager::GetMasterRunManager();
393   if (mrm == nullptr) return;
394 
395   //------------------------------------------------------------------------//
396   // Check UI commands not already processed
397   auto command_stack = mrm->GetCommandStack();
398   bool matching = (command_stack.size() == processedCommandStack.size());
399   if (matching) {
400     for (uintmax_t i = 0; i < command_stack.size(); ++i)
401       if (processedCommandStack.at(i) != command_stack.at(i)) {
402         matching = false;
403         break;
404       }
405   }
406 
407   //------------------------------------------------------------------------//
408   // Execute UI commands stored in the master UI manager
409   if (!matching) {
410     for (const auto& itr : command_stack)
411       G4UImanager::GetUIpointer()->ApplyCommand(itr);
412     processedCommandStack = std::move(command_stack);
413   }
414 }
415 
416 //============================================================================//
417 
418 void G4WorkerTaskRunManager::DoCleanup()
419 {
420   CleanUpPreviousEvents();
421 
422   delete currentRun;
423   currentRun = nullptr;
424 }
425 
426 //============================================================================//
427 
428 void G4WorkerTaskRunManager::DoWork()
429 {
430   G4TaskRunManager* mrm = G4TaskRunManager::GetMasterRunManager();
431   G4bool newRun = false;
432   const G4Run* run = mrm->GetCurrentRun();
433   G4ThreadLocalStatic G4int runId = -1;
434   if ((run != nullptr) && run->GetRunID() != runId) {
435     runId = run->GetRunID();
436     newRun = true;
437     if (runId > 0) {
438       ProcessUI();
439       assert(workerContext != nullptr);
440     }
441     workerContext->UpdateGeometryAndPhysicsVectorFromMaster();
442   }
443 
444   // Start this run
445   G4int nevts = mrm->GetNumberOfEventsPerTask();
446   G4int numSelect = mrm->GetNumberOfSelectEvents();
447   G4String macroFile = mrm->GetSelectMacro();
448   G4bool empty_macro = (macroFile.empty() || macroFile == " ");
449 
450   const char* macro = (empty_macro) ? nullptr : macroFile.c_str();
451   numSelect = (empty_macro) ? -1 : numSelect;
452 
453   if (newRun) {
454     G4bool cond = ConfirmBeamOnCondition();
455     if (cond) {
456       ConstructScoringWorlds();
457       RunInitialization();
458     }
459   }
460   DoEventLoop(nevts, macro, numSelect);
461 }
462 
463 //============================================================================//
464