Geant4 Cross Reference |
1 // 1 2 // ******************************************* 3 // * License and Disclaimer 4 // * 5 // * The Geant4 software is copyright of th 6 // * the Geant4 Collaboration. It is provided 7 // * conditions of the Geant4 Software License 8 // * LICENSE and available at http://cern.ch/ 9 // * include a list of copyright holders. 10 // * 11 // * Neither the authors of this software syst 12 // * institutes,nor the agencies providing fin 13 // * work make any representation or warran 14 // * regarding this software system or assum 15 // * use. Please see the license in the file 16 // * for the full disclaimer and the limitatio 17 // * 18 // * This code implementation is the result 19 // * technical work of the GEANT4 collaboratio 20 // * By using, copying, modifying or distri 21 // * any work based on the software) you ag 22 // * use in resulting scientific publicati 23 // * acceptance of all terms of the Geant4 Sof 24 // ******************************************* 25 // 26 // G4WorkerRunManager implementation 27 // 28 // Original authors: X.Dong, A.Dotti - 2013 29 // ------------------------------------------- 30 31 #include "G4WorkerRunManager.hh" 32 33 #include "G4AutoLock.hh" 34 #include "G4CopyRandomState.hh" 35 #include "G4MTRunManager.hh" 36 #include "G4ParallelWorldProcess.hh" 37 #include "G4ParallelWorldProcessStore.hh" 38 #include "G4RNGHelper.hh" 39 #include "G4Run.hh" 40 #include "G4SDManager.hh" 41 #include "G4ScoringManager.hh" 42 #include "G4Timer.hh" 43 #include "G4TransportationManager.hh" 44 #include "G4UImanager.hh" 45 #include "G4UserRunAction.hh" 46 #include "G4UserWorkerInitialization.hh" 47 #include "G4UserWorkerThreadInitialization.hh" 48 #include "G4VScoreNtupleWriter.hh" 49 #include "G4VScoringMesh.hh" 50 #include "G4VUserActionInitialization.hh" 51 #include "G4VUserDetectorConstruction.hh" 52 #include "G4VUserPhysicsList.hh" 53 #include "G4VUserPrimaryGeneratorAction.hh" 54 #include "G4VVisManager.hh" 55 #include "G4WorkerRunManagerKernel.hh" 56 #include "G4WorkerThread.hh" 57 58 #include "G4GeometryManager.hh" // For paral 59 60 #include <fstream> 61 #include <sstream> 62 63 // ------------------------------------------- 64 G4WorkerRunManager* G4WorkerRunManager::GetWor 65 { 66 return static_cast<G4WorkerRunManager*>(G4Ru 67 } 68 69 // ------------------------------------------- 70 G4WorkerRunManagerKernel* G4WorkerRunManager:: 71 { 72 return static_cast<G4WorkerRunManagerKernel* 73 } 74 75 // ------------------------------------------- 76 G4WorkerRunManager::G4WorkerRunManager() : G4R 77 { 78 // This constructor should never be called i 79 80 #ifndef G4MULTITHREADED 81 G4ExceptionDescription msg; 82 msg << "Geant4 code is compiled without mult 83 "(-DG4MULTITHREADED " 84 "is set to off)."; 85 msg << " This type of RunManager can only be 86 "applications."; 87 G4Exception("G4WorkerRunManager::G4WorkerRun 88 #endif 89 // G4ParticleTable::GetParticleTable()->Work 90 // WorkerG4ParticleTable() would be perfo 91 // as it is called already from G4Particl 92 // which is called beforehand by other Ge 93 G4ScoringManager* masterScM = G4MTRunManager 94 if (masterScM != nullptr) G4ScoringManager:: 95 96 // Properly initialise luxury level for Ranl 97 // 98 if (dynamic_cast<const CLHEP::Ranlux64Engine 99 const auto theEngine = dynamic_cast<const 100 luxury = theEngine->getLuxury(); 101 } 102 else if (dynamic_cast<const CLHEP::RanluxEng 103 const auto theEngine = dynamic_cast<const 104 luxury = theEngine->getLuxury(); 105 } 106 107 G4UImanager::GetUIpointer()->SetIgnoreCmdNot 108 109 #ifdef G4MULTITHREADED 110 G4VVisManager* pVVis = G4VVisManager::GetCon 111 if (pVVis != nullptr) { 112 pVVis->SetUpForAThread(); 113 visIsSetUp = true; 114 } 115 #endif 116 } 117 118 // ------------------------------------------- 119 G4WorkerRunManager::~G4WorkerRunManager() 120 { 121 CleanUpPreviousEvents(); 122 // Put these pointers to zero: owned by mast 123 // If not to zero, the base class destructor 124 // delete them 125 userDetector = nullptr; 126 userWorkerInitialization = nullptr; 127 userWorkerThreadInitialization = nullptr; 128 userActionInitialization = nullptr; 129 physicsList->TerminateWorker(); 130 physicsList = nullptr; 131 if (verboseLevel > 1) G4cout << "Destroying 132 } 133 134 // ------------------------------------------- 135 void G4WorkerRunManager::InitializeGeometry() 136 { 137 if (userDetector == nullptr) { 138 G4Exception("G4RunManager::InitializeGeome 139 "G4VUserDetectorConstruction i 140 return; 141 } 142 143 if (fGeometryHasBeenDestroyed) { 144 G4TransportationManager::GetTransportation 145 } 146 147 // Step 0: Contribute to the voxelisation of 148 G4GeometryManager* geomManager = G4GeometryM 149 if( geomManager->IsParallelOptimisationConfi 150 G4cout << "G4RunManager::InitializeGeometr 151 << G4endl; // TODO - suppress / de 152 geomManager->UndertakeOptimisation(); 153 } 154 // A barrier must ensure that all that all 155 // Currently we rely on the (later) barrier 156 157 // Step1: Get pointer to the physiWorld (not 158 // pointer, i.e. the one shared by all threa 159 G4RunManagerKernel* masterKernel = G4MTRunMa 160 G4VPhysicalVolume* worldVol = masterKernel-> 161 // Step2:, Call a new "WorkerDefineWorldVolu 162 kernel->WorkerDefineWorldVolume(worldVol, fa 163 kernel->SetNumberOfParallelWorld(masterKerne 164 // Step3: Call user's ConstructSDandField() 165 userDetector->ConstructSDandField(); 166 userDetector->ConstructParallelSD(); 167 geometryInitialized = true; 168 } 169 170 // ------------------------------------------- 171 void G4WorkerRunManager::RunInitialization() 172 { 173 #ifdef G4MULTITHREADED 174 if (!visIsSetUp) { 175 G4VVisManager* pVVis = G4VVisManager::GetC 176 if (pVVis != nullptr) { 177 pVVis->SetUpForAThread(); 178 visIsSetUp = true; 179 } 180 } 181 #endif 182 183 if (!(kernel->RunInitialization(fakeRun))) r 184 185 // Signal this thread can start event loop. 186 // Note this will return only when all threa 187 G4MTRunManager::GetMasterRunManager()->ThisW 188 if (fakeRun) return; 189 190 const G4UserWorkerInitialization* uwi = 191 G4MTRunManager::GetMasterRunManager()->Get 192 CleanUpPreviousEvents(); 193 delete currentRun; 194 currentRun = nullptr; 195 196 if (fGeometryHasBeenDestroyed) G4ParallelWor 197 // Call a user hook: this is guaranteed all 198 if (uwi != nullptr) uwi->WorkerRunStart(); 199 200 if (userRunAction != nullptr) currentRun = u 201 if (currentRun == nullptr) currentRun = new 202 203 currentRun->SetRunID(runIDCounter); 204 currentRun->SetNumberOfEventToBeProcessed(nu 205 206 currentRun->SetDCtable(DCtable); 207 G4SDManager* fSDM = G4SDManager::GetSDMpoint 208 if (fSDM != nullptr) { 209 currentRun->SetHCtable(fSDM->GetHCtable()) 210 } 211 212 if (G4VScoreNtupleWriter::Instance() != null 213 auto hce = (fSDM != nullptr) ? fSDM->Prepa 214 isScoreNtupleWriter = G4VScoreNtupleWriter 215 delete hce; 216 } 217 218 std::ostringstream oss; 219 G4Random::saveFullState(oss); 220 randomNumberStatusForThisRun = oss.str(); 221 currentRun->SetRandomNumberStatus(randomNumb 222 223 for (G4int i_prev = 0; i_prev < n_perviousEv 224 previousEvents->push_back(nullptr); 225 } 226 227 if (printModulo > 0 || verboseLevel > 0) { 228 G4cout << "### Run " << currentRun->GetRun 229 << G4Threading::G4GetThreadId() << 230 } 231 if (userRunAction != nullptr) userRunAction- 232 233 if (isScoreNtupleWriter) { 234 G4VScoreNtupleWriter::Instance()->OpenFile 235 } 236 237 if (storeRandomNumberStatus) { 238 G4String fileN = "currentRun"; 239 if (rngStatusEventsFlag) { 240 std::ostringstream os; 241 os << "run" << currentRun->GetRunID(); 242 fileN = os.str(); 243 } 244 StoreRNGStatus(fileN); 245 } 246 247 runAborted = false; 248 numberOfEventProcessed = 0; 249 } 250 251 // ------------------------------------------- 252 void G4WorkerRunManager::DoEventLoop(G4int n_e 253 { 254 if (userPrimaryGeneratorAction == nullptr) { 255 G4Exception("G4RunManager::GenerateEvent() 256 "G4VUserPrimaryGeneratorAction 257 } 258 259 // This is the same as in the sequential cas 260 // different 261 InitializeEventLoop(n_event, macroFile, n_se 262 263 // Reset random number seeds queue 264 while (!seedsQueue.empty()) { 265 seedsQueue.pop(); 266 } 267 // for each run, worker should receive at le 268 // seeds. 269 runIsSeeded = false; 270 271 // Event loop 272 eventLoopOnGoing = true; 273 /////// G4int i_event = workerContext->Ge 274 G4int i_event = -1; 275 nevModulo = -1; 276 currEvID = -1; 277 278 while (eventLoopOnGoing) { 279 ProcessOneEvent(i_event); 280 if (eventLoopOnGoing) { 281 TerminateOneEvent(); 282 if (runAborted) { 283 eventLoopOnGoing = false; 284 } 285 } 286 } 287 288 TerminateEventLoop(); 289 } 290 291 // ------------------------------------------- 292 void G4WorkerRunManager::ProcessOneEvent(G4int 293 { 294 currentEvent = GenerateEvent(i_event); 295 if (eventLoopOnGoing) { 296 eventManager->ProcessOneEvent(currentEvent 297 AnalyzeEvent(currentEvent); 298 UpdateScoring(); 299 if (currentEvent->GetEventID() < n_select_ 300 G4UImanager::GetUIpointer()->ApplyComman 301 } 302 } 303 304 // ------------------------------------------- 305 G4Event* G4WorkerRunManager::GenerateEvent(G4i 306 { 307 auto anEvent = new G4Event(i_event); 308 G4long s1 = 0; 309 G4long s2 = 0; 310 G4long s3 = 0; 311 G4bool eventHasToBeSeeded = true; 312 if (G4MTRunManager::SeedOncePerCommunication 313 eventHasToBeSeeded = false; 314 } 315 316 if (i_event < 0) { 317 G4int nevM = G4MTRunManager::GetMasterRunM 318 if (nevM == 1) { 319 eventLoopOnGoing = G4MTRunManager::GetMa 320 321 runIsSeeded = true; 322 } 323 else { 324 if (nevModulo <= 0) { 325 G4int nevToDo = G4MTRunManager::GetMas 326 327 if (nevToDo == 0) { 328 eventLoopOnGoing = false; 329 } 330 else { 331 currEvID = anEvent->GetEventID(); 332 nevModulo = nevToDo - 1; 333 } 334 } 335 else { 336 if (G4MTRunManager::SeedOncePerCommuni 337 anEvent->SetEventID(++currEvID); 338 --nevModulo; 339 } 340 if (eventLoopOnGoing && eventHasToBeSeed 341 s1 = seedsQueue.front(); 342 seedsQueue.pop(); 343 s2 = seedsQueue.front(); 344 seedsQueue.pop(); 345 } 346 } 347 348 if (!eventLoopOnGoing) { 349 delete anEvent; 350 return nullptr; 351 } 352 } 353 else if (eventHasToBeSeeded) { 354 // Need to reseed random number generator 355 G4RNGHelper* helper = G4RNGHelper::GetInst 356 s1 = helper->GetSeed(i_event * 2); 357 s2 = helper->GetSeed(i_event * 2 + 1); 358 } 359 360 if (eventHasToBeSeeded) { 361 G4long seeds[3] = {s1, s2, 0}; 362 G4Random::setTheSeeds(seeds, luxury); 363 runIsSeeded = true; 364 } 365 366 // Read from file seed. 367 // Andrea Dotti 4 November 2015 368 // This is required for strong-reproducibili 369 // thread produces, for each event a status 370 // Search a random file with the format run{ 371 372 // This is the filename base constructed fro 373 const auto filename = [&] { 374 std::ostringstream os; 375 os << "run" << currentRun->GetRunID() << " 376 return os.str(); 377 }; 378 379 G4bool RNGstatusReadFromFile = false; 380 if (readStatusFromFile) { 381 // Build full path of RNG status file for 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(randomStat 389 } 390 } 391 392 if (storeRandomNumberStatusToG4Event == 1 || 393 std::ostringstream oss; 394 G4Random::saveFullState(oss); 395 randomNumberStatusForThisEvent = oss.str() 396 anEvent->SetRandomNumberStatus(randomNumbe 397 } 398 399 if (storeRandomNumberStatus && !RNGstatusRea 400 { // If reading from file, avoid to rewrite 401 G4String fileN = "currentEvent"; 402 if (rngStatusEventsFlag) { 403 fileN = filename(); 404 } 405 StoreRNGStatus(fileN); 406 } 407 408 if (printModulo > 0 && anEvent->GetEventID() 409 G4cout << "--> Event " << anEvent->GetEven 410 if (eventHasToBeSeeded) { 411 G4cout << " with initial seeds (" << s1 412 } 413 G4cout << "." << G4endl; 414 } 415 userPrimaryGeneratorAction->GeneratePrimarie 416 return anEvent; 417 } 418 419 // ------------------------------------------- 420 void G4WorkerRunManager::MergePartialResults(G 421 { 422 // Merge partial results into global run 423 G4MTRunManager* mtRM = G4MTRunManager::GetMa 424 G4ScoringManager* ScM = G4ScoringManager::Ge 425 if (ScM != nullptr) mtRM->MergeScores(ScM); 426 #ifdef G4VERBOSE 427 if(mergeEvents && verboseLevel>3) { 428 auto eventVector = currentRun->GetEventVec 429 if(eventVector!=nullptr || !(eventVector-> 430 G4cout<<"G4WorkerRunManager::MergePartia 431 <<eventVector->size()<<" events."< 432 } 433 } 434 #endif 435 if(mergeEvents) mtRM->MergeRun(currentRun); 436 } 437 438 // ------------------------------------------- 439 void G4WorkerRunManager::RunTermination() 440 { 441 if (!fakeRun) { 442 MergePartialResults(); 443 444 // Call a user hook: note this is before t 445 // so threads execute this method asyncrho 446 //(TerminateRun allows for synch via G4Run 447 const G4UserWorkerInitialization* uwi = 448 G4MTRunManager::GetMasterRunManager()->G 449 if (uwi != nullptr) uwi->WorkerRunEnd(); 450 } 451 452 G4RunManager::RunTermination(); 453 // Signal this thread has finished envent-lo 454 // Note this will return only whan all threa 455 G4MTRunManager::GetMasterRunManager()->ThisW 456 } 457 458 // ------------------------------------------- 459 void G4WorkerRunManager::TerminateEventLoop() 460 { 461 if (verboseLevel > 0 && !fakeRun) { 462 timer->Stop(); 463 G4cout << "Thread-local run terminated." < 464 G4cout << "Run Summary" << G4endl; 465 if (runAborted) { 466 G4cout << " Run Aborted after " << numb 467 } 468 else { 469 G4cout << " Number of events processed 470 } 471 G4cout << " " << *timer << G4endl; 472 } 473 } 474 475 // ------------------------------------------- 476 namespace 477 { 478 G4Mutex ConstructScoringWorldsMutex = G4MUTEX_ 479 } 480 481 // ------------------------------------------- 482 void G4WorkerRunManager::ConstructScoringWorld 483 { 484 using MeshShape = G4VScoringMesh::MeshShape; 485 486 // Return if unnecessary 487 G4ScoringManager* ScM = G4ScoringManager::Ge 488 if (ScM == nullptr) return; 489 auto nPar = (G4int)ScM->GetNumberOfMesh(); 490 if (nPar < 1) return; 491 492 // Update thread-local G4TransportationManag 493 kernel->WorkerUpdateWorldVolume(); 494 495 G4ScoringManager* masterScM = G4MTRunManager 496 497 auto particleIterator = G4ParticleTable::Get 498 499 for (G4int iw = 0; iw < nPar; ++iw) { 500 G4VScoringMesh* mesh = ScM->GetMesh(iw); 501 if (fGeometryHasBeenDestroyed) mesh->Geome 502 G4VPhysicalVolume* pWorld = nullptr; 503 if (mesh->GetShape() != MeshShape::realWor 504 pWorld = 505 G4TransportationManager::GetTransporta 506 if (pWorld == nullptr) { 507 G4ExceptionDescription ed; 508 ed << "Mesh name <" << ScM->GetWorldNa 509 G4Exception("G4WorkerRunManager::Const 510 } 511 } 512 if ((mesh->GetMeshElementLogical()) == nul 513 G4AutoLock l(&ConstructScoringWorldsMute 514 G4VScoringMesh* masterMesh = masterScM-> 515 mesh->SetMeshElementLogical(masterMesh-> 516 l.unlock(); 517 518 if (mesh->GetShape() != MeshShape::realW 519 G4ParallelWorldProcess* theParallelWor 520 if (theParallelWorldProcess != nullptr 521 theParallelWorldProcess->SetParallel 522 } 523 else { 524 theParallelWorldProcess = new G4Para 525 mesh->SetParallelWorldProcess(thePar 526 theParallelWorldProcess->SetParallel 527 528 particleIterator->reset(); 529 while ((*particleIterator)()) { 530 G4ParticleDefinition* particle = p 531 G4ProcessManager* pmanager = parti 532 if (pmanager != nullptr) { 533 pmanager->AddProcess(theParallel 534 if (theParallelWorldProcess->IsA 535 pmanager->SetProcessOrdering(t 536 } 537 pmanager->SetProcessOrderingToSe 538 pmanager->SetProcessOrdering(the 539 } // if(pmanager) 540 } // while 541 } 542 theParallelWorldProcess->SetLayeredMat 543 } 544 } 545 mesh->WorkerConstruct(pWorld); 546 } 547 } 548 549 // ------------------------------------------- 550 void G4WorkerRunManager::SetUserInitialization 551 { 552 G4Exception("G4RunManager::SetUserInitializa 553 FatalException, "This method sho 554 } 555 556 // ------------------------------------------- 557 void G4WorkerRunManager::SetUserInitialization 558 { 559 G4Exception("G4RunManager::SetUserInitializa 560 FatalException, "This method sho 561 } 562 563 // ------------------------------------------- 564 void G4WorkerRunManager::SetUserInitialization 565 { 566 G4Exception("G4RunManager::SetUserInitializa 567 FatalException, "This method sho 568 } 569 570 // ------------------------------------------- 571 void G4WorkerRunManager::SetUserInitialization 572 { 573 G4Exception("G4RunManager::SetUserInitializa 574 FatalException, "This method sho 575 } 576 577 // ------------------------------------------- 578 void G4WorkerRunManager::SetUserInitialization 579 { 580 pl->InitializeWorker(); 581 G4RunManager::SetUserInitialization(pl); 582 } 583 584 // ------------------------------------------- 585 void G4WorkerRunManager::SetUserAction(G4UserR 586 { 587 G4RunManager::SetUserAction(userAction); 588 if (userAction != nullptr) userAction->SetMa 589 } 590 591 // ------------------------------------------- 592 void G4WorkerRunManager::SetupDefaultRNGEngine 593 { 594 const CLHEP::HepRandomEngine* mrnge = 595 G4MTRunManager::GetMasterRunManager()->get 596 const G4UserWorkerThreadInitialization* uwti 597 G4MTRunManager::GetMasterRunManager()->Get 598 uwti->SetupRNGEngine(mrnge); 599 } 600 601 // Forward calls (avoid GCC compilation warnin 602 603 // ------------------------------------------- 604 void G4WorkerRunManager::SetUserAction(G4UserE 605 { 606 G4RunManager::SetUserAction(ua); 607 } 608 609 // ------------------------------------------- 610 void G4WorkerRunManager::SetUserAction(G4VUser 611 { 612 G4RunManager::SetUserAction(ua); 613 } 614 615 // ------------------------------------------- 616 void G4WorkerRunManager::SetUserAction(G4UserS 617 { 618 G4RunManager::SetUserAction(ua); 619 } 620 621 // ------------------------------------------- 622 void G4WorkerRunManager::SetUserAction(G4UserT 623 { 624 G4RunManager::SetUserAction(ua); 625 } 626 627 // ------------------------------------------- 628 void G4WorkerRunManager::SetUserAction(G4UserS 629 { 630 G4RunManager::SetUserAction(ua); 631 } 632 633 // ------------------------------------------- 634 void G4WorkerRunManager::StoreRNGStatus(const 635 { 636 std::ostringstream os; 637 os << randomNumberStatusDir << "G4Worker" << 638 G4Random::saveEngineStatus(os.str().c_str()) 639 } 640 641 // ------------------------------------------- 642 void G4WorkerRunManager::rndmSaveThisRun() 643 { 644 G4int runNumber = 0; 645 if (currentRun != nullptr) runNumber = curre 646 if (!storeRandomNumberStatus) { 647 G4cerr << "Warning from G4RunManager::rndm 648 << " Random number status was not s 649 << "/random/setSavingFlag command m 650 << "Command ignored." << G4endl; 651 return; 652 } 653 654 std::ostringstream oos; 655 oos << "G4Worker" << workerContext->GetThrea 656 << "currentRun.rndm" 657 << "\0"; 658 G4fs::path fileIn = randomNumberStatusDir + 659 660 std::ostringstream os; 661 os << "run" << runNumber << ".rndm" << '\0'; 662 G4fs::path fileOut = randomNumberStatusDir + 663 664 if (G4CopyRandomState(fileIn, fileOut, "G4Wo 665 && verboseLevel > 0) 666 { 667 G4cout << fileIn << " is copied to " << fi 668 } 669 } 670 671 // ------------------------------------------- 672 void G4WorkerRunManager::rndmSaveThisEvent() 673 { 674 if (currentEvent == nullptr) { 675 G4cerr << "Warning from G4RunManager::rndm 676 << " there is no currentEvent avail 677 return; 678 } 679 680 if (!storeRandomNumberStatus) { 681 G4cerr << "Warning from G4RunManager::rndm 682 << " Random number engine status is 683 << "/random/setSavingFlag command m 684 << "prior to the start of the run. 685 return; 686 } 687 688 std::ostringstream oos; 689 oos << "G4Worker" << workerContext->GetThrea 690 << "currentEvent.rndm" 691 << "\0"; 692 G4fs::path fileIn = randomNumberStatusDir + 693 694 std::ostringstream os; 695 os << "run" << currentRun->GetRunID() << "ev 696 G4fs::path fileOut = randomNumberStatusDir + 697 698 if (G4CopyRandomState(fileIn, fileOut, "G4Wo 699 && verboseLevel > 0) 700 { 701 G4cout << fileIn << " is copied to " << fi 702 } 703 } 704 705 // ------------------------------------------- 706 void G4WorkerRunManager::DoWork() 707 { 708 G4MTRunManager* mrm = G4MTRunManager::GetMas 709 G4MTRunManager::WorkerActionRequest nextActi 710 while (nextAction != G4MTRunManager::WorkerA 711 if (nextAction == G4MTRunManager::WorkerAc 712 713 { 714 // The following code deals with changin 715 static G4ThreadLocal G4bool skipInitiali 716 if (skipInitialization) { 717 // re-initialization is not necessary 718 skipInitialization = false; 719 } 720 else { 721 // ReinitializeGeometry(); 722 workerContext->UpdateGeometryAndPhysic 723 } 724 725 // Execute UI commands stored in the mas 726 std::vector<G4String> cmds = mrm->GetCom 727 G4UImanager* uimgr = G4UImanager::GetUIp 728 for (const auto& cmd : cmds) { 729 uimgr->ApplyCommand(cmd); 730 } 731 // Start this run 732 G4int numevents = mrm->GetNumberOfEvents 733 G4String macroFile = mrm->GetSelectMacro 734 G4int numSelect = mrm->GetNumberOfSelect 735 if (macroFile.empty() || macroFile == " 736 this->BeamOn(numevents); 737 } 738 else { 739 this->BeamOn(numevents, macroFile, num 740 } 741 } 742 else if (nextAction == G4MTRunManager::Wor 743 std::vector<G4String> cmds = mrm->GetCom 744 G4UImanager* uimgr = G4UImanager::GetUIp 745 for (const auto& cmd : cmds) { 746 uimgr->ApplyCommand(cmd); 747 } 748 mrm->ThisWorkerProcessCommandsStackDone( 749 } 750 else { 751 G4ExceptionDescription d; 752 d << "Cannot continue, this worker has b 753 << static_cast<std::underlying_type<G4 754 G4Exception("G4WorkerRunManager::DoWork" 755 } 756 757 // Now wait for master thread to signal ne 758 nextAction = mrm->ThisWorkerWaitForNextAct 759 } // No more actions to perform 760 761 return; 762 } 763