Import Geant4 11.1.0.beta source tree

This commit is contained in:
Gabriele Cosmo
2022-07-01 10:44:02 +02:00
parent b3bf75a2a1
commit c07cea1fe0
2172 changed files with 183300 additions and 123938 deletions
+2 -5
View File
@@ -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
View File
@@ -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
+157
View File
@@ -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
+226
View File
@@ -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();
```
+105
View File
@@ -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
+243
View File
@@ -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
View File
@@ -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})
+1 -1
View File
@@ -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());
+10
View File
@@ -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;
+318
View File
@@ -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
}
//============================================================================//
+795
View File
@@ -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() {}
//============================================================================//
+362
View File
@@ -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();
}
//============================================================================//
+544
View File
@@ -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]);
}
}
}
//============================================================================//