The classes for users accumulables management were added in 10.2 release for the purpose of simplification of users application code. The accumulables objects are named variables registered to the accumulable manager, which provides the acces to them by name and performs their merging in multi-threading mode according to their defined merge mode. Their usage is demonstrated in the basic examples B1 and B3a.
To better reflect the meaning of these objects, the classes base name "Parameter" used in 10.2 was changed in "Accumulable" in 10.3. Further integration in the Geant4 framework is foreseen in the next Geant4 versions.
G4Accumulable<T>
templated class can be used instead of built-in types in order to facilitate merging of the values accumulated on workers to the master thread. The G4Accumulable<T>
object has, besides its value of the templated type T
, also a name, the initial value, which the value is set to in Reset()
function and a merge mode, specifying the operation which is performed in Merge()
function.
The accumulable object can be either instatiated using its constructor and registerd in G4AccumulablesManager
explicitly, or it can be created using G4AccumulablesManager::CreateAccumulable()
function, their registering is then automatic.
The first way is used in the basic examples B1 and B3a:
// B1RunAction.hh class B1RunAction : public G4UserRunAction { // ... private: G4Accumulable<G4double> fEdep; G4Accumulable<G4double> fEdep2; }; // B1RunAction.cc B1RunAction::B1RunAction() : G4UserRunAction(), fEdep("Edep", 0.), fEdep2("Edep2", 0.) // the accumulable is initialized with a name and a value = initValue // (the name can be omitted) { // .. // Register accumulable to the accumulable manager G4AccumulableManager* accumulableManager = G4AccumulableManager::Instance(); accumulableManager->RegisterAccumulable(fEdep); accumulableManager->RegisterAccumulable(fEdep2); }
An alternative way of creating an accumulable using G4AccumulablesManager
is
demonstrated below:
// B1RunAction.cc B1RunAction::B1RunAction() : G4UserRunAction() { // .. // Accumulables can be also created via accumulable manager G4AccumulableManager* accumulableManager = G4AccumulableManager::Instance(); accumulableManager->CreateAccumulable<G4double>("EdepBis", 0.); accumulableManager->CreateAccumulable<G4double>("Edep2Bis", 0.); }
The G4AccumulablesManager
takes ownership of the accumulables created by its
CreateAccumulable()
function the accumulables allocated in the user code has to
be deleted in the user code.
Since Geant4 10.3, the name of the accumulable can be omitted. A generic name "accumulable_N", where N is the current number of registered obects, will be then attributed.
In multi-threading mode all accumulables registered to G4AccumulablesManager
accumulated on workers can be merged to the master thread by calling G4AccumulablesManager::Merge()
function. This step may be not necessary in future after a planned closer integration of
G4Accumulable classes in the Geant4 kernel.
// B1RunAction.cc void B1RunAction::EndOfRunAction(const G4Run* run) { // ... // Merge accumulables G4AccumulableManager* accumulableManager = G4AccumulableManager::Instance(); accumulableManager->Merge(); }
The merging mode can be specified using the third (or the second one, if the name is omitted)
G4Accumulable<T>
constructor argument.
The merge modes are defined in G4MergeMode
class enumeration:
enum class G4MergeMode { kAddition, // "Or" if boolean type kMultiplication, // "And" if boolean type kMaximum, // "Or" if boolean type kMinimum // "And" if boolean type };
The default accumulable merge operation is addition.
The registered accumulables can be accessed via G4AccumulablesManager
by name or by the id, attributed in the order of registering:
// ... G4AccumulableManager* accumulableManager = G4AccumulableManager::Instance(); // Access accumulables by name G4double edepBis = accumulableManager->GetAccumulable<G4double>("EdepBis")->GetValue(); G4double edep2Bis = accumulableManager->GetAccumulable<G4double>("Edep2Bis")->GetValue(); // Access accumulables by id G4VAccumulable* accumulable = accumulableManager->GetAccumulable(id);
Users can define their own accumulable class derived from G4VAccumulable
abstract base class. An example of a ProcessCounterAccumulable
class,
implementing an accumulable holding a map of the processes occurences by the procesesses names,
is given below. Such processes occurences map is used in several electromagnetic extended examples,
e.g. TestEm1.
ProcCounterAccumulable.hh
#include "G4VAccumulable.hh" #include "globals.hh" #include <map> class ProcCounterAccumulable : public G4VAccumulable { public: ProcCounterAccumulable(const G4String& name) : G4VAccumulable(name, 0), fProcCounter() {} virtual ~ProcCounterAccumulable() {} void CountProcesses(G4String procName); virtual void Merge(const G4VAccumulable& other); virtual void Reset(); private: std::map<G4String,G4int> fProcCounter; };
ProcCounterAccumulable.cc
void ProcCounterAccumulable::Merge(const G4VAccumulable& other) { const ProcCounterAccumulable& otherProcCounterAccumulable = static_cast<const ProcCounterAccumulable&>(other); std::map<G4String,G4int>::const_iterator it; for (it = otherProcCounterAccumulable.fProcCounter.begin(); it != otherProcCounterAccumulable.fProcCounter.end(); ++it) { G4String procName = it->first; G4int otherCount = it->second; if ( fProcCounter.find(procName) == fProcCounter.end()) { fProcCounter[procName] = otherCount; } else { fProcCounter[procName] += otherCount; } } } void ProcCounterAccumulable::Reset() { fProcCounter.clear(); }
The implementation of the CountProcesses()
function is identical as in
Run::CountProcesses()
function in TestEm1.