Accumulables¶
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 access 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>¶
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 instantiated using its constructor
and registered 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 objects, 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);
User defined accumulables¶
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 occurrences by the processes names, is given
below. Such processes occurrences 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.