Import Geant4 11.1.0.beta source tree
This commit is contained in:
@@ -1,6 +1,3 @@
|
||||
# - G4run category build
|
||||
|
||||
# Add (private) allocation export symbol
|
||||
add_definitions(-DG4RUN_ALLOC_EXPORT)
|
||||
|
||||
geant4_global_library_target(COMPONENTS sources.cmake)
|
||||
include(sources.cmake)
|
||||
geant4_add_category(G4run MODULES G4run)
|
||||
|
||||
+34
-19
@@ -1,35 +1,50 @@
|
||||
-------------------------------------------------------------------
|
||||
# Category run History
|
||||
|
||||
=========================================================
|
||||
Geant4 - an Object-Oriented Toolkit for Simulation in HEP
|
||||
=========================================================
|
||||
See `CONTRIBUTING.rst` for details of **required** info/format for each entry,
|
||||
which **must** added in reverse chronological order (newest at the top). It must **not**
|
||||
be used as a substitute for writing good git commit messages!
|
||||
|
||||
Category History file
|
||||
---------------------
|
||||
This file should be used by G4 developers and category coordinators
|
||||
to briefly summarize all major modifications introduced in the code
|
||||
and keep track of all category-tags.
|
||||
It DOES NOT substitute the CVS log-message one should put at every
|
||||
committal in the CVS repository !
|
||||
|
||||
----------------------------------------------------------
|
||||
* Reverse chronological order (last date on top), please *
|
||||
----------------------------------------------------------
|
||||
|
||||
May 17, 2022 Ben Morgan (run-V10-07-15)
|
||||
## 2022-05-17 Ben Morgan (run-V11-00-08)
|
||||
- Apply patches from Seth Johnson:
|
||||
- Check for correct state in default exception handler before trying to access
|
||||
manager classes that may be nullptr in other states
|
||||
- Don't create a default exception manager in run manager kernel if one exists
|
||||
already.
|
||||
|
||||
February 24, 2022 Makoto Asai (run-V10-07-14)
|
||||
## 2022-04-13 Ben Morgan (run-V11-00-07)
|
||||
- Add missing dependency on G4decay, remove unneeded dependency on G4hadronic_util
|
||||
|
||||
## 2022-03-29 Hoang Tran (run-V11-00-06)
|
||||
- Added new DNAScavenger in PhysicsListHelper for DNA processes
|
||||
|
||||
## 2022-03-25 Ben Morgan (run-V11-00-05)
|
||||
- Move implementations of task-based Run interfaces/implementations into Run
|
||||
category from tasking category.
|
||||
- See `History.tasking` file for History of tasking prior this tag of `run`.
|
||||
|
||||
## 2022-02-24 Makoto Asai (run-V11-00-04)
|
||||
- Adding verbosity control to some G4cout. Addressing to bug report #2397.
|
||||
|
||||
December 11, 2021 Laurie Nevay
|
||||
## 2022-01-28 Ben Morgan (run-V11-00-03)
|
||||
- Replace `geant4_global_library_target` with direct file inclusion and
|
||||
call to `geant4_add_category` to define library build from source modules.
|
||||
- Make DLL export symbol a CMake module-level compile definition to aid
|
||||
future modularization
|
||||
|
||||
## 2022-01-18 Jonas Hahnfeld (run-V11-00-02)
|
||||
- Prefer pointer to `const G4Material` if possible
|
||||
|
||||
## 2021-12-11 Laurie Nevay (run-V11-00-01)
|
||||
- Fix missing AnnihToTauTau entry from default physics list ordering that
|
||||
would cause a fatal exception if EmExtra is used with PositronToMuMu=True.
|
||||
|
||||
## 2021-12-10 Ben Morgan (run-V11-00-00)
|
||||
- Change to new Markdown History format
|
||||
|
||||
---
|
||||
|
||||
# History entries prior to 11.0
|
||||
|
||||
October 25, 2021 B.Morgan (run-V10-07-13)
|
||||
- Use G4StrUtil functions replacing deprecated G4String member functions
|
||||
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
# Category tasking History
|
||||
|
||||
See `CONTRIBUTING.rst` for details of **required** info/format for each entry,
|
||||
which **must** added in reverse chronological order (newest at the top). It must **not**
|
||||
be used as a substitute for writing good git commit messages!
|
||||
|
||||
## 2022-03-25 Ben Morgan (tasking-V11-00-04)
|
||||
- Functionality split into global/management (core Task interfaces) and
|
||||
run (implementations). Category retired.
|
||||
|
||||
## 2022-02-24 Makoto Asai (tasking-V11-00-03)
|
||||
- Adding verbosity control to some G4cout. Addressing to bug report #2397.
|
||||
|
||||
## 2022-01-28 Ben Morgan (tasking-V11-00-02)
|
||||
- Replace `geant4_global_library_target` with direct file inclusion and
|
||||
call to `geant4_add_category` to define library build from source modules.
|
||||
- Make DLL export symbol a CMake module-level compile definition to aid
|
||||
future modularization
|
||||
|
||||
## 2022-01-03 Makoto Asai (tasking-V11-00-01)
|
||||
- Fixing number of seeds to be generated for the sedds from master are seeded
|
||||
only once per task.
|
||||
|
||||
## 2021-12-10 Ben Morgan (tasking-V11-00-00)
|
||||
- Change to new Markdown History format
|
||||
|
||||
---
|
||||
|
||||
# History entries prior to 11.0
|
||||
|
||||
September 10th, 2021 Gabriele Cosmo (tasking-V10-07-06)
|
||||
- Added new Ranlux++ engine to the list of supported random engines in
|
||||
G4UserTaskThreadInitialization. Requires CLHEP-2.4.5.1.
|
||||
|
||||
June 6th, 2021 Jonathan Madsen (tasking-V10-07-05)
|
||||
- Check for valid threadPool pointer in
|
||||
G4TaskRunManager::RequestWorkersProcessCommandsStack()
|
||||
(causes seg-fault when ui/viz inited but run not inited)
|
||||
|
||||
May 24th, 2021 Jonathan Madsen (tasking-V10-07-04)
|
||||
- Update to PTL v2.0.0 (shared_ptr usage) included some minor API
|
||||
changes to direct async usage
|
||||
|
||||
May 17th, 2021 Jonathan Madsen (tasking-V10-07-03)
|
||||
- Fixes to TBB task-group usage
|
||||
|
||||
Apr 21st, 2021 Jonathan Madsen (tasking-V10-07-02)
|
||||
- Fix for G4FORCENUMBEROFTHREADS env lookup
|
||||
|
||||
Mar 30th, 2021 Makoto Asai (tasking-V10-07-01)
|
||||
- G4RunManagerFactory : Set default run manager type to Tasking for
|
||||
release 11.0.
|
||||
|
||||
Jan 25th, 2021 Makoto Asai (tasking-V10-07-00)
|
||||
- G4WorkerTaskRunManager.cc : Correct the way to count the number of events
|
||||
processed in a worker thread. This correction also fixes a rare crash due to
|
||||
accessing to the seed vector more than necessary.
|
||||
- G4TaskRunManager.cc : Reduce number of events per task to evenly distribute
|
||||
evnets to all available threads.
|
||||
|
||||
Nov 12th, 2020 Jonathan Madsen (tasking-V10-06-13)
|
||||
- Added G4Profiler support
|
||||
- Removed TIMEMORY_AUTO_TIMER
|
||||
|
||||
Nov 12th, 2020, B. Morgan (tasking-V10-06-12)
|
||||
- G4RunManagerFactory : simplify logic of choosing type from function
|
||||
inputs or environment. Provide new "SerialOnly"... entries for G4RunManagerType
|
||||
to allow users to force use of a specific (but available) type.
|
||||
|
||||
Nov 4th, 2020, M. Asai (tasking-V10-06-11)
|
||||
- G4TaskRunManager.cc : not resetting the run ID counter for the
|
||||
run initialization except the first run.
|
||||
|
||||
Oct 28th, 2020, M. Asai (tasking-V10-06-10)
|
||||
- G4RunManagerFactory : Set default run manager type to MT for
|
||||
release 10.7.
|
||||
|
||||
Oct 20th, 2020, J. Madsen (tasking-V10-06-09)
|
||||
- Implemented GetMasterRunManager in G4RunManagerFactory
|
||||
- Added DoCleanup() for worker task run managers
|
||||
- Replaced worker DoWork(int) with DoWork()
|
||||
- Resolved issues with G4Run number of events to be processed
|
||||
- Resolved issues with G4Run number of events processed
|
||||
|
||||
Sept 23rd, 2020, B. Morgan (tasking-V10-06-08)
|
||||
- Remove no longer required include_directories
|
||||
|
||||
Sept 21st, 2020 J. Madsen (tasking-V10-06-07)
|
||||
- Added checks for currentRun before calling routines with currentRun
|
||||
- updated docs using G4RunManagerCreator instead of G4RunManagerFactory
|
||||
- G4WorkerTaskRunManager: minor tweaks to ProcessUI
|
||||
- G4TaskRunManagerKernel: memory cleanup + initCmdStack
|
||||
- G4TaskRunManager:
|
||||
- appears to fix previous issues with geometry changes
|
||||
- inherited scoring-worlds, master-worlds, fMasterRM data from G4MTRunManager
|
||||
- CreateAndStartWorkers processes command stack on second fakeRun
|
||||
- cleaned up header
|
||||
|
||||
Sept 12th, 2020, J. Madsen (tasking-V10-06-06)
|
||||
- Tasking stability fixes
|
||||
- removed a bunch of excess functions from G4WorkerTaskRunManager
|
||||
- Got rid of regular task group vs. TBB task group implementation
|
||||
- this is thanks to the generic execute_on_all_threads function
|
||||
|
||||
July 17th, 2020, I. Hrivnacova (tasking-V10-06-05)
|
||||
- Adding call to G4VScoreNtupleWriter in G4WorkerTaskRunManager,
|
||||
which missing was causing a break in B4d basic example.
|
||||
|
||||
June 22nd, 2020, G. Cosmo (tasking-V10-06-04)
|
||||
- Fixed recursive inclusion in G4TaskRunManager.
|
||||
|
||||
June 18th, 2020, G. Cosmo (tasking-V10-06-03)
|
||||
- Added DLL macros for Windows build.
|
||||
- Fixed cases of static inline methods and static symbols to export
|
||||
in G4TaskRunManager and G4RunManagerFactory. Some code cleanup for
|
||||
use of G4 types.
|
||||
- Fixed compilation warnings for unused mutexes in G4TaskRunManager
|
||||
and G4WorkerTaskRunManager.
|
||||
|
||||
June 17th, 2020, G. Folger
|
||||
- Fixes for Windows: in G4TaskRunManager, replaced direct access to
|
||||
static data by access functions.
|
||||
|
||||
June 10th, 2020, J. Madsen
|
||||
- Updated README.md
|
||||
- generated README via `pandoc -f markdown -t plain -o README README.md`
|
||||
- generated .README.txt via `pandoc -f markdown -t latex -o .README.txt README.md`
|
||||
|
||||
June 10th, 2020, J. Madsen (tasking-V10-06-02)
|
||||
- Fixed numberOfEventsPerTask < nworker reproducibility
|
||||
- Migrated G4RunManagerCreator to own header/source
|
||||
- cleaned up sources.cmake
|
||||
|
||||
June 4th, 2020, J. Madsen (tasking-V10-06-01)
|
||||
- Added G4TaskRunManager constructor overload taking boolean
|
||||
for whether to use TBB
|
||||
- Added warning if using TBB is requested but no compile support
|
||||
- Default arguments in G4TaskRunManager query G4USE_TBB environment
|
||||
variable to set default bool
|
||||
|
||||
May 28th, 2020, J. Madsen (tasking-V10-06-00)
|
||||
- Created
|
||||
- Added tasking classes:
|
||||
- G4TBBTask
|
||||
- G4TBBTaskGroup
|
||||
- G4Task
|
||||
- G4TaskGroup
|
||||
- G4TaskManager
|
||||
- G4TaskRunManager
|
||||
- G4TaskRunManagerKernel
|
||||
- G4ThreadPool
|
||||
- G4UserTaskInitialization
|
||||
- G4UserTaskQueue
|
||||
- G4UserTaskThreadInitialization
|
||||
- G4VTask
|
||||
- G4VTaskGroup
|
||||
- G4VUserTaskQueue
|
||||
@@ -0,0 +1,226 @@
|
||||
# Geant4 Tasking
|
||||
|
||||
This directory contains a Geant4 run manager which uses a tasking system for the G4Event loop.
|
||||
This tasking system is fully compatible with TBB if `GEANT4_USE_TBB=ON` is specified when
|
||||
configuring CMake. The default behavior, however, is to submit the tasks to an internal
|
||||
thread-pool and task-queue.
|
||||
|
||||
## G4TaskRunManager
|
||||
|
||||
`G4TaskRunManager` multiply inherits from `G4MTRunManager` and `PTL::TaskRunManager`.
|
||||
`PTL::TaskRunManager` holds the thread-pool instance, the size of the thread-pool,
|
||||
and the default task-queue. The constructor of `G4TaskRunManager` takes a `G4VUserTaskQueue`
|
||||
pointer (can be nullptr), a boolean for whether to use TBB if available, and a grainsize.
|
||||
|
||||
### Concepts
|
||||
|
||||
#### Grainsize
|
||||
|
||||
> Environment Variable: `G4FORCE_GRAINSIZE=N`
|
||||
|
||||
The grainsize is essentially the number of tasks. If set to 0, the default grainsize
|
||||
will be `poolSize` and each thread will get `numEvents / poolSize` events.
|
||||
If the grainsize is set to 1, then _all the events_ will be submitted as one task (i.e. be
|
||||
processed serially by one thread in the pool). If the grainsize is set to 50 and there are 500 events,
|
||||
then 50 tasks of 10 events will be submitted.
|
||||
|
||||
#### Events Per Tasks
|
||||
|
||||
> Environment Variable: `G4FORCE_EVENTS_PER_TASK=N`
|
||||
|
||||
Sometimes is easier to specify the number of events in a task instead of the grainsize.
|
||||
If the events-per-task is set to 10 and there are 500 events,
|
||||
then 50 tasks of 10 events will be submitted.
|
||||
|
||||
### Default Constructor
|
||||
|
||||
```cpp
|
||||
G4TaskRunManager(G4VUserTaskQueue* = nullptr, bool useTBB = false, G4int grainsize = 0);
|
||||
```
|
||||
|
||||
## G4RunManagerFactory
|
||||
|
||||
An enumeration `G4RunManagerType` and a function `G4RunManagerFactory::CreateRunManager(...)`
|
||||
was added to `"G4RunManagerFactory.hh"` to simplify the selection of the various run managers.
|
||||
The first parameter is either one of the enumerated `G4RunManagerType` or a string identifier
|
||||
|
||||
| Enumeration | String ID | Class |
|
||||
| ------------------------------- | ----------- | ------------------- |
|
||||
| `G4RunManagerType::Serial` | `"Serial"` | `G4RunManager` |
|
||||
| `G4RunManagerType::MT` | `"MT"` | `G4MTRunManager` |
|
||||
| `G4RunManagerType::Tasking` | `"Tasking"` | `G4TaskRunManager` |
|
||||
| `G4RunManagerType::TBB` | `"TBB"` | `G4TaskRunManager` |
|
||||
| `G4RunManagerType::Default` | `"Default"` | Environment setting |
|
||||
| `G4RunManagerType::SerialOnly` | `"Serial"` | `G4RunManager` |
|
||||
| `G4RunManagerType::MTOnly` | `"MT"` | `G4MTRunManager` |
|
||||
| `G4RunManagerType::TaskingOnly` | `"Tasking"` | `G4TaskRunManager` |
|
||||
| `G4RunManagerType::TBBOnly` | `"TBB"` | `G4TaskRunManager` |
|
||||
|
||||
|
||||
The `Default` enumeration value will defer to the following environment variable `G4RUN_MANAGER_TYPE`
|
||||
if specified and will default to `"MT"` if MT is supported and serial if MT is not supported.
|
||||
If the `G4FORCE_RUN_MANAGER_TYPE` environment variable is set, this variable will override the
|
||||
value passed to the `CreateRunManager` function unless `G4RunManagerType` matches one of the `<TYPE>Only`
|
||||
values. In this case, the environment variable is ignored and the run manager will be `<TYPE>`.
|
||||
|
||||
| Environment Variable | Options | Description |
|
||||
| -------------------------- | ---------------------------------------- | -------------------------------------------------------------------------------------- |
|
||||
| `G4RUN_MANAGER_TYPE` | `"Serial"`, `"MT"`, `"Tasking"`, `"TBB"` | Only applicable when `G4RunManagerType::Default` is used |
|
||||
| `G4FORCE_RUN_MANAGER_TYPE` | `"Serial"`, `"MT"`, `"Tasking"`, `"TBB"` | Will override explicitly specifed `G4RunManagerType` if application allows and fail if type is not available |
|
||||
|
||||
## Creating the G4RunManager
|
||||
|
||||
- The `G4RunManagerFactory::CreateRunManager(...)` function takes either `G4RunManagerType` enumerated type or string to specify the desired G4RunManager
|
||||
- If a string is used, regex matching is used which is case-insensitive
|
||||
- Returns a `G4RunManager*`
|
||||
- Various overloads exist which just reorder passing in:
|
||||
- `int numberOfThreads` - executes `G4MTRunManager::SetNumberOfThreads(numberOfThreads)` before returning if > 0
|
||||
- default: `0`
|
||||
- `bool fail_if_unavail` - will cause a runtime failure if requested type is not available with Geant4 build
|
||||
- default: `true`
|
||||
- `G4VTaskQueue*` - a task-queue manager
|
||||
- default: `nullptr`
|
||||
|
||||
```cpp
|
||||
#include "G4RunManagerFactory.hh"
|
||||
|
||||
int main()
|
||||
{
|
||||
// specify {Serial, MT, Tasking, TBB} as the default, can be overridden
|
||||
// with "G4FORCE_RUN_MANAGER_TYPE" env variable
|
||||
auto* runmanager = G4RunManagerFactory::CreateRunManager(G4RunManagerType::Serial);
|
||||
auto* runmanager = G4RunManagerFactory::CreateRunManager(G4RunManagerType::MT);
|
||||
auto* runmanager = G4RunManagerFactory::CreateRunManager(G4RunManagerType::Tasking);
|
||||
auto* runmanager = G4RunManagerFactory::CreateRunManager(G4RunManagerType::TBB);
|
||||
|
||||
// specify {Serial, MT, Tasking, TBB} as the required type, cannot be overridden
|
||||
// with "G4FORCE_RUN_MANAGER_TYPE" env variable
|
||||
auto* runmanager = G4RunManagerFactory::CreateRunManager(G4RunManagerType::SerialOnly);
|
||||
auto* runmanager = G4RunManagerFactory::CreateRunManager(G4RunManagerType::MTOnly);
|
||||
auto* runmanager = G4RunManagerFactory::CreateRunManager(G4RunManagerType::TaskingOnly);
|
||||
auto* runmanager = G4RunManagerFactory::CreateRunManager(G4RunManagerType::TBBOnly);
|
||||
|
||||
// defer to "G4RUN_MANAGER_TYPE" env variable and default to MT if
|
||||
// env variable is not set
|
||||
auto* runmanager = G4RunManagerFactory::CreateRunManager(G4RunManagerType::Default);
|
||||
|
||||
// same as above
|
||||
auto* runmanager = G4RunManagerFactory::CreateRunManager();
|
||||
}
|
||||
```
|
||||
|
||||
## Using the Tasking System
|
||||
|
||||
With G4TaskRunManager, Geant4 events will be launched asynchronously as tasks. These tasks are
|
||||
placed into a queue until one of the thread in the pool is available to execute the task. Users can
|
||||
take advantage of this system to load-balance expensive sub-event calculations which might have
|
||||
previously resulted in serial bottlenecks. For example, if an application needs to do extensive event
|
||||
analysis on electrons and thread #1 ends up with 10x as many of these events, the other threads
|
||||
might finish their G4Run significantly eariler and be idle while thread #1 has a lot of work.
|
||||
Tasking allows these analysis calculations to be offload back into the queue so that other
|
||||
threads can contribute to their completion.
|
||||
|
||||
### Option 1 - Submit Directly to Thread-Pool
|
||||
|
||||
- To execute the function `foo(int, double)` asynchronously:
|
||||
|
||||
```cpp
|
||||
// get the task manager
|
||||
auto* task_manager = G4TaskRunManager::GetTaskManager();
|
||||
|
||||
// submit task to thread-pool and receive a future for when the result is need
|
||||
std::future<void> _fvoid = task_manager->async<void>(foo, 1, 1.0);
|
||||
std::future<int> _fint = task_manager->async<int>(bar, 1.0);
|
||||
|
||||
// wait for task to execute
|
||||
_fvoid.wait();
|
||||
_fint.wait();
|
||||
|
||||
// get the result (if non-void)
|
||||
auto result = _fint.get();
|
||||
```
|
||||
|
||||
### Option 2 - Submit to task-group
|
||||
|
||||
- Obtain a pointer to the thread-pool instance
|
||||
- Create a `task_group<T>` object where `T` is the return type of all the functions in the group
|
||||
- If `T` is non-void, you must provide a join functor who return type and first argument are both references
|
||||
to the joined type and the second argument is type `T`, e.g. `task_group<int>` can provide a join functor
|
||||
with `vector<int>&` as the return type and `T` as the second argument or `int&` as the return and first argument
|
||||
and `int` as the second argument
|
||||
- If `T` is void, the join functor is optional and can be treated as a final synchronization operation after
|
||||
all the tasks have been completed.
|
||||
|
||||
> NOTE: The join functor for task-groups are called sequentially on the thread that is
|
||||
> waiting on `task_group<T>::join()` member function.
|
||||
|
||||
#### Global Definitions for Examples
|
||||
|
||||
```cpp
|
||||
// obtain thread-pool instance from task manager
|
||||
static auto* thread_pool = G4TaskRunManager::GetThreadPool();
|
||||
|
||||
// trivial int function which just returns value passed
|
||||
int foo(int v) { return v; }
|
||||
|
||||
// function which launches CUDA kernel
|
||||
void bar(int v)
|
||||
{
|
||||
cuda_bar<<<512, 1>>>(v);
|
||||
}
|
||||
```
|
||||
|
||||
#### Example with non-void return types from tasks
|
||||
|
||||
```cpp
|
||||
// put all return values from tasks into an array
|
||||
auto join_vec = [](std::vector<int>& lhs, int rhs) { lhs.push_back(rhs); return lhs; };
|
||||
|
||||
// sum the values returned by tasks
|
||||
auto sum_int = [](int& lhs, int rhs) { return lhs += rhs; };
|
||||
|
||||
// task group which applies 'join_vec' to all task return values
|
||||
task_group<int> vec_tg(join_vec, thread_pool);
|
||||
// task group with applies 'sum_int' to all task return values
|
||||
task_group<int> sum_tg(sum_int, thread_pool);
|
||||
|
||||
// submit work to task-groups
|
||||
vec_tg.exec(foo, 1);
|
||||
vec_tg.exec(foo, 2);
|
||||
sum_tg.exec(foo, 1);
|
||||
sum_tg.exec(foo, 2);
|
||||
|
||||
// produces std::vector{ 1, 2 };
|
||||
auto vec_result = vec_tg.join();
|
||||
|
||||
// produces 1 + 2 = 3
|
||||
auto sum_result = sum_tg.join();
|
||||
```
|
||||
|
||||
#### Example with void return type from tasks
|
||||
|
||||
```cpp
|
||||
// wait for the GPU to finish
|
||||
auto sync = []() { cudaDeviceSynchronize(); };
|
||||
|
||||
// task group which applies 'sync' after all tasks have been executed
|
||||
task_group<void> gpu_tg(sync, thread_pool);
|
||||
// generic task group w/o a join functor
|
||||
task_group<void> general_tg(thread_pool);
|
||||
|
||||
// submit work to task-groups
|
||||
gpu_tg.exec(bar, 1);
|
||||
gpu_tg.exec(bar, 2);
|
||||
general_tg.exec(bar, 1);
|
||||
general_tg.exec(bar, 2);
|
||||
|
||||
// 'sync()' will get called after all tasks in group have executed
|
||||
// (i.e. return from 'bar' function). 'sync' will then block until
|
||||
// all GPU work has been completed
|
||||
gpu_tg.join();
|
||||
|
||||
// will block only until all tasks in group have been executed
|
||||
// (i.e. returned from 'bar' function)
|
||||
generic_tg.join();
|
||||
|
||||
```
|
||||
@@ -0,0 +1,105 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
// Author: Jonathan Madsen (May 28th 2020)
|
||||
//
|
||||
// class description:
|
||||
// This is a class creates a G4RunManager instance. Once can specify an
|
||||
// enumerated value to set the default. If "G4RunManagerType::Default"
|
||||
// is used,
|
||||
//
|
||||
|
||||
#ifndef G4RunManagerFactory_hh
|
||||
#define G4RunManagerFactory_hh 1
|
||||
|
||||
#include "G4Types.hh"
|
||||
#include "G4RunManager.hh"
|
||||
#include "G4MTRunManager.hh"
|
||||
#include "G4TaskRunManager.hh"
|
||||
#include "G4VUserTaskQueue.hh"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
//============================================================================//
|
||||
|
||||
enum class G4RunManagerType : G4int
|
||||
{
|
||||
Serial = 0,
|
||||
SerialOnly = 1,
|
||||
MT = 2,
|
||||
MTOnly = 3,
|
||||
Tasking = 4,
|
||||
TaskingOnly = 5,
|
||||
TBB = 6,
|
||||
TBBOnly = 7,
|
||||
Default
|
||||
};
|
||||
|
||||
//============================================================================//
|
||||
|
||||
class G4RunManagerFactory
|
||||
{
|
||||
public:
|
||||
static G4RunManager* CreateRunManager(
|
||||
G4RunManagerType _type = G4RunManagerType::Default,
|
||||
G4VUserTaskQueue* _queue = nullptr, G4bool fail_if_unavail = true,
|
||||
G4int nthreads = 0);
|
||||
|
||||
// provide a version which specifies to fail if unavailable
|
||||
static G4RunManager* CreateRunManager(G4RunManagerType _type,
|
||||
G4bool fail_if_unavail,
|
||||
G4int nthreads = 0,
|
||||
G4VUserTaskQueue* _queue = nullptr)
|
||||
{
|
||||
return CreateRunManager(_type, _queue, fail_if_unavail, nthreads);
|
||||
}
|
||||
|
||||
static G4RunManager* CreateRunManager(G4RunManagerType _type, G4int nthreads,
|
||||
G4bool fail_if_unavail = true,
|
||||
G4VUserTaskQueue* _queue = nullptr)
|
||||
{
|
||||
return CreateRunManager(_type, _queue, fail_if_unavail, nthreads);
|
||||
}
|
||||
|
||||
// provide string versions of above
|
||||
template <typename... Args>
|
||||
static G4RunManager* CreateRunManager(std::string type, Args&&... args)
|
||||
{
|
||||
return CreateRunManager(GetType(type), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
static std::string GetDefault();
|
||||
static std::string GetName(G4RunManagerType);
|
||||
static G4RunManagerType GetType(const std::string&);
|
||||
static std::set<std::string> GetOptions();
|
||||
static G4RunManager* GetMasterRunManager();
|
||||
static G4MTRunManager* GetMTMasterRunManager();
|
||||
static G4RunManagerKernel* GetMasterRunManagerKernel();
|
||||
};
|
||||
|
||||
#endif // G4TaskRunManagerCreator_h
|
||||
@@ -0,0 +1,243 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
// Author: Jonathan Madsen (May 28st 2020)
|
||||
//
|
||||
// class description:
|
||||
// This is a class for run control in GEANT4 for multi-threaded runs
|
||||
// It extends G4RunManager re-implementing multi-threaded behavior in
|
||||
// key methods. See documentation for G4RunManager
|
||||
// Users initializes an instance of this class instead of G4RunManager
|
||||
// to start a multi-threaded simulation.
|
||||
|
||||
#ifndef G4TaskRunManager_hh
|
||||
#define G4TaskRunManager_hh 1
|
||||
|
||||
#include "rundefs.hh"
|
||||
#include "G4MTBarrier.hh"
|
||||
#include "G4MTRunManager.hh"
|
||||
#include "G4RNGHelper.hh"
|
||||
#include "G4RunManager.hh"
|
||||
#include "G4TBBTaskGroup.hh"
|
||||
#include "G4TaskGroup.hh"
|
||||
#include "G4TaskManager.hh"
|
||||
#include "G4ThreadPool.hh"
|
||||
#include "G4Threading.hh"
|
||||
#include "G4VUserTaskQueue.hh"
|
||||
#include "G4EnvironmentUtils.hh"
|
||||
#include "G4Profiler.hh"
|
||||
|
||||
#include "PTL/TaskRunManager.hh"
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
class G4TaskRunManagerKernel;
|
||||
class G4ScoringManager;
|
||||
class G4UserTaskInitialization;
|
||||
class G4UserTaskThreadInitialization;
|
||||
class G4WorkerTaskRunManager;
|
||||
class G4RunManagerFactory;
|
||||
|
||||
//============================================================================//
|
||||
|
||||
class G4TaskRunManager
|
||||
: public G4MTRunManager
|
||||
, public PTL::TaskRunManager
|
||||
{
|
||||
friend class G4RunManagerFactory;
|
||||
|
||||
public:
|
||||
// the profiler aliases are only used when compiled with GEANT4_USE_TIMEMORY
|
||||
using ProfilerConfig = G4ProfilerConfig<G4ProfileType::Run>;
|
||||
|
||||
public:
|
||||
using InitializeSeedsCallback = std::function<G4bool(G4int, G4int&, G4int&)>;
|
||||
using RunTaskGroup = G4TaskGroup<void>;
|
||||
|
||||
public:
|
||||
// Parameters:
|
||||
// taskQueue : provide a custom task queue
|
||||
// useTBB : only relevant if GEANT4_USE_TBB defined
|
||||
// evtGrainsize : the number of events per task
|
||||
G4TaskRunManager(G4bool useTBB = G4GetEnv<G4bool>("G4USE_TBB", false));
|
||||
G4TaskRunManager(G4VUserTaskQueue* taskQueue,
|
||||
G4bool useTBB = G4GetEnv<G4bool>("G4USE_TBB", false),
|
||||
G4int evtGrainsize = 0);
|
||||
virtual ~G4TaskRunManager();
|
||||
|
||||
public:
|
||||
void SetGrainsize(G4int n) { eventGrainsize = n; }
|
||||
G4int GetGrainsize() const { return eventGrainsize; }
|
||||
inline G4int GetNumberOfTasks() const { return numberOfTasks; }
|
||||
inline G4int GetNumberOfEventsPerTask() const
|
||||
{
|
||||
return numberOfEventsPerTask;
|
||||
}
|
||||
|
||||
virtual void SetNumberOfThreads(G4int n) override;
|
||||
virtual G4int GetNumberOfThreads() const override
|
||||
{
|
||||
return PTL::TaskRunManager::GetNumberOfThreads();
|
||||
}
|
||||
virtual size_t GetNumberActiveThreads() const override
|
||||
{
|
||||
return PTL::TaskRunManager::GetNumberActiveThreads();
|
||||
}
|
||||
static G4ThreadId GetMasterThreadId();
|
||||
|
||||
public:
|
||||
// Inherited methods to re-implement for MT case
|
||||
virtual void Initialize() override;
|
||||
virtual void InitializeEventLoop(G4int n_event,
|
||||
const char* macroFile = nullptr,
|
||||
G4int n_select = -1) override;
|
||||
virtual void InitializeThreadPool() override;
|
||||
G4bool ThreadPoolIsInitialized() const { return poolInitialized; }
|
||||
|
||||
virtual void Initialize(uint64_t nthreads) override
|
||||
{
|
||||
PTL::TaskRunManager::Initialize(nthreads);
|
||||
}
|
||||
|
||||
virtual void TerminateOneEvent() override;
|
||||
virtual void ProcessOneEvent(G4int i_event) override;
|
||||
virtual void ConstructScoringWorlds() override;
|
||||
virtual void RunTermination() override;
|
||||
|
||||
// The following method should be invoked by G4WorkerTaskRunManager for each
|
||||
// event. False is returned if no more event to be processed. Note: G4Event
|
||||
// object must be instantiated by a worker thread. In case no more
|
||||
// event remains to be processed, that worker thread must delete that G4Event
|
||||
// object. If a worker runs with its own random number sequence, the Boolean
|
||||
// flag reseedRequired should be set to false. This is *NOT* allowed for the
|
||||
// first event.
|
||||
virtual G4bool SetUpAnEvent(G4Event*, G4long& s1, G4long& s2, G4long& s3,
|
||||
G4bool reseedRequired = true) override;
|
||||
// Same as above method, but the seeds are set only once over "eventModulo"
|
||||
// events. The return value shows the number of events the caller Worker has
|
||||
// to process (between 1 and eventModulo depending on number of events yet to
|
||||
// be processed). G4Event object has the event ID of the first event of this
|
||||
// bunch. If zero is returned no more event needs to be processed, and worker
|
||||
// thread must delete that G4Event.
|
||||
virtual G4int SetUpNEvents(G4Event*, G4SeedsQueue* seedsQueue,
|
||||
G4bool reseedRequired = true) override;
|
||||
|
||||
// Method called by Initialize() method
|
||||
|
||||
protected:
|
||||
virtual void ComputeNumberOfTasks();
|
||||
// Initialize the seeds list, if derived class does not implement this method
|
||||
// A default generation will be used (nevents*2 random seeds)
|
||||
// Return true if initialization is done.
|
||||
virtual G4bool InitializeSeeds(G4int /*nevts*/) override { return false; }
|
||||
virtual void RefillSeeds() override;
|
||||
// Adds one seed to the list of seeds
|
||||
virtual void StoreRNGStatus(const G4String& filenamePrefix) override;
|
||||
virtual void CreateAndStartWorkers() override;
|
||||
// Creates worker threads and signal to start
|
||||
|
||||
protected:
|
||||
virtual void TerminateWorkers() override;
|
||||
|
||||
public: // with description
|
||||
static G4TaskRunManager* GetMasterRunManager()
|
||||
{
|
||||
auto* _rm = G4MTRunManager::GetMasterRunManager();
|
||||
return dynamic_cast<G4TaskRunManager*>(_rm);
|
||||
}
|
||||
// Returns the singleton instance of the run manager common to all threads
|
||||
// implementing the master behavior
|
||||
static G4TaskRunManagerKernel* GetMTMasterRunManagerKernel();
|
||||
// Returns the singleton instance of the run manager kernel common to all
|
||||
// threads
|
||||
|
||||
public:
|
||||
// To be invoked solely from G4WorkerTaskRunManager to merge the results
|
||||
void MergeScores(const G4ScoringManager* localScoringManager);
|
||||
void MergeRun(const G4Run* localRun);
|
||||
|
||||
public:
|
||||
virtual void RequestWorkersProcessCommandsStack() override;
|
||||
// Called to force workers to request and process the UI commands stack
|
||||
// This will block untill all workers have processed UI commands
|
||||
virtual void ThisWorkerProcessCommandsStackDone() override;
|
||||
// Called by workers to signal to master it has completed processing of
|
||||
// UI commands
|
||||
// virtual WorkerActionRequest ThisWorkerWaitForNextAction();
|
||||
// Worker thread barrier
|
||||
// This method should be used by workers' run manager to wait,
|
||||
// after an event loop for the next action to be performed
|
||||
// (for example execute a new run)
|
||||
// This returns the action to be performed
|
||||
virtual void WaitForReadyWorkers() override {}
|
||||
virtual void WaitForEndEventLoopWorkers() override;
|
||||
virtual void ThisWorkerReady() override {}
|
||||
virtual void ThisWorkerEndEventLoop() override {}
|
||||
virtual WorkerActionRequest ThisWorkerWaitForNextAction() override
|
||||
{
|
||||
return WorkerActionRequest::UNDEFINED;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void NewActionRequest(WorkerActionRequest) override {}
|
||||
virtual void AddEventTask(G4int);
|
||||
|
||||
public:
|
||||
inline void SetInitializeSeedsCallback(InitializeSeedsCallback f)
|
||||
{
|
||||
initSeedsCallback = f;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void AbortRun(G4bool softAbort = false) override;
|
||||
virtual void AbortEvent() override;
|
||||
|
||||
private:
|
||||
// grainsize
|
||||
bool workersStarted = false;
|
||||
G4int eventGrainsize = 0;
|
||||
G4int numberOfEventsPerTask = -1;
|
||||
G4int numberOfTasks = -1;
|
||||
CLHEP::HepRandomEngine* masterRNGEngine = nullptr;
|
||||
// Pointer to the master thread random engine
|
||||
G4TaskRunManagerKernel* MTkernel = nullptr;
|
||||
|
||||
protected:
|
||||
// Barriers: synch points between master and workers
|
||||
RunTaskGroup* workTaskGroup = nullptr;
|
||||
|
||||
// aliases to inherited member values
|
||||
G4bool& poolInitialized = PTL::TaskRunManager::m_is_initialized;
|
||||
G4ThreadPool*& threadPool = PTL::TaskRunManager::m_thread_pool;
|
||||
G4VUserTaskQueue*& taskQueue = PTL::TaskRunManager::m_task_queue;
|
||||
G4TaskManager*& taskManager = PTL::TaskRunManager::m_task_manager;
|
||||
|
||||
InitializeSeedsCallback initSeedsCallback = [](G4int, G4int&, G4int&) {
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
#endif // G4TaskRunManager_hh
|
||||
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
// Author: Jonathan Madsen (May 28st 2020)
|
||||
//
|
||||
// class description:
|
||||
//
|
||||
// This is a class for mandatory control of GEANT4 kernel.
|
||||
// This class implements Worker behavior in a MT application.
|
||||
//
|
||||
// This class is constructed by G4TaskRunManager. If a user uses his/her own
|
||||
// class instead of G4TaskRunManager, this class must be instantiated by
|
||||
// him/herself at the very beginning of the application and must be deleted
|
||||
// at the very end of the application. Also, following methods must be
|
||||
// invoked in the proper order.
|
||||
// DefineWorldVolume
|
||||
// InitializePhysics
|
||||
// RunInitialization
|
||||
// RunTermination
|
||||
//
|
||||
// User must provide his/her own classes derived from the following
|
||||
// abstract class and register it to the RunManagerKernel.
|
||||
// G4VUserPhysicsList - Particle types, Processes and Cuts
|
||||
//
|
||||
// G4TaskRunManagerKernel does not have any eveny loop. Handling of events
|
||||
// is managed by G4RunManager.
|
||||
//
|
||||
// This class re-implements only the method that require special treatment
|
||||
// to implement worker behavior
|
||||
|
||||
#ifndef G4TaskRunManagerKernel_hh
|
||||
#define G4TaskRunManagerKernel_hh 1
|
||||
|
||||
#include "rundefs.hh"
|
||||
#include "G4RunManagerKernel.hh"
|
||||
#include "G4TaskRunManager.hh"
|
||||
#include "G4Threading.hh"
|
||||
|
||||
class G4WorkerThread;
|
||||
class G4WorkerTaskRunManager;
|
||||
#include <vector>
|
||||
|
||||
class G4TaskRunManagerKernel : public G4RunManagerKernel
|
||||
{
|
||||
public:
|
||||
G4TaskRunManagerKernel();
|
||||
virtual ~G4TaskRunManagerKernel();
|
||||
|
||||
public: // with descroption
|
||||
static G4WorkerThread* GetWorkerThread();
|
||||
// G4ThreadPool tasks
|
||||
static void InitializeWorker();
|
||||
static void ExecuteWorkerInit();
|
||||
static void ExecuteWorkerTask();
|
||||
static void TerminateWorkerRunEventLoop();
|
||||
static void TerminateWorker();
|
||||
static void TerminateWorkerRunEventLoop(G4WorkerTaskRunManager*);
|
||||
static void TerminateWorker(G4WorkerTaskRunManager*);
|
||||
|
||||
static std::vector<G4String>& InitCommandStack();
|
||||
// Fill decay tables with particle definition pointers of
|
||||
// decay products. This method has to be invoked by
|
||||
// MTRunManager before event loop starts on workers.
|
||||
void SetUpDecayChannels();
|
||||
// This method should be invoked by G4TaskRunManager
|
||||
void BroadcastAbortRun(G4bool softAbort);
|
||||
|
||||
protected:
|
||||
void SetupShadowProcess() const;
|
||||
G4RUN_DLL static std::vector<G4String> initCmdStack;
|
||||
};
|
||||
|
||||
#endif // G4TaskRunManagerKernel_hh
|
||||
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// Author: Jonathan Madsen (May 28st 2020)
|
||||
//
|
||||
// class description:
|
||||
//
|
||||
// This class is used for multi-threaded Geant4.
|
||||
// The object of this class can be set to G4MTRunManager, but not to
|
||||
// G4RunManager. G4UserTaskInitialization class has five virtual methods as
|
||||
// the user hooks which are invoked at several occasions of the life cycle
|
||||
// of each thread.
|
||||
//
|
||||
// - virtual void WorkerInitialize() const
|
||||
// This method is called after the tread is created but before the
|
||||
// G4WorkerTaskRunManager is instantiated.
|
||||
// - virtual void WorkerStart() const
|
||||
// This method is called once at the beginning of simulation job when
|
||||
// kernel classes and user action classes have already instantiated but
|
||||
// geometry and physics have not been yet initialized. This situation is
|
||||
// identical to "PreInit" state in the sequential mode.
|
||||
// - virtual void WorkerRunStart() const
|
||||
// This method is called before an event loop. Geometry and physics have
|
||||
// already been set up for the thread. All threads are synchronized and
|
||||
// ready to start the local event loop. This situation is identical to
|
||||
// "Idle" state in the sequential mode.
|
||||
// - virtual void WorkerRunEnd() const
|
||||
// This method is called for each thread when the local event loop is
|
||||
// done, but before the synchronization over threads.
|
||||
// - virtual void WorkerStop() const
|
||||
// This method is called once at the end of simulation job.
|
||||
//
|
||||
// Note: This object should be instantiated only once and set to
|
||||
// G4MTRunManager,
|
||||
// while these five methods are invoked for each worker thread. Thus, to
|
||||
// store thread-local objects, use G4ThreadLocal keyword.
|
||||
//
|
||||
|
||||
#ifndef G4UserTaskInitialization_hh
|
||||
#define G4UserTaskInitialization_hh
|
||||
|
||||
#include "G4UserWorkerInitialization.hh"
|
||||
|
||||
class G4UserTaskInitialization : public G4UserWorkerInitialization
|
||||
{
|
||||
public: // with description
|
||||
G4UserTaskInitialization();
|
||||
virtual ~G4UserTaskInitialization();
|
||||
|
||||
virtual void WorkerInitialize() const;
|
||||
// This method is called after the tread is created but before the
|
||||
// G4WorkerTaskRunManager is instantiated.
|
||||
|
||||
virtual void WorkerStart() const;
|
||||
// This method is called once at the beginning of simulation job
|
||||
// when kernel classes and user action classes have already instantiated
|
||||
// but geometry and physics have not been yet initialized. This situation
|
||||
// is identical to "PreInit" state in the sequential mode.
|
||||
|
||||
virtual void WorkerRunStart() const;
|
||||
// This method is called before an event loop. Geometry and physics have
|
||||
// already been set up for the thread. All threads are synchronized and
|
||||
// ready to start the local event loop. This situation is identical to
|
||||
// "Idle" state in the sequential mode.
|
||||
|
||||
virtual void WorkerRunEnd() const;
|
||||
// This method is called for each thread, when the local event loop has
|
||||
// finished but before the synchronization over threads.
|
||||
|
||||
virtual void WorkerStop() const;
|
||||
// This method is called once at the end of simulation job.
|
||||
// Implement here a clean up action.
|
||||
};
|
||||
|
||||
#endif // G4UserTaskInitialization_hh
|
||||
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
// Author: Jonathan Madsen (May 28st 2020)
|
||||
//
|
||||
// class description:
|
||||
//
|
||||
// This class is used for multi-threaded Geant4.
|
||||
// It encapsulates the mechanism of starting/stopping threads.
|
||||
|
||||
#ifndef G4UserTaskThreadInitialization_hh
|
||||
#define G4UserTaskThreadInitialization_hh
|
||||
|
||||
class G4VUserPrimaryGeneratorAction;
|
||||
class G4UserRunAction;
|
||||
class G4UserEventAction;
|
||||
class G4UserStackingAction;
|
||||
class G4UserTrackingAction;
|
||||
class G4UserSteppingAction;
|
||||
|
||||
class G4WorkerThread;
|
||||
class G4WorkerTaskRunManager;
|
||||
|
||||
#include "G4Threading.hh"
|
||||
#include "G4UserWorkerThreadInitialization.hh"
|
||||
#include "Randomize.hh"
|
||||
|
||||
class G4UserTaskThreadInitialization : public G4UserWorkerThreadInitialization
|
||||
{
|
||||
public: // with description
|
||||
G4UserTaskThreadInitialization();
|
||||
virtual ~G4UserTaskThreadInitialization();
|
||||
|
||||
virtual G4Thread* CreateAndStartWorker(G4WorkerThread* workerThreadContext);
|
||||
// Called by the kernel to create a new thread/worker
|
||||
// and start work.
|
||||
// Usere should not re-implement this function (in derived class), except only
|
||||
// if he/she wants to verwrite the default threading model (see StartThread
|
||||
// function)
|
||||
|
||||
virtual void SetupRNGEngine(const CLHEP::HepRandomEngine* aRNGEngine) const;
|
||||
// Called by worker threads to set the Random Number Generator Engine
|
||||
// The default implementation "clones" the engine from the master thread
|
||||
// User needs to re-implement this method if using a non-standard
|
||||
// RNG Engine (i.e. a different one w.r.t. the one provided in the CLHEP
|
||||
// version supported by G4.
|
||||
// Important: this method is called by all threads at the same time
|
||||
// if is user responsibilitiy to make it thread-safe
|
||||
|
||||
virtual void JoinWorker(G4Thread* aThread);
|
||||
// Called by the kernel when threads need to be terminated. Implements logic
|
||||
// of joining the aThread. Calling thread will wait for aThread to end. Usere
|
||||
// should not re-implement this function (in derived class), except only if
|
||||
// he/she wants to verwrite the default threading model (see StartThread
|
||||
// function)
|
||||
|
||||
virtual G4WorkerRunManager* CreateWorkerRunManager() const;
|
||||
// Called by StartThread function to create a run-manager implementing worker
|
||||
// behvior. User should re-implemtn this function in derived class to
|
||||
// instantiate his/her user-defined WorkerRunManager. By default this method
|
||||
// instantiates G4WorkerTaskRunManager object.
|
||||
};
|
||||
|
||||
#endif // G4UserTaskThreadInitialization_hh
|
||||
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// Author: Jonathan Madsen (May 28st 2020)
|
||||
//
|
||||
// class description:
|
||||
//
|
||||
// This is a class for run control in GEANT4 for multi-threaded runs
|
||||
// It extends G4RunManager re-implementing multi-threaded behavior in
|
||||
// key methods. See documentation for G4RunManager. User should never
|
||||
// initialize instances of this class, that are usually handled by
|
||||
// G4MTRunManager. There exists one instance of this class for each
|
||||
// worker in a MT application.
|
||||
|
||||
#ifndef G4WorkerTaskRunManager_h
|
||||
#define G4WorkerTaskRunManager_h 1
|
||||
|
||||
#include "G4RNGHelper.hh"
|
||||
#include "G4RunManager.hh"
|
||||
#include "G4WorkerRunManager.hh"
|
||||
|
||||
class G4WorkerThread;
|
||||
class G4WorkerTaskRunManagerKernel;
|
||||
|
||||
class G4WorkerTaskRunManager : public G4WorkerRunManager
|
||||
{
|
||||
public:
|
||||
using ProfilerConfig = G4ProfilerConfig<G4ProfileType::Run>;
|
||||
|
||||
public:
|
||||
typedef std::vector<G4String> G4StrVector;
|
||||
|
||||
public:
|
||||
static G4WorkerTaskRunManager* GetWorkerRunManager();
|
||||
static G4WorkerTaskRunManagerKernel* GetWorkerRunManagerKernel();
|
||||
G4WorkerTaskRunManager();
|
||||
|
||||
// Modified for worker behavior
|
||||
virtual void RunInitialization() override;
|
||||
virtual void DoEventLoop(G4int n_event, const char* macroFile = nullptr,
|
||||
G4int n_select = -1) override;
|
||||
virtual void ProcessOneEvent(G4int i_event) override;
|
||||
virtual G4Event* GenerateEvent(G4int i_event) override;
|
||||
virtual void RunTermination() override;
|
||||
virtual void TerminateEventLoop() override;
|
||||
virtual void DoWork() override;
|
||||
virtual void RestoreRndmEachEvent(G4bool flag) override
|
||||
{
|
||||
readStatusFromFile = flag;
|
||||
}
|
||||
|
||||
virtual void DoCleanup();
|
||||
virtual void ProcessUI();
|
||||
G4WorkerThread* GetWorkerThread() const { return workerContext; }
|
||||
G4StrVector GetCommandStack() const { return processedCommandStack; }
|
||||
|
||||
protected:
|
||||
virtual void StoreRNGStatus(const G4String& filenamePrefix) override;
|
||||
|
||||
private:
|
||||
void SetupDefaultRNGEngine();
|
||||
|
||||
private:
|
||||
G4StrVector processedCommandStack;
|
||||
|
||||
private:
|
||||
std::unique_ptr<ProfilerConfig> workerRunProfiler;
|
||||
};
|
||||
|
||||
#endif // G4WorkerTaskRunManager_h
|
||||
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
// Author: Jonathan Madsen (May 28st 2020)
|
||||
//
|
||||
// class description:
|
||||
//
|
||||
// This is a class for mandatory control of GEANT4 kernel.
|
||||
// This class implements Worker behavior in a MT application.
|
||||
//
|
||||
// This class is constructed by G4WorkerTaskRunManager. If a user uses
|
||||
// his/her own class instead of G4WorkerTaskRunManager, this class must be
|
||||
// instantiated by him/herself at the very beginning of the application and
|
||||
// must be deleted at the very end of the application. Also, following
|
||||
// methods must be invoked in the proper order.
|
||||
// DefineWorldVolume
|
||||
// InitializePhysics
|
||||
// RunInitialization
|
||||
// RunTermination
|
||||
//
|
||||
// User must provide his/her own classes derived from the following
|
||||
// abstract class and register it to the RunManagerKernel.
|
||||
// G4VUserPhysicsList - Particle types, Processes and Cuts
|
||||
//
|
||||
// G4WorkerTaskRunManagerKernel does not have any eveny loop. Handling of
|
||||
// events is managed by G4RunManager.
|
||||
//
|
||||
// This class re-implements only the method that require special treatment
|
||||
// to implement worker behavior
|
||||
//
|
||||
|
||||
#ifndef G4WorkerTaskRunManagerKernel_h
|
||||
#define G4WorkerTaskRunManagerKernel_h 1
|
||||
|
||||
#include "G4RunManagerKernel.hh"
|
||||
|
||||
class G4WorkerTaskRunManagerKernel : public G4RunManagerKernel
|
||||
{
|
||||
public:
|
||||
G4WorkerTaskRunManagerKernel();
|
||||
virtual ~G4WorkerTaskRunManagerKernel();
|
||||
|
||||
protected:
|
||||
// Overwrite default behavior
|
||||
void SetupShadowProcess() const;
|
||||
};
|
||||
|
||||
#endif // G4WorkerTaskRunManagerKernel_h
|
||||
+37
-22
@@ -7,72 +7,88 @@ geant4_add_module(G4run
|
||||
G4AdjointSimManager.hh
|
||||
G4AdjointSimMessenger.hh
|
||||
G4ExceptionHandler.hh
|
||||
G4MSSteppingAction.hh
|
||||
G4MatScanMessenger.hh
|
||||
G4MaterialScanner.hh
|
||||
G4MatScanMessenger.hh
|
||||
G4MSSteppingAction.hh
|
||||
G4MTRunManager.hh
|
||||
G4MTRunManagerKernel.hh
|
||||
G4MultiRunAction.hh
|
||||
G4PhysicsBuilderInterface.hh
|
||||
G4PhysicsListHelper.hh
|
||||
G4PhysicsListOrderingParameter.hh
|
||||
G4PhysicsListWorkspace.hh
|
||||
G4RNGHelper.hh
|
||||
G4Run.hh
|
||||
G4RunManagerFactory.hh
|
||||
G4RunManager.hh
|
||||
G4MTRunManager.hh
|
||||
G4WorkerRunManager.hh
|
||||
G4RunManagerKernel.hh
|
||||
G4MTRunManagerKernel.hh
|
||||
G4WorkerRunManagerKernel.hh
|
||||
G4RunMessenger.hh
|
||||
G4TaskRunManager.hh
|
||||
G4TaskRunManagerKernel.hh
|
||||
G4UserPhysicsListMessenger.hh
|
||||
G4UserRunAction.hh
|
||||
G4MultiRunAction.hh
|
||||
G4UserTaskInitialization.hh
|
||||
G4UserTaskThreadInitialization.hh
|
||||
G4UserWorkerInitialization.hh
|
||||
G4UserWorkerThreadInitialization.hh
|
||||
G4VModularPhysicsList.hh
|
||||
G4VPersistencyManager.hh
|
||||
G4VPhysicsConstructor.hh
|
||||
G4VUPLSplitter.hh
|
||||
G4VUserActionInitialization.hh
|
||||
G4VUserDetectorConstruction.hh
|
||||
G4VUserParallelWorld.hh
|
||||
G4VUserPhysicsList.hh
|
||||
G4VUserPrimaryGeneratorAction.hh
|
||||
G4WorkerRunManager.hh
|
||||
G4WorkerRunManagerKernel.hh
|
||||
G4WorkerTaskRunManager.hh
|
||||
G4WorkerTaskRunManagerKernel.hh
|
||||
G4WorkerThread.hh
|
||||
G4VUPLSplitter.hh
|
||||
rundefs.hh
|
||||
G4RNGHelper.hh
|
||||
G4PhysicsBuilderInterface.hh
|
||||
SOURCES
|
||||
G4AdjointPrimaryGeneratorAction.cc
|
||||
G4AdjointSimManager.cc
|
||||
G4AdjointSimMessenger.cc
|
||||
G4ExceptionHandler.cc
|
||||
G4MSSteppingAction.cc
|
||||
G4MatScanMessenger.cc
|
||||
G4MaterialScanner.cc
|
||||
G4MatScanMessenger.cc
|
||||
G4MSSteppingAction.cc
|
||||
G4MTRunManager.cc
|
||||
G4MTRunManagerKernel.cc
|
||||
G4MultiRunAction.cc
|
||||
G4PhysicsListHelper.cc
|
||||
G4PhysicsListOrderingParamater.cc
|
||||
G4PhysicsListWorkspace.cc
|
||||
G4RNGHelper.cc
|
||||
G4Run.cc
|
||||
G4RunManager.cc
|
||||
G4MTRunManager.cc
|
||||
G4WorkerRunManager.cc
|
||||
G4RunManagerFactory.cc
|
||||
G4RunManagerKernel.cc
|
||||
G4MTRunManagerKernel.cc
|
||||
G4WorkerRunManagerKernel.cc
|
||||
G4RunMessenger.cc
|
||||
G4TaskRunManager.cc
|
||||
G4TaskRunManagerKernel.cc
|
||||
G4UserPhysicsListMessenger.cc
|
||||
G4UserRunAction.cc
|
||||
G4MultiRunAction.cc
|
||||
G4UserTaskInitialization.cc
|
||||
G4UserTaskThreadInitialization.cc
|
||||
G4UserWorkerInitialization.cc
|
||||
G4UserWorkerThreadInitialization.cc
|
||||
G4VModularPhysicsList.cc
|
||||
G4VPersistencyManager.cc
|
||||
G4VPhysicsConstructor.cc
|
||||
G4VUserActionInitialization.cc
|
||||
G4VUserDetectorConstruction.cc
|
||||
G4VUserParallelWorld.cc
|
||||
G4VPhysicsConstructor.cc
|
||||
G4VUserPhysicsList.cc
|
||||
G4VUserPrimaryGeneratorAction.cc
|
||||
G4WorkerThread.cc
|
||||
G4RNGHelper.cc)
|
||||
G4WorkerRunManager.cc
|
||||
G4WorkerRunManagerKernel.cc
|
||||
G4WorkerTaskRunManager.cc
|
||||
G4WorkerTaskRunManagerKernel.cc
|
||||
G4WorkerThread.cc)
|
||||
|
||||
geant4_module_compile_definitions(G4run PRIVATE G4RUN_ALLOC_EXPORT)
|
||||
|
||||
geant4_module_link_libraries(G4run
|
||||
PUBLIC
|
||||
@@ -85,13 +101,13 @@ geant4_module_link_libraries(G4run
|
||||
G4tracking
|
||||
PRIVATE
|
||||
G4bosons
|
||||
G4decay
|
||||
G4detector
|
||||
G4detutils
|
||||
G4emutils
|
||||
G4geometrymng
|
||||
G4graphics_reps
|
||||
G4hadronic_mgt
|
||||
G4hadronic_util
|
||||
G4hepnumerics
|
||||
G4hits
|
||||
G4ions
|
||||
@@ -103,7 +119,6 @@ geant4_module_link_libraries(G4run
|
||||
G4scoring
|
||||
G4specsolids
|
||||
G4track
|
||||
G4tracking
|
||||
G4transportation
|
||||
G4volumes
|
||||
${timemory_LIBRARIES})
|
||||
|
||||
@@ -62,7 +62,7 @@ void G4MSSteppingAction::UserSteppingAction(const G4Step* aStep)
|
||||
return;
|
||||
|
||||
G4double stlen = aStep->GetStepLength();
|
||||
G4Material* material = preStepPoint->GetMaterial();
|
||||
const G4Material* material = preStepPoint->GetMaterial();
|
||||
length += stlen;
|
||||
x0 += stlen / (material->GetRadlen());
|
||||
lambda += stlen / (material->GetNuclearInterLength());
|
||||
|
||||
@@ -1094,6 +1094,16 @@ void G4PhysicsListHelper::ReadInDefaultOrderingParameter()
|
||||
theTable->push_back(tmp);
|
||||
sizeOfTable +=1;
|
||||
|
||||
tmp.processTypeName = "DNAScavenger";
|
||||
tmp.processType = fUserDefined;
|
||||
tmp.processSubType = fLowEnergyScavenger;
|
||||
tmp.ordering[0] = -1;
|
||||
tmp.ordering[1] = -1;
|
||||
tmp.ordering[2] = 1000;
|
||||
tmp.isDuplicable = false;
|
||||
theTable->push_back(tmp);
|
||||
sizeOfTable += 1;
|
||||
|
||||
tmp.processTypeName = "HadElastic";
|
||||
tmp.processType = fHadronic;
|
||||
tmp.processSubType = fHadronElastic;
|
||||
|
||||
@@ -0,0 +1,318 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
|
||||
#include "G4RunManagerFactory.hh"
|
||||
#include "G4EnvironmentUtils.hh"
|
||||
#include "G4RunManager.hh"
|
||||
#include "G4MTRunManager.hh"
|
||||
#include "G4TaskRunManager.hh"
|
||||
#include "G4Threading.hh"
|
||||
#include "templates.hh"
|
||||
|
||||
//============================================================================//
|
||||
|
||||
namespace
|
||||
{
|
||||
// failure message
|
||||
static void fail(const std::string& _prefix, const std::string& _name,
|
||||
const std::set<std::string>& _opts, G4int _num)
|
||||
{
|
||||
G4ExceptionDescription msg;
|
||||
msg << _prefix << ": \"" << _name << "\". "
|
||||
<< "Must be one of: ";
|
||||
std::stringstream ss;
|
||||
for(const auto& itr : _opts)
|
||||
ss << ", \"" << itr << "\"";
|
||||
msg << ss.str().substr(2);
|
||||
auto mnum = std::string("RunManagerFactory000") + std::to_string(_num);
|
||||
G4Exception("G4RunManagerFactory::CreateRunManager", mnum.c_str(),
|
||||
FatalException, msg);
|
||||
}
|
||||
|
||||
static G4RunManager* master_run_manager = nullptr;
|
||||
static G4MTRunManager* mt_master_run_manager = nullptr;
|
||||
static G4RunManagerKernel* master_run_manager_kernel = nullptr;
|
||||
} // namespace
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4RunManager* G4RunManagerFactory::CreateRunManager(G4RunManagerType _type,
|
||||
G4VUserTaskQueue* _queue,
|
||||
G4bool fail_if_unavail,
|
||||
G4int nthreads)
|
||||
{
|
||||
// If the supplied type is not ...Only, then allow override from environment
|
||||
std::string rm_type = GetName(_type);
|
||||
if(_type == G4RunManagerType::SerialOnly ||
|
||||
_type == G4RunManagerType::MTOnly ||
|
||||
_type == G4RunManagerType::TaskingOnly ||
|
||||
_type == G4RunManagerType::TBBOnly)
|
||||
{
|
||||
// MUST fail if unavail in this case
|
||||
fail_if_unavail = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// - G4RUN_MANAGER_TYPE can be set to override the "default"
|
||||
// - If the requested type isn't available, then it will fall back to the
|
||||
// system default
|
||||
// - G4FORCE_RUN_MANAGER_TYPE can be set to force a specific type
|
||||
// - A G4Exception is raised if the requested type is not available
|
||||
rm_type = G4GetEnv<std::string>("G4RUN_MANAGER_TYPE", GetName(_type),
|
||||
"Overriding G4RunManager type...");
|
||||
auto force_rm = G4GetEnv<std::string>("G4FORCE_RUN_MANAGER_TYPE", "",
|
||||
"Forcing G4RunManager type...");
|
||||
|
||||
if(force_rm.length() > 0)
|
||||
{
|
||||
rm_type = force_rm;
|
||||
fail_if_unavail = true;
|
||||
}
|
||||
else if(rm_type.empty())
|
||||
{
|
||||
rm_type = GetDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// At this point will have a string for the RM type we can check for existence
|
||||
// NB: Comparison at present is case sensitive (needs a comparator in
|
||||
// GetOptions)
|
||||
auto opts = GetOptions();
|
||||
if(opts.find(rm_type) == opts.end())
|
||||
{
|
||||
if(fail_if_unavail)
|
||||
{
|
||||
fail("Run manager type is not available", rm_type, opts, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
rm_type = GetDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// Construct requested RunManager given type
|
||||
_type = GetType(rm_type);
|
||||
G4RunManager* rm = nullptr;
|
||||
|
||||
switch(_type)
|
||||
{
|
||||
case G4RunManagerType::Serial:
|
||||
rm = new G4RunManager();
|
||||
break;
|
||||
case G4RunManagerType::MT:
|
||||
#if defined(G4MULTITHREADED)
|
||||
rm = new G4MTRunManager();
|
||||
#endif
|
||||
break;
|
||||
case G4RunManagerType::Tasking:
|
||||
#if defined(G4MULTITHREADED)
|
||||
rm = new G4TaskRunManager(_queue, false);
|
||||
#endif
|
||||
break;
|
||||
case G4RunManagerType::TBB:
|
||||
#if defined(G4MULTITHREADED) && defined(GEANT4_USE_TBB)
|
||||
rm = new G4TaskRunManager(_queue, true);
|
||||
#endif
|
||||
break;
|
||||
// "Only" types are not handled since they are converted above to main type
|
||||
case G4RunManagerType::SerialOnly:
|
||||
break;
|
||||
case G4RunManagerType::MTOnly:
|
||||
break;
|
||||
case G4RunManagerType::TaskingOnly:
|
||||
break;
|
||||
case G4RunManagerType::TBBOnly:
|
||||
break;
|
||||
case G4RunManagerType::Default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(!rm)
|
||||
fail("Failure creating run manager", GetName(_type), GetOptions(), 2);
|
||||
|
||||
auto mtrm = dynamic_cast<G4MTRunManager*>(rm);
|
||||
if(nthreads > 0 && mtrm)
|
||||
mtrm->SetNumberOfThreads(nthreads);
|
||||
|
||||
master_run_manager = rm;
|
||||
mt_master_run_manager = mtrm;
|
||||
master_run_manager_kernel = rm->kernel;
|
||||
|
||||
G4ConsumeParameters(_queue);
|
||||
return rm;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
std::string G4RunManagerFactory::GetDefault()
|
||||
{
|
||||
#if defined(G4MULTITHREADED)
|
||||
// For version 10.7, default is set to MT
|
||||
// return "MT";
|
||||
return "Tasking";
|
||||
#else
|
||||
return "Serial";
|
||||
#endif
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
std::set<std::string> G4RunManagerFactory::GetOptions()
|
||||
{
|
||||
static auto _instance = []() {
|
||||
std::set<std::string> options = { "Serial" };
|
||||
#if defined(G4MULTITHREADED)
|
||||
options.insert({ "MT", "Tasking" });
|
||||
# if defined(GEANT4_USE_TBB)
|
||||
options.insert("TBB");
|
||||
# endif
|
||||
#endif
|
||||
return options;
|
||||
}();
|
||||
return _instance;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4RunManagerType G4RunManagerFactory::GetType(const std::string& key)
|
||||
{
|
||||
// IGNORES CASE!
|
||||
static const auto opts = std::regex::icase;
|
||||
|
||||
if(std::regex_match(key, std::regex("^(Serial).*", opts)))
|
||||
return G4RunManagerType::Serial;
|
||||
else if(std::regex_match(key, std::regex("^(MT).*", opts)))
|
||||
return G4RunManagerType::MT;
|
||||
else if(std::regex_match(key, std::regex("^(Task).*", opts)))
|
||||
return G4RunManagerType::Tasking;
|
||||
else if(std::regex_match(key, std::regex("^(TBB).*", opts)))
|
||||
return G4RunManagerType::TBB;
|
||||
|
||||
return G4RunManagerType::Default;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
std::string G4RunManagerFactory::GetName(G4RunManagerType _type)
|
||||
{
|
||||
switch(_type)
|
||||
{
|
||||
case G4RunManagerType::Serial:
|
||||
return "Serial";
|
||||
case G4RunManagerType::SerialOnly:
|
||||
return "Serial";
|
||||
case G4RunManagerType::MT:
|
||||
return "MT";
|
||||
case G4RunManagerType::MTOnly:
|
||||
return "MT";
|
||||
case G4RunManagerType::Tasking:
|
||||
return "Tasking";
|
||||
case G4RunManagerType::TaskingOnly:
|
||||
return "Tasking";
|
||||
case G4RunManagerType::TBB:
|
||||
return "TBB";
|
||||
case G4RunManagerType::TBBOnly:
|
||||
return "TBB";
|
||||
default:
|
||||
break;
|
||||
};
|
||||
return "";
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4RunManager* G4RunManagerFactory::GetMasterRunManager()
|
||||
{
|
||||
#if !defined(G4MULTITHREADED)
|
||||
// if serial build just return G4RunManager
|
||||
return G4RunManager::GetRunManager();
|
||||
#else
|
||||
// if the application used G4RunManagerFactory to create the run-manager
|
||||
if(master_run_manager)
|
||||
return master_run_manager;
|
||||
|
||||
// if the application did not use G4RunManagerFactory and is MT
|
||||
if(G4Threading::IsMultithreadedApplication())
|
||||
{
|
||||
auto mt_rm = GetMTMasterRunManager();
|
||||
if(mt_rm)
|
||||
return mt_rm;
|
||||
}
|
||||
|
||||
// if the application did not use G4RunManagerFactory and is serial
|
||||
return G4RunManager::GetRunManager();
|
||||
#endif
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4MTRunManager* G4RunManagerFactory::GetMTMasterRunManager()
|
||||
{
|
||||
#if defined(G4MULTITHREADED)
|
||||
// if the application used G4RunManagerFactory to create the run-manager
|
||||
if(mt_master_run_manager)
|
||||
return mt_master_run_manager;
|
||||
|
||||
// if the application did not use G4RunManagerFactory
|
||||
if(G4Threading::IsMultithreadedApplication())
|
||||
{
|
||||
auto task_rm = G4TaskRunManager::GetMasterRunManager();
|
||||
if(task_rm)
|
||||
return task_rm;
|
||||
return G4MTRunManager::GetMasterRunManager();
|
||||
}
|
||||
#endif
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4RunManagerKernel* G4RunManagerFactory::GetMasterRunManagerKernel()
|
||||
{
|
||||
#if !defined(G4MULTITHREADED)
|
||||
// if serial build just return G4RunManager
|
||||
return G4RunManager::GetRunManager()->kernel;
|
||||
#else
|
||||
// if the application used G4RunManagerFactory to create the run-manager
|
||||
if(master_run_manager_kernel)
|
||||
return master_run_manager_kernel;
|
||||
|
||||
// if the application did not use G4RunManagerFactory and is MT
|
||||
if(G4Threading::IsMultithreadedApplication())
|
||||
{
|
||||
auto mt_rm = GetMTMasterRunManager();
|
||||
if(mt_rm)
|
||||
return mt_rm->kernel;
|
||||
}
|
||||
|
||||
// if the application did not use G4RunManagerFactory and is serial
|
||||
return G4RunManager::GetRunManager()->kernel;
|
||||
#endif
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
@@ -0,0 +1,795 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
|
||||
#include "G4TaskRunManager.hh"
|
||||
#include "G4AutoLock.hh"
|
||||
#include "G4EnvironmentUtils.hh"
|
||||
#include "G4ProductionCutsTable.hh"
|
||||
#include "G4Run.hh"
|
||||
#include "G4ScoringManager.hh"
|
||||
#include "G4StateManager.hh"
|
||||
#include "G4Task.hh"
|
||||
#include "G4TaskGroup.hh"
|
||||
#include "G4TaskManager.hh"
|
||||
#include "G4TaskRunManagerKernel.hh"
|
||||
#include "G4ThreadPool.hh"
|
||||
#include "G4Threading.hh"
|
||||
#include "G4TiMemory.hh"
|
||||
#include "G4Timer.hh"
|
||||
#include "G4TransportationManager.hh"
|
||||
#include "G4UImanager.hh"
|
||||
#include "G4UserRunAction.hh"
|
||||
#include "G4UserTaskInitialization.hh"
|
||||
#include "G4UserTaskThreadInitialization.hh"
|
||||
#include "G4VUserActionInitialization.hh"
|
||||
#include "G4WorkerTaskRunManager.hh"
|
||||
#include "G4WorkerThread.hh"
|
||||
#include "G4UserTaskQueue.hh"
|
||||
#include "G4TiMemory.hh"
|
||||
#include "G4ThreadLocalSingleton.hh"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
|
||||
//============================================================================//
|
||||
|
||||
namespace
|
||||
{
|
||||
G4Mutex scorerMergerMutex;
|
||||
G4Mutex runMergerMutex;
|
||||
G4Mutex setUpEventMutex;
|
||||
} // namespace
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4TaskRunManagerKernel* G4TaskRunManager::GetMTMasterRunManagerKernel()
|
||||
{
|
||||
return GetMasterRunManager()->MTkernel;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4TaskRunManager::G4TaskRunManager(G4VUserTaskQueue* task_queue, G4bool useTBB,
|
||||
G4int grainsize)
|
||||
: G4MTRunManager()
|
||||
, PTL::TaskRunManager(useTBB)
|
||||
, eventGrainsize(grainsize)
|
||||
, numberOfEventsPerTask(-1)
|
||||
, numberOfTasks(-1)
|
||||
, masterRNGEngine(nullptr)
|
||||
, workTaskGroup(nullptr)
|
||||
{
|
||||
if(task_queue)
|
||||
taskQueue = task_queue;
|
||||
|
||||
// override default of 2 from G4MTRunManager
|
||||
nworkers = G4Threading::G4GetNumberOfCores();
|
||||
fMasterRM = this;
|
||||
MTkernel = static_cast<G4TaskRunManagerKernel*>(kernel);
|
||||
|
||||
G4int numberOfStaticAllocators = kernel->GetNumberOfStaticAllocators();
|
||||
if(numberOfStaticAllocators > 0)
|
||||
{
|
||||
G4ExceptionDescription msg1;
|
||||
msg1 << "There are " << numberOfStaticAllocators
|
||||
<< " static G4Allocator objects detected.\n"
|
||||
<< "In multi-threaded mode, all G4Allocator objects must "
|
||||
<< "be dynamicly instantiated.";
|
||||
G4Exception("G4TaskRunManager::G4TaskRunManager", "Run1035", FatalException,
|
||||
msg1);
|
||||
}
|
||||
|
||||
G4UImanager::GetUIpointer()->SetMasterUIManager(true);
|
||||
masterScM = G4ScoringManager::GetScoringManagerIfExist();
|
||||
|
||||
// use default RandomNumberGenerator if created by user, or create default
|
||||
masterRNGEngine = G4Random::getTheEngine();
|
||||
|
||||
numberOfEventToBeProcessed = 0;
|
||||
randDbl = new G4double[nSeedsPerEvent * nSeedsMax];
|
||||
|
||||
//------------------------------------------------------------------------//
|
||||
// handle threading
|
||||
//------------------------------------------------------------------------//
|
||||
G4String _nthread_env = G4GetEnv<G4String>("G4FORCENUMBEROFTHREADS", "");
|
||||
for(auto& itr : _nthread_env)
|
||||
itr = tolower(itr);
|
||||
|
||||
if(_nthread_env == "max")
|
||||
forcedNwokers = G4Threading::G4GetNumberOfCores();
|
||||
else if(!_nthread_env.empty())
|
||||
{
|
||||
std::stringstream ss;
|
||||
G4int _nthread_val = -1;
|
||||
ss << _nthread_env;
|
||||
ss >> _nthread_val;
|
||||
if(_nthread_val > 0)
|
||||
forcedNwokers = _nthread_val;
|
||||
|
||||
if(forcedNwokers > 0)
|
||||
nworkers = forcedNwokers;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------//
|
||||
// option for forcing TBB
|
||||
//------------------------------------------------------------------------//
|
||||
#ifdef GEANT4_USE_TBB
|
||||
G4int _useTBB = G4GetEnv<G4int>("G4FORCE_TBB", (G4int) useTBB);
|
||||
if(_useTBB > 0)
|
||||
useTBB = true;
|
||||
#else
|
||||
if(useTBB)
|
||||
{
|
||||
G4ExceptionDescription msg;
|
||||
msg << "TBB was requested but Geant4 was not built with TBB support";
|
||||
G4Exception("G4TaskRunManager::G4TaskRunManager(...)", "Run0131",
|
||||
JustWarning, msg);
|
||||
}
|
||||
useTBB = false;
|
||||
#endif
|
||||
|
||||
// handle TBB
|
||||
G4ThreadPool::set_use_tbb(useTBB);
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4TaskRunManager::G4TaskRunManager(G4bool useTBB)
|
||||
: G4TaskRunManager(nullptr, useTBB, 0)
|
||||
{}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4TaskRunManager::~G4TaskRunManager()
|
||||
{
|
||||
// finalize profiler before shutting down the threads
|
||||
G4Profiler::Finalize();
|
||||
|
||||
// terminate all the workers
|
||||
G4TaskRunManager::TerminateWorkers();
|
||||
|
||||
// trigger all G4AutoDelete instances
|
||||
G4ThreadLocalSingleton<void>::Clear();
|
||||
|
||||
// delete the task-group
|
||||
delete workTaskGroup;
|
||||
workTaskGroup = nullptr;
|
||||
|
||||
// destroy the thread-pool
|
||||
if(threadPool)
|
||||
threadPool->destroy_threadpool();
|
||||
|
||||
PTL::TaskRunManager::Terminate();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4ThreadId G4TaskRunManager::GetMasterThreadId()
|
||||
{
|
||||
return G4MTRunManager::GetMasterThreadId();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::StoreRNGStatus(const G4String& fn)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << randomNumberStatusDir << "G4Master_" << fn << ".rndm";
|
||||
G4Random::saveEngineStatus(os.str().c_str());
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::SetNumberOfThreads(G4int n)
|
||||
{
|
||||
if(forcedNwokers > 0)
|
||||
{
|
||||
if(verboseLevel > 0)
|
||||
{
|
||||
G4ExceptionDescription msg;
|
||||
msg << "\n### Number of threads is forced to " << forcedNwokers
|
||||
<< " by G4FORCENUMBEROFTHREADS environment variable. G4TaskRunManager::"
|
||||
<< __FUNCTION__ << "(" << n << ") ignored ###";
|
||||
G4Exception("G4TaskRunManager::SetNumberOfThreads(G4int)", "Run0132",
|
||||
JustWarning, msg);
|
||||
}
|
||||
nworkers = forcedNwokers;
|
||||
}
|
||||
else
|
||||
{
|
||||
nworkers = n;
|
||||
if(poolInitialized)
|
||||
{
|
||||
if(verboseLevel > 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "\n### Thread-pool already initialized. Resizing to " << nworkers
|
||||
<< "threads ###";
|
||||
G4cout << ss.str() << "\n" << G4endl;
|
||||
}
|
||||
GetThreadPool()->resize(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::Initialize()
|
||||
{
|
||||
G4bool firstTime = (!threadPool);
|
||||
if(firstTime)
|
||||
InitializeThreadPool();
|
||||
|
||||
G4RunManager::Initialize();
|
||||
|
||||
// make sure all worker threads are set up.
|
||||
G4RunManager::BeamOn(0);
|
||||
if(firstTime)
|
||||
G4RunManager::SetRunIDCounter(0);
|
||||
// G4UImanager::GetUIpointer()->SetIgnoreCmdNotFound(true);
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::InitializeThreadPool()
|
||||
{
|
||||
if(poolInitialized && threadPool && workTaskGroup)
|
||||
{
|
||||
G4Exception("G4TaskRunManager::InitializeThreadPool", "Run1040",
|
||||
JustWarning, "Threadpool already initialized. Ignoring...");
|
||||
return;
|
||||
}
|
||||
|
||||
PTL::TaskRunManager::SetVerbose(GetVerbose());
|
||||
PTL::TaskRunManager::Initialize(nworkers);
|
||||
|
||||
// create the joiners
|
||||
if(!workTaskGroup)
|
||||
{ workTaskGroup = new RunTaskGroup(threadPool); }
|
||||
|
||||
if(verboseLevel > 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss.fill('=');
|
||||
ss << std::setw(90) << "";
|
||||
G4cout << "\n" << ss.str() << G4endl;
|
||||
|
||||
if(threadPool->is_tbb_threadpool())
|
||||
{
|
||||
G4cout << "G4TaskRunManager :: Using TBB..." << G4endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
G4cout << "G4TaskRunManager :: Using G4ThreadPool..." << G4endl;
|
||||
}
|
||||
|
||||
G4cout << ss.str() << "\n" << G4endl;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::ProcessOneEvent(G4int)
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::TerminateOneEvent()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::ComputeNumberOfTasks()
|
||||
{
|
||||
G4int grainSize = (eventGrainsize == 0) ? threadPool->size() : eventGrainsize;
|
||||
grainSize =
|
||||
G4GetEnv<G4int>("G4FORCE_GRAINSIZE", grainSize, "Forcing grainsize...");
|
||||
if(grainSize == 0)
|
||||
grainSize = 1;
|
||||
|
||||
G4int nEvtsPerTask = (numberOfEventToBeProcessed > grainSize)
|
||||
? (numberOfEventToBeProcessed / grainSize)
|
||||
: 1;
|
||||
|
||||
if(eventModuloDef > 0)
|
||||
{
|
||||
eventModulo = eventModuloDef;
|
||||
}
|
||||
else
|
||||
{
|
||||
eventModulo = G4int(std::sqrt(G4double(numberOfEventToBeProcessed)));
|
||||
if(eventModulo < 1)
|
||||
eventModulo = 1;
|
||||
}
|
||||
if(eventModulo > nEvtsPerTask)
|
||||
{
|
||||
G4int oldMod = eventModulo;
|
||||
eventModulo = nEvtsPerTask;
|
||||
|
||||
G4ExceptionDescription msgd;
|
||||
msgd << "Event modulo is reduced to " << eventModulo << " (was " << oldMod
|
||||
<< ")"
|
||||
<< " to distribute events to all threads.";
|
||||
G4Exception("G4TaskRunManager::InitializeEventLoop()", "Run10035",
|
||||
JustWarning, msgd);
|
||||
}
|
||||
nEvtsPerTask = eventModulo;
|
||||
|
||||
if(fakeRun)
|
||||
nEvtsPerTask = G4GetEnv<G4int>(
|
||||
"G4FORCE_EVENTS_PER_TASK", nEvtsPerTask,
|
||||
"Forcing number of events per task (overrides grainsize)...");
|
||||
else
|
||||
nEvtsPerTask = G4GetEnv<G4int>("G4FORCE_EVENTS_PER_TASK", nEvtsPerTask);
|
||||
|
||||
if(nEvtsPerTask < 1)
|
||||
nEvtsPerTask = 1;
|
||||
|
||||
numberOfTasks = numberOfEventToBeProcessed / nEvtsPerTask;
|
||||
numberOfEventsPerTask = nEvtsPerTask;
|
||||
eventModulo = numberOfEventsPerTask;
|
||||
|
||||
if(fakeRun && verboseLevel > 1)
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << "--> G4TaskRunManager::ComputeNumberOfTasks() --> " << numberOfTasks
|
||||
<< " tasks with " << numberOfEventsPerTask << " events/task...";
|
||||
|
||||
std::stringstream ss;
|
||||
ss.fill('=');
|
||||
ss << std::setw(msg.str().length()) << "";
|
||||
G4cout << "\n"
|
||||
<< ss.str() << "\n"
|
||||
<< msg.str() << "\n"
|
||||
<< ss.str() << "\n"
|
||||
<< G4endl;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::CreateAndStartWorkers()
|
||||
{
|
||||
// Now loop on requested number of workers
|
||||
// This will also start the workers
|
||||
// Currently we do not allow to change the
|
||||
// number of threads: threads area created once
|
||||
// Instead of pthread based workers, create tbbTask
|
||||
static bool initializeStarted = false;
|
||||
|
||||
ComputeNumberOfTasks();
|
||||
|
||||
if(fakeRun)
|
||||
{
|
||||
if(initializeStarted)
|
||||
{
|
||||
auto initCmdStack = GetCommandStack();
|
||||
if(!initCmdStack.empty())
|
||||
{
|
||||
threadPool->execute_on_all_threads([initCmdStack]() {
|
||||
for(auto& itr : initCmdStack)
|
||||
G4UImanager::GetUIpointer()->ApplyCommand(itr);
|
||||
G4WorkerTaskRunManager::GetWorkerRunManager()->DoWork();
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << "--> G4TaskRunManager::CreateAndStartWorkers() --> "
|
||||
<< "Initializing workers...";
|
||||
|
||||
std::stringstream ss;
|
||||
ss.fill('=');
|
||||
ss << std::setw(msg.str().length()) << "";
|
||||
G4cout << "\n"
|
||||
<< ss.str() << "\n"
|
||||
<< msg.str() << "\n"
|
||||
<< ss.str() << "\n"
|
||||
<< G4endl;
|
||||
|
||||
G4TaskRunManagerKernel::InitCommandStack() = GetCommandStack();
|
||||
threadPool->execute_on_all_threads(
|
||||
[]() { G4TaskRunManagerKernel::InitializeWorker(); });
|
||||
}
|
||||
initializeStarted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto initCmdStack = GetCommandStack();
|
||||
if(!initCmdStack.empty())
|
||||
{
|
||||
threadPool->execute_on_all_threads([initCmdStack]() {
|
||||
for(auto& itr : initCmdStack)
|
||||
G4UImanager::GetUIpointer()->ApplyCommand(itr);
|
||||
});
|
||||
}
|
||||
|
||||
// cleans up a previous run and events in case a thread
|
||||
// does not execute any tasks
|
||||
threadPool->execute_on_all_threads(
|
||||
[]() { G4TaskRunManagerKernel::ExecuteWorkerInit(); });
|
||||
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << "--> G4TaskRunManager::CreateAndStartWorkers() --> "
|
||||
<< "Creating " << numberOfTasks << " tasks with "
|
||||
<< numberOfEventsPerTask << " events/task...";
|
||||
|
||||
std::stringstream ss;
|
||||
ss.fill('=');
|
||||
ss << std::setw(msg.str().length()) << "";
|
||||
G4cout << "\n"
|
||||
<< ss.str() << "\n"
|
||||
<< msg.str() << "\n"
|
||||
<< ss.str() << "\n"
|
||||
<< G4endl;
|
||||
}
|
||||
|
||||
G4int remaining = numberOfEventToBeProcessed;
|
||||
for(G4int nt = 0; nt < numberOfTasks + 1; ++nt)
|
||||
{
|
||||
if(remaining > 0)
|
||||
AddEventTask(nt);
|
||||
remaining -= numberOfEventsPerTask;
|
||||
}
|
||||
workTaskGroup->wait();
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::AddEventTask(G4int nt)
|
||||
{
|
||||
if(verboseLevel > 1)
|
||||
G4cout << "Adding task " << nt << " to task-group..." << G4endl;
|
||||
workTaskGroup->exec([]() { G4TaskRunManagerKernel::ExecuteWorkerTask(); });
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::RefillSeeds()
|
||||
{
|
||||
G4RNGHelper* helper = G4RNGHelper::GetInstance();
|
||||
G4int nFill = 0;
|
||||
switch(SeedOncePerCommunication())
|
||||
{
|
||||
case 0:
|
||||
nFill = numberOfEventToBeProcessed - nSeedsFilled;
|
||||
break;
|
||||
case 1:
|
||||
nFill = numberOfTasks - nSeedsFilled;
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
nFill = (numberOfEventToBeProcessed - nSeedsFilled * eventModulo) /
|
||||
eventModulo +
|
||||
1;
|
||||
}
|
||||
// Generates up to nSeedsMax seed pairs only.
|
||||
if(nFill > nSeedsMax)
|
||||
nFill = nSeedsMax;
|
||||
masterRNGEngine->flatArray(nSeedsPerEvent * nFill, randDbl);
|
||||
helper->Refill(randDbl, nFill);
|
||||
nSeedsFilled += nFill;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::InitializeEventLoop(G4int n_event, const char* macroFile,
|
||||
G4int n_select)
|
||||
{
|
||||
MTkernel->SetUpDecayChannels();
|
||||
numberOfEventToBeProcessed = n_event;
|
||||
numberOfEventProcessed = 0;
|
||||
|
||||
if(!fakeRun)
|
||||
{
|
||||
nSeedsUsed = 0;
|
||||
nSeedsFilled = 0;
|
||||
|
||||
if(verboseLevel > 0)
|
||||
timer->Start();
|
||||
|
||||
n_select_msg = n_select;
|
||||
if(macroFile != nullptr)
|
||||
{
|
||||
if(n_select_msg < 0)
|
||||
n_select_msg = n_event;
|
||||
|
||||
msgText = "/control/execute ";
|
||||
msgText += macroFile;
|
||||
selectMacro = macroFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
n_select_msg = -1;
|
||||
selectMacro = "";
|
||||
}
|
||||
|
||||
ComputeNumberOfTasks();
|
||||
|
||||
// initialize seeds
|
||||
// If user did not implement InitializeSeeds,
|
||||
// use default: nSeedsPerEvent seeds per event
|
||||
|
||||
if(n_event > 0)
|
||||
{
|
||||
G4bool _overload = InitializeSeeds(n_event);
|
||||
G4bool _functor = false;
|
||||
if(!_overload)
|
||||
_functor = initSeedsCallback(n_event, nSeedsPerEvent, nSeedsFilled);
|
||||
if(_overload == false && _functor == false)
|
||||
{
|
||||
G4RNGHelper* helper = G4RNGHelper::GetInstance();
|
||||
switch(SeedOncePerCommunication())
|
||||
{
|
||||
case 0:
|
||||
nSeedsFilled = n_event;
|
||||
break;
|
||||
case 1:
|
||||
nSeedsFilled = numberOfTasks;
|
||||
break;
|
||||
case 2:
|
||||
nSeedsFilled = n_event / eventModulo + 1;
|
||||
break;
|
||||
default:
|
||||
G4ExceptionDescription msgd;
|
||||
msgd << "Parameter value <" << SeedOncePerCommunication()
|
||||
<< "> of seedOncePerCommunication is invalid. It is reset "
|
||||
"to 0.";
|
||||
G4Exception("G4TaskRunManager::InitializeEventLoop()", "Run10036",
|
||||
JustWarning, msgd);
|
||||
SetSeedOncePerCommunication(0);
|
||||
nSeedsFilled = n_event;
|
||||
}
|
||||
|
||||
// Generates up to nSeedsMax seed pairs only.
|
||||
if(nSeedsFilled > nSeedsMax)
|
||||
nSeedsFilled = nSeedsMax;
|
||||
masterRNGEngine->flatArray(nSeedsPerEvent * nSeedsFilled, randDbl);
|
||||
helper->Fill(randDbl, nSeedsFilled, n_event, nSeedsPerEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now initialize workers. Check if user defined a WorkerThreadInitialization
|
||||
if(userWorkerThreadInitialization == nullptr)
|
||||
userWorkerThreadInitialization = new G4UserTaskThreadInitialization();
|
||||
|
||||
// Prepare UI commands for threads
|
||||
PrepareCommandsStack();
|
||||
|
||||
// Start worker threads
|
||||
CreateAndStartWorkers();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::RunTermination()
|
||||
{
|
||||
// Wait for all worker threads to have finished the run
|
||||
// i.e. wait for them to return from RunTermination()
|
||||
// This guarantee that userrunaction for workers has been called
|
||||
|
||||
// Wait now for all threads to finish event-loop
|
||||
WaitForEndEventLoopWorkers();
|
||||
// Now call base-class methof
|
||||
G4RunManager::TerminateEventLoop();
|
||||
G4RunManager::RunTermination();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::ConstructScoringWorlds()
|
||||
{
|
||||
masterScM = G4ScoringManager::GetScoringManagerIfExist();
|
||||
// Call base class stuff...
|
||||
G4RunManager::ConstructScoringWorlds();
|
||||
|
||||
masterWorlds.clear();
|
||||
size_t nWorlds =
|
||||
G4TransportationManager::GetTransportationManager()->GetNoWorlds();
|
||||
std::vector<G4VPhysicalVolume*>::iterator itrW =
|
||||
G4TransportationManager::GetTransportationManager()->GetWorldsIterator();
|
||||
for(size_t iWorld = 0; iWorld < nWorlds; ++iWorld)
|
||||
{
|
||||
addWorld(iWorld, *itrW);
|
||||
++itrW;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::MergeScores(const G4ScoringManager* localScoringManager)
|
||||
{
|
||||
G4AutoLock l(&scorerMergerMutex);
|
||||
if(masterScM)
|
||||
masterScM->Merge(localScoringManager);
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::MergeRun(const G4Run* localRun)
|
||||
{
|
||||
G4AutoLock l(&runMergerMutex);
|
||||
if(currentRun)
|
||||
currentRun->Merge(localRun);
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4bool G4TaskRunManager::SetUpAnEvent(G4Event* evt, G4long& s1, G4long& s2,
|
||||
G4long& s3, G4bool reseedRequired)
|
||||
{
|
||||
G4AutoLock l(&setUpEventMutex);
|
||||
if(numberOfEventProcessed < numberOfEventToBeProcessed)
|
||||
{
|
||||
evt->SetEventID(numberOfEventProcessed);
|
||||
if(reseedRequired)
|
||||
{
|
||||
G4RNGHelper* helper = G4RNGHelper::GetInstance();
|
||||
G4int idx_rndm = nSeedsPerEvent * nSeedsUsed;
|
||||
s1 = helper->GetSeed(idx_rndm);
|
||||
s2 = helper->GetSeed(idx_rndm + 1);
|
||||
if(nSeedsPerEvent == 3)
|
||||
s3 = helper->GetSeed(idx_rndm + 2);
|
||||
++nSeedsUsed;
|
||||
if(nSeedsUsed == nSeedsFilled)
|
||||
RefillSeeds();
|
||||
}
|
||||
numberOfEventProcessed++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4int G4TaskRunManager::SetUpNEvents(G4Event* evt, G4SeedsQueue* seedsQueue,
|
||||
G4bool reseedRequired)
|
||||
{
|
||||
G4AutoLock l(&setUpEventMutex);
|
||||
if(numberOfEventProcessed < numberOfEventToBeProcessed && !runAborted)
|
||||
{
|
||||
G4int nevt = numberOfEventsPerTask;
|
||||
G4int nmod = eventModulo;
|
||||
if(numberOfEventProcessed + nevt > numberOfEventToBeProcessed)
|
||||
{
|
||||
nevt = numberOfEventToBeProcessed - numberOfEventProcessed;
|
||||
nmod = numberOfEventToBeProcessed - numberOfEventProcessed;
|
||||
}
|
||||
evt->SetEventID(numberOfEventProcessed);
|
||||
|
||||
if(reseedRequired)
|
||||
{
|
||||
G4RNGHelper* helper = G4RNGHelper::GetInstance();
|
||||
G4int nevRnd = nmod;
|
||||
if(SeedOncePerCommunication() > 0)
|
||||
nevRnd = 1;
|
||||
for(G4int i = 0; i < nevRnd; ++i)
|
||||
{
|
||||
seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed));
|
||||
seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed + 1));
|
||||
if(nSeedsPerEvent == 3)
|
||||
seedsQueue->push(helper->GetSeed(nSeedsPerEvent * nSeedsUsed + 2));
|
||||
nSeedsUsed++;
|
||||
if(nSeedsUsed == nSeedsFilled)
|
||||
RefillSeeds();
|
||||
}
|
||||
}
|
||||
numberOfEventProcessed += nevt;
|
||||
return nevt;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::TerminateWorkers()
|
||||
{
|
||||
// Force workers to execute (if any) all UI commands left in the stack
|
||||
RequestWorkersProcessCommandsStack();
|
||||
|
||||
if(workTaskGroup)
|
||||
{
|
||||
workTaskGroup->join();
|
||||
if(!fakeRun)
|
||||
threadPool->execute_on_all_threads(
|
||||
[]() { G4TaskRunManagerKernel::TerminateWorker(); });
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::AbortRun(G4bool softAbort)
|
||||
{
|
||||
// This method is valid only for GeomClosed or EventProc state
|
||||
G4ApplicationState currentState =
|
||||
G4StateManager::GetStateManager()->GetCurrentState();
|
||||
if(currentState == G4State_GeomClosed || currentState == G4State_EventProc)
|
||||
{
|
||||
runAborted = true;
|
||||
MTkernel->BroadcastAbortRun(softAbort);
|
||||
}
|
||||
else
|
||||
{
|
||||
G4cerr << "Run is not in progress. AbortRun() ignored." << G4endl;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::AbortEvent()
|
||||
{
|
||||
// nothing to do in the master thread
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::WaitForEndEventLoopWorkers()
|
||||
{
|
||||
if(workTaskGroup)
|
||||
{
|
||||
workTaskGroup->join();
|
||||
if(!fakeRun)
|
||||
threadPool->execute_on_all_threads(
|
||||
[]() { G4TaskRunManagerKernel::TerminateWorkerRunEventLoop(); });
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::RequestWorkersProcessCommandsStack()
|
||||
{
|
||||
PrepareCommandsStack();
|
||||
|
||||
auto process_commands_stack = []() {
|
||||
G4MTRunManager* mrm = G4MTRunManager::GetMasterRunManager();
|
||||
if(mrm)
|
||||
{
|
||||
auto cmds = mrm->GetCommandStack();
|
||||
for(const auto& itr : cmds)
|
||||
G4UImanager::GetUIpointer()->ApplyCommand(itr); // TLS instance
|
||||
mrm->ThisWorkerProcessCommandsStackDone();
|
||||
}
|
||||
};
|
||||
|
||||
if(threadPool)
|
||||
threadPool->execute_on_all_threads(process_commands_stack);
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManager::ThisWorkerProcessCommandsStackDone() {}
|
||||
|
||||
//============================================================================//
|
||||
@@ -0,0 +1,362 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
|
||||
#include "G4TaskRunManagerKernel.hh"
|
||||
#include "G4AutoLock.hh"
|
||||
#include "G4RegionStore.hh"
|
||||
#include "G4StateManager.hh"
|
||||
|
||||
#include "G4DecayTable.hh"
|
||||
#include "G4LogicalVolume.hh"
|
||||
#include "G4Material.hh"
|
||||
#include "G4MaterialTable.hh"
|
||||
#include "G4PVParameterised.hh"
|
||||
#include "G4PVReplica.hh"
|
||||
#include "G4ParticleDefinition.hh"
|
||||
#include "G4ParticleTable.hh"
|
||||
#include "G4ParticleTableIterator.hh"
|
||||
#include "G4PhysicalVolumeStore.hh"
|
||||
#include "G4PhysicsVector.hh"
|
||||
#include "G4PolyconeSide.hh"
|
||||
#include "G4PolyhedraSide.hh"
|
||||
#include "G4Region.hh"
|
||||
#include "G4Run.hh"
|
||||
#include "G4TaskManager.hh"
|
||||
#include "G4TiMemory.hh"
|
||||
#include "G4UImanager.hh"
|
||||
#include "G4UserWorkerInitialization.hh"
|
||||
#include "G4UserWorkerThreadInitialization.hh"
|
||||
#include "G4VDecayChannel.hh"
|
||||
#include "G4VModularPhysicsList.hh"
|
||||
#include "G4VPhysicalVolume.hh"
|
||||
#include "G4VPhysicsConstructor.hh"
|
||||
#include "G4VUserActionInitialization.hh"
|
||||
#include "G4VUserPhysicsList.hh"
|
||||
#include "G4WorkerTaskRunManager.hh"
|
||||
#include "G4WorkerThread.hh"
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
//============================================================================//
|
||||
|
||||
std::vector<G4String> G4TaskRunManagerKernel::initCmdStack = {};
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4TaskRunManagerKernel::G4TaskRunManagerKernel()
|
||||
: G4RunManagerKernel(masterRMK)
|
||||
{
|
||||
// This version of the constructor should never be called in sequential mode!
|
||||
#ifndef G4MULTITHREADED
|
||||
G4ExceptionDescription msg;
|
||||
msg << "Geant4 code is compiled without multi-threading support "
|
||||
"(-DG4MULTITHREADED "
|
||||
"is set to off).";
|
||||
msg << " This type of RunManager can only be used in mult-threaded "
|
||||
"applications.";
|
||||
G4Exception("G4RunManagerKernel::G4RunManagerKernel()", "Run0109",
|
||||
FatalException, msg);
|
||||
#endif
|
||||
// Set flag that a MT-type kernel has been instantiated
|
||||
G4Threading::SetMultithreadedApplication(true);
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4TaskRunManagerKernel::~G4TaskRunManagerKernel() {}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManagerKernel::SetupShadowProcess() const
|
||||
{
|
||||
// Behavior is the same as base class (sequential mode)
|
||||
// ShadowProcess pointer == process poitner
|
||||
G4RunManagerKernel::SetupShadowProcess();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
namespace
|
||||
{
|
||||
using WorkerRunManPtr_t = std::unique_ptr<G4WorkerTaskRunManager>;
|
||||
using WorkerThreadPtr_t = std::unique_ptr<G4WorkerThread>;
|
||||
|
||||
WorkerRunManPtr_t& workerRM()
|
||||
{
|
||||
G4ThreadLocalStatic WorkerRunManPtr_t _instance{ nullptr };
|
||||
return _instance;
|
||||
}
|
||||
|
||||
WorkerThreadPtr_t& context()
|
||||
{
|
||||
G4ThreadLocalStatic WorkerThreadPtr_t _instance{ nullptr };
|
||||
return _instance;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4WorkerThread* G4TaskRunManagerKernel::GetWorkerThread()
|
||||
{
|
||||
return context().get();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManagerKernel::InitializeWorker()
|
||||
{
|
||||
if(context() && workerRM())
|
||||
return;
|
||||
|
||||
G4TaskRunManager* mrm = G4TaskRunManager::GetMasterRunManager();
|
||||
if(G4MTRunManager::GetMasterThreadId() == G4ThisThread::get_id())
|
||||
{
|
||||
G4TaskManager* taskManager = mrm->GetTaskManager();
|
||||
auto _fut = taskManager->async(InitializeWorker);
|
||||
_fut->wait();
|
||||
return;
|
||||
}
|
||||
|
||||
//!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
//!!!!!! IMPORTANT !!!!!!!!!
|
||||
//!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// Here is not sequential anymore and G4UserWorkerThreadInitialization is
|
||||
// a shared user initialization class
|
||||
// This means this method cannot use data memebers of G4RunManagerKernel
|
||||
// unless they are invariant ("read-only") and can be safely shared.
|
||||
// All the rest that is not invariant should be incapsualted into
|
||||
// the context (or, as for wThreadContext be G4ThreadLocal)
|
||||
//!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
G4Threading::WorkerThreadJoinsPool();
|
||||
context().reset(new G4WorkerThread);
|
||||
|
||||
//============================
|
||||
// Step-0: Thread ID
|
||||
//============================
|
||||
// Initliazie per-thread stream-output
|
||||
// The following line is needed before we actually do IO initialization
|
||||
// becasue the constructor of UI manager resets the IO destination.
|
||||
context()->SetNumberThreads(mrm->GetThreadPool()->size());
|
||||
context()->SetThreadId(G4ThreadPool::get_this_thread_id() - 1);
|
||||
G4int thisID = context()->GetThreadId();
|
||||
G4Threading::G4SetThreadId(thisID);
|
||||
G4UImanager::GetUIpointer()->SetUpForAThread(thisID);
|
||||
|
||||
//============================
|
||||
// Optimization: optional
|
||||
//============================
|
||||
// Enforce thread affinity if requested
|
||||
context()->SetPinAffinity(mrm->GetPinAffinity());
|
||||
|
||||
//============================
|
||||
// Step-1: Random number engine
|
||||
//============================
|
||||
// RNG Engine needs to be initialized by "cloning" the master one.
|
||||
const CLHEP::HepRandomEngine* masterEngine = mrm->getMasterRandomEngine();
|
||||
mrm->GetUserWorkerThreadInitialization()->SetupRNGEngine(masterEngine);
|
||||
|
||||
//============================
|
||||
// Step-2: Initialize worker thread
|
||||
//============================
|
||||
if(mrm->GetUserWorkerInitialization())
|
||||
mrm->GetUserWorkerInitialization()->WorkerInitialize();
|
||||
|
||||
if(mrm->GetUserActionInitialization())
|
||||
{
|
||||
G4VSteppingVerbose* sv =
|
||||
mrm->GetUserActionInitialization()->InitializeSteppingVerbose();
|
||||
if(sv)
|
||||
G4VSteppingVerbose::SetInstance(sv);
|
||||
}
|
||||
// Now initialize worker part of shared objects (geometry/physics)
|
||||
context()->BuildGeometryAndPhysicsVector();
|
||||
workerRM().reset(static_cast<G4WorkerTaskRunManager*>(
|
||||
mrm->GetUserWorkerThreadInitialization()->CreateWorkerRunManager()));
|
||||
auto& wrm = workerRM();
|
||||
wrm->SetWorkerThread(context().get());
|
||||
|
||||
//================================
|
||||
// Step-3: Setup worker run manager
|
||||
//================================
|
||||
// Set the detector and physics list to the worker thread. Share with master
|
||||
const G4VUserDetectorConstruction* detector =
|
||||
mrm->GetUserDetectorConstruction();
|
||||
wrm->G4RunManager::SetUserInitialization(
|
||||
const_cast<G4VUserDetectorConstruction*>(detector));
|
||||
const G4VUserPhysicsList* physicslist = mrm->GetUserPhysicsList();
|
||||
wrm->SetUserInitialization(const_cast<G4VUserPhysicsList*>(physicslist));
|
||||
|
||||
//================================
|
||||
// Step-4: Initialize worker run manager
|
||||
//================================
|
||||
if(mrm->GetUserActionInitialization())
|
||||
mrm->GetNonConstUserActionInitialization()->Build();
|
||||
if(mrm->GetUserWorkerInitialization())
|
||||
mrm->GetUserWorkerInitialization()->WorkerStart();
|
||||
|
||||
workerRM()->Initialize();
|
||||
|
||||
for(auto& itr : initCmdStack)
|
||||
G4UImanager::GetUIpointer()->ApplyCommand(itr);
|
||||
|
||||
wrm->ProcessUI();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManagerKernel::ExecuteWorkerInit()
|
||||
{
|
||||
// because of TBB
|
||||
if(G4MTRunManager::GetMasterThreadId() == G4ThisThread::get_id())
|
||||
{
|
||||
G4TaskManager* taskManager =
|
||||
G4TaskRunManager::GetMasterRunManager()->GetTaskManager();
|
||||
auto _fut = taskManager->async(ExecuteWorkerInit);
|
||||
return _fut->get();
|
||||
}
|
||||
|
||||
// this check is for TBB as there is not a way to run an initialization
|
||||
// routine on each thread
|
||||
if(!workerRM())
|
||||
InitializeWorker();
|
||||
|
||||
auto& wrm = workerRM();
|
||||
assert(wrm.get() != nullptr);
|
||||
wrm->DoCleanup();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManagerKernel::ExecuteWorkerTask()
|
||||
{
|
||||
// because of TBB
|
||||
if(G4MTRunManager::GetMasterThreadId() == G4ThisThread::get_id())
|
||||
{
|
||||
G4TaskManager* taskManager =
|
||||
G4TaskRunManager::GetMasterRunManager()->GetTaskManager();
|
||||
auto _fut = taskManager->async(ExecuteWorkerTask);
|
||||
return _fut->get();
|
||||
}
|
||||
|
||||
// this check is for TBB as there is not a way to run an initialization
|
||||
// routine on each thread
|
||||
if(!workerRM())
|
||||
InitializeWorker();
|
||||
|
||||
auto& wrm = workerRM();
|
||||
assert(wrm.get() != nullptr);
|
||||
wrm->DoWork();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManagerKernel::TerminateWorkerRunEventLoop()
|
||||
{
|
||||
if(workerRM())
|
||||
TerminateWorkerRunEventLoop(workerRM().get());
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManagerKernel::TerminateWorker()
|
||||
{
|
||||
if(workerRM())
|
||||
TerminateWorker(workerRM().get());
|
||||
workerRM().reset();
|
||||
context().reset();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManagerKernel::TerminateWorkerRunEventLoop(
|
||||
G4WorkerTaskRunManager* wrm)
|
||||
{
|
||||
if(!wrm)
|
||||
return;
|
||||
|
||||
wrm->TerminateEventLoop();
|
||||
wrm->RunTermination();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManagerKernel::TerminateWorker(G4WorkerTaskRunManager* wrm)
|
||||
{
|
||||
if(!wrm)
|
||||
return;
|
||||
|
||||
//===============================
|
||||
// Step-6: Terminate worker thread
|
||||
//===============================
|
||||
G4TaskRunManager* mrm = G4TaskRunManager::GetMasterRunManager();
|
||||
if(mrm && mrm->GetUserWorkerInitialization())
|
||||
mrm->GetUserWorkerInitialization()->WorkerStop();
|
||||
|
||||
G4WorkerThread* _context = wrm->GetWorkerThread();
|
||||
_context->DestroyGeometryAndPhysicsVector();
|
||||
|
||||
G4Threading::WorkerThreadLeavesPool();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
std::vector<G4String>& G4TaskRunManagerKernel::InitCommandStack()
|
||||
{
|
||||
return initCmdStack;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManagerKernel::SetUpDecayChannels()
|
||||
{
|
||||
G4ParticleTable::G4PTblDicIterator* pItr =
|
||||
G4ParticleTable::GetParticleTable()->GetIterator();
|
||||
pItr->reset();
|
||||
while((*pItr)())
|
||||
{
|
||||
G4DecayTable* dt = pItr->value()->GetDecayTable();
|
||||
if(dt)
|
||||
{
|
||||
G4int nCh = dt->entries();
|
||||
for(G4int i = 0; i < nCh; i++)
|
||||
{
|
||||
dt->GetDecayChannel(i)->GetDaughter(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4TaskRunManagerKernel::BroadcastAbortRun(G4bool softAbort)
|
||||
{
|
||||
G4ConsumeParameters(softAbort);
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
|
||||
#include "G4UserTaskInitialization.hh"
|
||||
|
||||
G4UserTaskInitialization::G4UserTaskInitialization() {}
|
||||
G4UserTaskInitialization::~G4UserTaskInitialization() {}
|
||||
|
||||
void G4UserTaskInitialization::WorkerInitialize() const {}
|
||||
void G4UserTaskInitialization::WorkerStart() const {}
|
||||
void G4UserTaskInitialization::WorkerRunStart() const {}
|
||||
void G4UserTaskInitialization::WorkerRunEnd() const {}
|
||||
void G4UserTaskInitialization::WorkerStop() const {}
|
||||
@@ -0,0 +1,130 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
|
||||
#include "G4UserTaskThreadInitialization.hh"
|
||||
#include "G4AutoLock.hh"
|
||||
#include "G4TaskRunManagerKernel.hh"
|
||||
#include "G4UImanager.hh"
|
||||
#include "G4VUserActionInitialization.hh"
|
||||
#include "G4VUserPhysicsList.hh"
|
||||
#include "G4WorkerRunManager.hh"
|
||||
#include "G4WorkerTaskRunManager.hh"
|
||||
#include "G4WorkerThread.hh"
|
||||
#include "globals.hh"
|
||||
#include <sstream>
|
||||
|
||||
//============================================================================//
|
||||
|
||||
namespace
|
||||
{
|
||||
G4Mutex rngCreateMutex;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4Thread* G4UserTaskThreadInitialization::CreateAndStartWorker(G4WorkerThread*)
|
||||
{
|
||||
// Note: this method is called by G4MTRunManager, here we are still sequential
|
||||
// Create a new thread/worker structure
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
// Avoid compilation warning in sequential
|
||||
void G4UserTaskThreadInitialization::JoinWorker(G4Thread* aThread)
|
||||
{
|
||||
if(aThread)
|
||||
{
|
||||
G4THREADJOIN(*aThread);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4UserTaskThreadInitialization::G4UserTaskThreadInitialization() {}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4UserTaskThreadInitialization::~G4UserTaskThreadInitialization() {}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4UserTaskThreadInitialization::SetupRNGEngine(
|
||||
const CLHEP::HepRandomEngine* aNewRNG) const
|
||||
{
|
||||
G4AutoLock l(&rngCreateMutex);
|
||||
// No default available, let's create the instance of random stuff
|
||||
// A Call to this just forces the creation to defaults
|
||||
G4Random::getTheEngine();
|
||||
// Poor man's solution to check which RNG Engine is used in master thread
|
||||
CLHEP::HepRandomEngine* retRNG = nullptr;
|
||||
|
||||
// Need to make these calls thread safe
|
||||
if(dynamic_cast<const CLHEP::HepJamesRandom*>(aNewRNG))
|
||||
retRNG = new CLHEP::HepJamesRandom;
|
||||
if(dynamic_cast<const CLHEP::MixMaxRng*>(aNewRNG))
|
||||
retRNG = new CLHEP::MixMaxRng;
|
||||
if(dynamic_cast<const CLHEP::RanecuEngine*>(aNewRNG))
|
||||
retRNG = new CLHEP::RanecuEngine;
|
||||
if(dynamic_cast<const CLHEP::Ranlux64Engine*>(aNewRNG))
|
||||
retRNG = new CLHEP::Ranlux64Engine;
|
||||
if(dynamic_cast<const CLHEP::RanluxppEngine*>(aNewRNG))
|
||||
retRNG = new CLHEP::RanluxppEngine;
|
||||
if(dynamic_cast<const CLHEP::MTwistEngine*>(aNewRNG))
|
||||
retRNG = new CLHEP::MTwistEngine;
|
||||
if(dynamic_cast<const CLHEP::DualRand*>(aNewRNG))
|
||||
retRNG = new CLHEP::DualRand;
|
||||
if(dynamic_cast<const CLHEP::RanluxEngine*>(aNewRNG))
|
||||
retRNG = new CLHEP::RanluxEngine;
|
||||
if(dynamic_cast<const CLHEP::RanshiEngine*>(aNewRNG))
|
||||
retRNG = new CLHEP::RanshiEngine;
|
||||
|
||||
if(retRNG != nullptr)
|
||||
G4Random::setTheEngine(retRNG);
|
||||
else
|
||||
{
|
||||
// Does a new method, such as aNewRng->newEngine() exist to clone it ?
|
||||
G4ExceptionDescription msg;
|
||||
msg << " Unknown type of RNG Engine - " << G4endl
|
||||
<< " Can cope only with HepJamesRandom, MixMaxRng, Ranecu, Ranlux64,"
|
||||
<< " Ranlux++, MTwistEngine, DualRand, Ranlux or Ranshi." << G4endl
|
||||
<< " Cannot clone this type of RNG engine, as required for this thread"
|
||||
<< G4endl << " Aborting... " << G4endl;
|
||||
G4Exception("G4UserTaskInitializition::SetupRNGEngine()", "Run0122",
|
||||
FatalException, msg);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4WorkerRunManager* G4UserTaskThreadInitialization::CreateWorkerRunManager()
|
||||
const
|
||||
{
|
||||
return new G4WorkerTaskRunManager();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
@@ -0,0 +1,544 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
|
||||
#include "G4WorkerTaskRunManager.hh"
|
||||
#include "G4MTRunManager.hh"
|
||||
#include "G4ParallelWorldProcess.hh"
|
||||
#include "G4RNGHelper.hh"
|
||||
#include "G4Run.hh"
|
||||
#include "G4SDManager.hh"
|
||||
#include "G4ScoringManager.hh"
|
||||
#include "G4TiMemory.hh"
|
||||
#include "G4Timer.hh"
|
||||
#include "G4TransportationManager.hh"
|
||||
#include "G4UImanager.hh"
|
||||
#include "G4UserRunAction.hh"
|
||||
#include "G4UserWorkerInitialization.hh"
|
||||
#include "G4UserWorkerThreadInitialization.hh"
|
||||
#include "G4VScoreNtupleWriter.hh"
|
||||
#include "G4VScoringMesh.hh"
|
||||
#include "G4VUserActionInitialization.hh"
|
||||
#include "G4VUserDetectorConstruction.hh"
|
||||
#include "G4VUserPhysicsList.hh"
|
||||
#include "G4VUserPrimaryGeneratorAction.hh"
|
||||
#include "G4VVisManager.hh"
|
||||
#include "G4WorkerTaskRunManagerKernel.hh"
|
||||
#include "G4WorkerThread.hh"
|
||||
#include "G4AutoLock.hh"
|
||||
#include "G4ParallelWorldProcessStore.hh"
|
||||
#include "G4TaskRunManager.hh"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
// namespace
|
||||
// {
|
||||
// G4Mutex ConstructScoringWorldsMutex;
|
||||
// }
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4WorkerTaskRunManager* G4WorkerTaskRunManager::GetWorkerRunManager()
|
||||
{
|
||||
return static_cast<G4WorkerTaskRunManager*>(G4RunManager::GetRunManager());
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4WorkerTaskRunManagerKernel*
|
||||
G4WorkerTaskRunManager::GetWorkerRunManagerKernel()
|
||||
{
|
||||
return static_cast<G4WorkerTaskRunManagerKernel*>(
|
||||
GetWorkerRunManager()->kernel);
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4WorkerTaskRunManager::G4WorkerTaskRunManager()
|
||||
: G4WorkerRunManager()
|
||||
{}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4WorkerTaskRunManager::RunInitialization()
|
||||
{
|
||||
#ifdef G4MULTITHREADED
|
||||
if(!visIsSetUp)
|
||||
{
|
||||
G4VVisManager* pVVis = G4VVisManager::GetConcreteInstance();
|
||||
if(pVVis)
|
||||
{
|
||||
pVVis->SetUpForAThread();
|
||||
visIsSetUp = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
runIsSeeded = false;
|
||||
|
||||
if(!(kernel->RunInitialization(fakeRun)))
|
||||
return;
|
||||
|
||||
// Signal this thread can start event loop.
|
||||
// Note this will return only when all threads reach this point
|
||||
G4MTRunManager::GetMasterRunManager()->ThisWorkerReady();
|
||||
if(fakeRun)
|
||||
return;
|
||||
|
||||
const G4UserWorkerInitialization* uwi =
|
||||
G4MTRunManager::GetMasterRunManager()->GetUserWorkerInitialization();
|
||||
|
||||
CleanUpPreviousEvents();
|
||||
if(currentRun)
|
||||
delete currentRun;
|
||||
|
||||
currentRun = nullptr;
|
||||
|
||||
if(IfGeometryHasBeenDestroyed())
|
||||
G4ParallelWorldProcessStore::GetInstance()->UpdateWorlds();
|
||||
|
||||
// Call a user hook: this is guaranteed all threads are "synchronized"
|
||||
if(uwi)
|
||||
uwi->WorkerRunStart();
|
||||
|
||||
if(userRunAction)
|
||||
currentRun = userRunAction->GenerateRun();
|
||||
if(!currentRun)
|
||||
currentRun = new G4Run();
|
||||
|
||||
currentRun->SetRunID(runIDCounter);
|
||||
G4TaskRunManager* mrm = G4TaskRunManager::GetMasterRunManager();
|
||||
numberOfEventToBeProcessed = mrm->GetNumberOfEventsToBeProcessed();
|
||||
currentRun->SetNumberOfEventToBeProcessed(numberOfEventToBeProcessed);
|
||||
|
||||
currentRun->SetDCtable(DCtable);
|
||||
G4SDManager* fSDM = G4SDManager::GetSDMpointerIfExist();
|
||||
if(fSDM)
|
||||
currentRun->SetHCtable(fSDM->GetHCtable());
|
||||
|
||||
if(G4VScoreNtupleWriter::Instance())
|
||||
{
|
||||
auto hce = fSDM->PrepareNewEvent();
|
||||
isScoreNtupleWriter = G4VScoreNtupleWriter::Instance()->Book(hce);
|
||||
delete hce;
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
G4Random::saveFullState(oss);
|
||||
randomNumberStatusForThisRun = oss.str();
|
||||
currentRun->SetRandomNumberStatus(randomNumberStatusForThisRun);
|
||||
|
||||
for(G4int i_prev = 0; i_prev < n_perviousEventsToBeStored; ++i_prev)
|
||||
previousEvents->push_back(nullptr);
|
||||
|
||||
if(printModulo > 0 || verboseLevel > 0)
|
||||
{
|
||||
G4cout << "### Run " << currentRun->GetRunID()
|
||||
<< " starts on worker thread " << G4Threading::G4GetThreadId() << "."
|
||||
<< G4endl;
|
||||
}
|
||||
|
||||
if(userRunAction)
|
||||
userRunAction->BeginOfRunAction(currentRun);
|
||||
|
||||
#if defined(GEANT4_USE_TIMEMORY)
|
||||
workerRunProfiler.reset(new ProfilerConfig(currentRun));
|
||||
#endif
|
||||
|
||||
if(isScoreNtupleWriter)
|
||||
{
|
||||
G4VScoreNtupleWriter::Instance()->OpenFile();
|
||||
}
|
||||
|
||||
if(storeRandomNumberStatus)
|
||||
{
|
||||
G4String fileN = "currentRun";
|
||||
if(rngStatusEventsFlag)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "run" << currentRun->GetRunID();
|
||||
fileN = os.str();
|
||||
}
|
||||
StoreRNGStatus(fileN);
|
||||
}
|
||||
|
||||
runAborted = false;
|
||||
numberOfEventProcessed = 0;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4WorkerTaskRunManager::DoEventLoop(G4int n_event, const char* macroFile,
|
||||
G4int n_select)
|
||||
{
|
||||
if(!userPrimaryGeneratorAction)
|
||||
{
|
||||
G4Exception("G4RunManager::GenerateEvent()", "Run0032", FatalException,
|
||||
"G4VUserPrimaryGeneratorAction is not defined!");
|
||||
}
|
||||
|
||||
// This is the same as in the sequential case, just the for-loop indexes are
|
||||
// different
|
||||
InitializeEventLoop(n_event, macroFile, n_select);
|
||||
|
||||
// Reset random number seeds queue
|
||||
while(seedsQueue.size() > 0)
|
||||
seedsQueue.pop();
|
||||
// for each run, worker should receive at least one set of random number
|
||||
// seeds.
|
||||
// runIsSeeded = false;
|
||||
|
||||
// Event loop
|
||||
eventLoopOnGoing = true;
|
||||
G4int i_event = -1;
|
||||
nevModulo = -1;
|
||||
currEvID = -1;
|
||||
|
||||
for(G4int evt = 0; evt < n_event; ++evt)
|
||||
{
|
||||
ProcessOneEvent(i_event);
|
||||
if(eventLoopOnGoing)
|
||||
{
|
||||
TerminateOneEvent();
|
||||
if(runAborted)
|
||||
eventLoopOnGoing = false;
|
||||
}
|
||||
if(!eventLoopOnGoing)
|
||||
break;
|
||||
}
|
||||
|
||||
// TerminateEventLoop();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4WorkerTaskRunManager::ProcessOneEvent(G4int i_event)
|
||||
{
|
||||
currentEvent = GenerateEvent(i_event);
|
||||
if(eventLoopOnGoing)
|
||||
{
|
||||
eventManager->ProcessOneEvent(currentEvent);
|
||||
AnalyzeEvent(currentEvent);
|
||||
UpdateScoring();
|
||||
if(currentEvent->GetEventID() < n_select_msg)
|
||||
{
|
||||
G4cout << "Applying command \"" << msgText << "\" @ " << __FUNCTION__
|
||||
<< ":" << __LINE__ << G4endl;
|
||||
G4UImanager::GetUIpointer()->ApplyCommand(msgText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4Event* G4WorkerTaskRunManager::GenerateEvent(G4int i_event)
|
||||
{
|
||||
G4Event* anEvent = new G4Event(i_event);
|
||||
long s1 = 0;
|
||||
long s2 = 0;
|
||||
long s3 = 0;
|
||||
G4bool eventHasToBeSeeded = true;
|
||||
if(G4MTRunManager::SeedOncePerCommunication() == 1 && runIsSeeded)
|
||||
eventHasToBeSeeded = false;
|
||||
|
||||
if(i_event < 0)
|
||||
{
|
||||
G4int nevM = G4MTRunManager::GetMasterRunManager()->GetEventModulo();
|
||||
if(nevM == 1)
|
||||
{
|
||||
eventLoopOnGoing = G4MTRunManager::GetMasterRunManager()->SetUpAnEvent(
|
||||
anEvent, s1, s2, s3, eventHasToBeSeeded);
|
||||
runIsSeeded = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(nevModulo <= 0)
|
||||
{
|
||||
G4int nevToDo = G4MTRunManager::GetMasterRunManager()->SetUpNEvents(
|
||||
anEvent, &seedsQueue, eventHasToBeSeeded);
|
||||
if(nevToDo == 0)
|
||||
eventLoopOnGoing = false;
|
||||
else
|
||||
{
|
||||
currEvID = anEvent->GetEventID();
|
||||
nevModulo = nevToDo - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(G4MTRunManager::SeedOncePerCommunication() > 0)
|
||||
eventHasToBeSeeded = false;
|
||||
anEvent->SetEventID(++currEvID);
|
||||
nevModulo--;
|
||||
}
|
||||
if(eventLoopOnGoing && eventHasToBeSeeded)
|
||||
{
|
||||
s1 = seedsQueue.front();
|
||||
seedsQueue.pop();
|
||||
s2 = seedsQueue.front();
|
||||
seedsQueue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if(!eventLoopOnGoing)
|
||||
{
|
||||
delete anEvent;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else if(eventHasToBeSeeded)
|
||||
{
|
||||
// Need to reseed random number generator
|
||||
G4RNGHelper* helper = G4RNGHelper::GetInstance();
|
||||
s1 = helper->GetSeed(i_event * 2);
|
||||
s2 = helper->GetSeed(i_event * 2 + 1);
|
||||
}
|
||||
|
||||
if(eventHasToBeSeeded)
|
||||
{
|
||||
long seeds[3] = { s1, s2, 0 };
|
||||
G4Random::setTheSeeds(seeds, -1);
|
||||
runIsSeeded = true;
|
||||
////G4cout<<"Event "<<currEvID<<" is seeded with { "<<s1<<", "<<s2<<"
|
||||
///}"<<G4endl;
|
||||
}
|
||||
|
||||
// Read from file seed.
|
||||
// Andrea Dotti 4 November 2015
|
||||
// This is required for strong-reproducibility, in MT mode we have that each
|
||||
// thread produces, for each event a status file, we want to do that.
|
||||
// Search a random file with the format run{%d}evt{%d}.rndm
|
||||
|
||||
// This is the filename base constructed from run and event
|
||||
const auto filename = [&] {
|
||||
std::ostringstream os;
|
||||
os << "run" << currentRun->GetRunID() << "evt" << anEvent->GetEventID();
|
||||
return os.str();
|
||||
};
|
||||
|
||||
G4bool RNGstatusReadFromFile = false;
|
||||
if(readStatusFromFile)
|
||||
{
|
||||
// Build full path of RNG status file for this event
|
||||
std::ostringstream os;
|
||||
os << filename() << ".rndm";
|
||||
const G4String& randomStatusFile = os.str();
|
||||
std::ifstream ifile(randomStatusFile.c_str());
|
||||
if(ifile)
|
||||
{
|
||||
// File valid and readable
|
||||
RNGstatusReadFromFile = true;
|
||||
G4Random::restoreEngineStatus(randomStatusFile.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if(storeRandomNumberStatusToG4Event == 1 ||
|
||||
storeRandomNumberStatusToG4Event == 3)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
G4Random::saveFullState(oss);
|
||||
randomNumberStatusForThisEvent = oss.str();
|
||||
anEvent->SetRandomNumberStatus(randomNumberStatusForThisEvent);
|
||||
}
|
||||
|
||||
if(storeRandomNumberStatus && !RNGstatusReadFromFile)
|
||||
{
|
||||
// If reading from file, avoid to rewrite the same
|
||||
G4String fileN = "currentEvent";
|
||||
if(rngStatusEventsFlag)
|
||||
fileN = filename();
|
||||
StoreRNGStatus(fileN);
|
||||
}
|
||||
|
||||
if(printModulo > 0 && anEvent->GetEventID() % printModulo == 0)
|
||||
{
|
||||
G4cout << "--> Event " << anEvent->GetEventID() << " starts";
|
||||
if(eventHasToBeSeeded)
|
||||
G4cout << " with initial seeds (" << s1 << "," << s2 << ")";
|
||||
G4cout << "." << G4endl;
|
||||
}
|
||||
userPrimaryGeneratorAction->GeneratePrimaries(anEvent);
|
||||
return anEvent;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4WorkerTaskRunManager::RunTermination()
|
||||
{
|
||||
if(!fakeRun && currentRun)
|
||||
{
|
||||
#if defined(GEANT4_USE_TIMEMORY)
|
||||
workerRunProfiler.reset();
|
||||
#endif
|
||||
MergePartialResults();
|
||||
|
||||
// Call a user hook: note this is before the next barrier
|
||||
// so threads execute this method asyncrhonouzly
|
||||
//(TerminateRun allows for synch via G4RunAction::EndOfRun)
|
||||
const G4UserWorkerInitialization* uwi =
|
||||
G4MTRunManager::GetMasterRunManager()->GetUserWorkerInitialization();
|
||||
if(uwi)
|
||||
uwi->WorkerRunEnd();
|
||||
}
|
||||
|
||||
if(currentRun)
|
||||
{
|
||||
G4RunManager::RunTermination();
|
||||
}
|
||||
// Signal this thread has finished envent-loop.
|
||||
// Note this will return only whan all threads reach this point
|
||||
G4MTRunManager::GetMasterRunManager()->ThisWorkerEndEventLoop();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4WorkerTaskRunManager::TerminateEventLoop()
|
||||
{
|
||||
if(verboseLevel > 0 && !fakeRun)
|
||||
{
|
||||
timer->Stop();
|
||||
// prefix with thread # info due to how TBB calls this function
|
||||
G4String prefix =
|
||||
"[thread " + std::to_string(workerContext->GetThreadId()) + "] ";
|
||||
G4cout << prefix << "Thread-local run terminated." << G4endl;
|
||||
G4cout << prefix << "Run Summary" << G4endl;
|
||||
if(runAborted)
|
||||
G4cout << prefix << " Run Aborted after " << numberOfEventProcessed
|
||||
<< " events processed." << G4endl;
|
||||
else
|
||||
G4cout << prefix
|
||||
<< " Number of events processed : " << numberOfEventProcessed
|
||||
<< G4endl;
|
||||
G4cout << prefix << " " << *timer << G4endl;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4WorkerTaskRunManager::SetupDefaultRNGEngine()
|
||||
{
|
||||
const CLHEP::HepRandomEngine* mrnge =
|
||||
G4MTRunManager::GetMasterRunManager()->getMasterRandomEngine();
|
||||
assert(mrnge); // Master has created RNG
|
||||
const G4UserWorkerThreadInitialization* uwti =
|
||||
G4MTRunManager::GetMasterRunManager()->GetUserWorkerThreadInitialization();
|
||||
uwti->SetupRNGEngine(mrnge);
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4WorkerTaskRunManager::StoreRNGStatus(const G4String& fn)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << randomNumberStatusDir << "G4Worker" << workerContext->GetThreadId()
|
||||
<< "_" << fn << ".rndm";
|
||||
G4Random::saveEngineStatus(os.str().c_str());
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4WorkerTaskRunManager::ProcessUI()
|
||||
{
|
||||
G4TaskRunManager* mrm = G4TaskRunManager::GetMasterRunManager();
|
||||
if(!mrm)
|
||||
return;
|
||||
|
||||
//------------------------------------------------------------------------//
|
||||
// Check UI commands not already processed
|
||||
auto command_stack = mrm->GetCommandStack();
|
||||
bool matching = (command_stack.size() == processedCommandStack.size());
|
||||
if(matching)
|
||||
{
|
||||
for(uintmax_t i = 0; i < command_stack.size(); ++i)
|
||||
if(processedCommandStack.at(i) != command_stack.at(i))
|
||||
{
|
||||
matching = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------//
|
||||
// Execute UI commands stored in the master UI manager
|
||||
if(!matching)
|
||||
{
|
||||
for(const auto& itr : command_stack)
|
||||
G4UImanager::GetUIpointer()->ApplyCommand(itr);
|
||||
processedCommandStack = command_stack;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4WorkerTaskRunManager::DoCleanup()
|
||||
{
|
||||
CleanUpPreviousEvents();
|
||||
if(currentRun)
|
||||
delete currentRun;
|
||||
currentRun = nullptr;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4WorkerTaskRunManager::DoWork()
|
||||
{
|
||||
G4TaskRunManager* mrm = G4TaskRunManager::GetMasterRunManager();
|
||||
G4bool newRun = false;
|
||||
const G4Run* run = mrm->GetCurrentRun();
|
||||
G4ThreadLocalStatic G4int runId = -1;
|
||||
if(run && run->GetRunID() != runId)
|
||||
{
|
||||
runId = run->GetRunID();
|
||||
newRun = true;
|
||||
if(runId > 0)
|
||||
{
|
||||
ProcessUI();
|
||||
assert(workerContext != nullptr);
|
||||
}
|
||||
workerContext->UpdateGeometryAndPhysicsVectorFromMaster();
|
||||
}
|
||||
|
||||
// Start this run
|
||||
G4int nevts = mrm->GetNumberOfEventsToBeProcessed();
|
||||
G4int numSelect = mrm->GetNumberOfSelectEvents();
|
||||
G4String macroFile = mrm->GetSelectMacro();
|
||||
bool empty_macro = (macroFile == "" || macroFile == " ");
|
||||
|
||||
const char* macro = (empty_macro) ? nullptr : macroFile.c_str();
|
||||
numSelect = (empty_macro) ? -1 : numSelect;
|
||||
|
||||
if(newRun)
|
||||
{
|
||||
G4bool cond = ConfirmBeamOnCondition();
|
||||
if(cond)
|
||||
{
|
||||
ConstructScoringWorlds();
|
||||
RunInitialization();
|
||||
}
|
||||
}
|
||||
DoEventLoop(nevts, macro, numSelect);
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
|
||||
#include "G4WorkerTaskRunManagerKernel.hh"
|
||||
#include "G4ParticleTable.hh"
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4WorkerTaskRunManagerKernel::G4WorkerTaskRunManagerKernel()
|
||||
: G4RunManagerKernel(workerRMK)
|
||||
{
|
||||
// This version of the constructor should never be called in sequential mode!
|
||||
#ifndef G4MULTITHREADED
|
||||
G4ExceptionDescription msg;
|
||||
msg << "Geant4 code is compiled without multi-threading support "
|
||||
"(-DG4MULTITHREADED is set to off).";
|
||||
msg << " This type of RunManager can only be used in mult-threaded "
|
||||
"applications.";
|
||||
G4Exception("G4RunManagerKernel::G4RunManagerKernel()", "Run0102",
|
||||
FatalException, msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
G4WorkerTaskRunManagerKernel::~G4WorkerTaskRunManagerKernel()
|
||||
{
|
||||
G4ParticleTable::GetParticleTable()->DestroyWorkerG4ParticleTable();
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
|
||||
void G4WorkerTaskRunManagerKernel::SetupShadowProcess() const
|
||||
{
|
||||
// Master thread has created processes and setup a pointer
|
||||
// to the master process, get it and copy it in this instance
|
||||
G4ParticleTable* theParticleTable = G4ParticleTable::GetParticleTable();
|
||||
G4ParticleTable::G4PTblDicIterator* theParticleIterator =
|
||||
theParticleTable->GetIterator();
|
||||
theParticleIterator->reset();
|
||||
// loop on particles and get process manager from there list of processes
|
||||
while((*theParticleIterator)())
|
||||
{
|
||||
G4ParticleDefinition* pd = theParticleIterator->value();
|
||||
G4ProcessManager* pm = pd->GetProcessManager();
|
||||
G4ProcessManager* pmM = pd->GetMasterProcessManager();
|
||||
if(!pm || !pmM)
|
||||
{
|
||||
G4ExceptionDescription msg;
|
||||
msg
|
||||
<< "Process manager or process manager shadow to master are not set.\n";
|
||||
msg << "Particle : " << pd->GetParticleName() << " (" << pd
|
||||
<< "), proc-manager: " << pm;
|
||||
msg << " proc-manager-shadow: " << pmM;
|
||||
G4Exception("G4WorkerTaskRunManagerKernel::SetupShadowProcess()",
|
||||
"Run0116", FatalException, msg);
|
||||
return;
|
||||
}
|
||||
G4ProcessVector& procs = *(pm->GetProcessList());
|
||||
G4ProcessVector& procsM = *(pmM->GetProcessList());
|
||||
if(procs.size() != procsM.size())
|
||||
{
|
||||
G4cout
|
||||
<< "G4WorkerTaskRunManagerKernel::SetupShadowProcess() for particle <"
|
||||
<< pd->GetParticleName() << ">" << G4endl;
|
||||
G4cout << " ProcessManager : " << pm << " ProcessManagerShadow : " << pmM
|
||||
<< G4endl;
|
||||
|
||||
for(size_t iv1 = 0; iv1 < procs.size(); iv1++)
|
||||
G4cout << " " << iv1 << " - " << procs[iv1]->GetProcessName()
|
||||
<< G4endl;
|
||||
|
||||
G4cout << "--------------------------------------------------------------"
|
||||
<< G4endl;
|
||||
|
||||
for(size_t iv2 = 0; iv2 < procsM.size(); iv2++)
|
||||
G4cout << " " << iv2 << " - " << procsM[iv2]->GetProcessName()
|
||||
<< G4endl;
|
||||
|
||||
G4cout << "--------------------------------------------------------------"
|
||||
<< G4endl;
|
||||
|
||||
G4ExceptionDescription msg;
|
||||
msg
|
||||
<< " Size of G4ProcessVector is inconsistent between master and worker "
|
||||
"threads ";
|
||||
msg << " for the particle <" << pd->GetParticleName() << ">. \n";
|
||||
msg << " size of G4ProcessVector for worker thread is " << procs.size();
|
||||
msg << " while master thread is " << procsM.size() << ".";
|
||||
G4Exception("G4WorkerTaskRunManagerKernel::SetupShadowProcess()",
|
||||
"Run0117", FatalException, msg);
|
||||
}
|
||||
// To each process add the reference to the same
|
||||
// process from master. Note that we rely on
|
||||
// processes being in the correct order!
|
||||
// We could use some checking using process name or type
|
||||
for(size_t idx = 0; idx < procs.size(); ++idx)
|
||||
{
|
||||
procs[idx]->SetMasterProcess(procsM[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
Reference in New Issue
Block a user