// Gen_MultiCombo.cc
// Contact person: Phil Jones
// See Gen_MultiCombo.hh for more details
//———————————————————————//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using std::string;
using std::vector;
namespace RAT {
Gen_MultiCombo::Gen_MultiCombo() : GLG4Gen("MultiCombo"),
fGenPairs(vector()), fStateStr(""), fPairStateStr(""),
fVertexGenType(""), fPosGenType(""), fWeightSum(0)
{
// Default time generator, in case none is specified during SetState
fTimeGen = new GLG4TimeGen_Poisson();
}
Gen_MultiCombo::~Gen_MultiCombo()
{
//Only the generators are newed, delete all of them
// delete fTimeGen;
for (size_t i = 0; i < fGenPairs.size(); ++i) {
delete fGenPairs.at(i);
}
}
//Constructor for a new GenPair, the struct packaging a Vertex Generator,
//Position Generator, and weight
Gen_MultiCombo::GenPair::GenPair(G4String vtxType, G4String vtxState,
G4String posType, G4String posState, double weight) :
fWeight(weight)
{
try {
fVtxGen =
GlobalFactory::New(vtxType);
fVtxGen->SetState(vtxState);
fPosGen =
GlobalFactory::New(posType);
fPosGen->SetState(posState);
} catch (FactoryUnknownID &unknown) {
Log::Die("Gen_MultiCombo: Unknown generator \"" + unknown.id +
"\", terminating.");
}
}
Gen_MultiCombo::GenPair::~GenPair()
{
delete fVtxGen;
delete fPosGen;
}
void Gen_MultiCombo::BeginOfRun() {
// Call the base BeginofRun to deal with local instances
GLG4Gen::BeginOfRun();
for (size_t i = 0; i < fGenPairs.size(); ++i) {
fGenPairs.at(i)->fVtxGen->BeginOfRun();
fGenPairs.at(i)->fPosGen->BeginOfRun();
}
}
void Gen_MultiCombo::EndOfRun() {
GLG4Gen::EndOfRun();
for (size_t i = 0; i < fGenPairs.size(); ++i) {
fGenPairs.at(i)->fVtxGen->EndOfRun();
fGenPairs.at(i)->fPosGen->EndOfRun();
}
}
void Gen_MultiCombo::SetState(G4String state)
{
state = trim(state);
vector parts = split(state, ":");
try {
switch (parts.size()) {
case 3:
// last parameter is optional time generator
// Clear fTimeGen before resetting, in case of exception
delete fTimeGen; fTimeGen = NULL;
fTimeGen = RAT::GlobalFactory::New(parts[2]);
case 2:
fVertexGenType = parts[0];
fPosGenType = parts[1];
break;
default:
Log::Die("Combo generator syntax error: "+state);
break;
}
// Save for later call to GetState()
fStateStr = state;
} catch (FactoryUnknownID &unknown) {
warn << "Unknown generator \"" << unknown.id << "\""
<< newline;
}
}
G4String Gen_MultiCombo::GetState() const
{
return fStateStr;
}
// wrapper for the Time Generator's own SetState method
void Gen_MultiCombo::SetTimeState(G4String state)
{
if (fTimeGen)
fTimeGen->SetState(state);
else
warn << "Gen_MultiCombo error: " <<
"Cannot set time state, no time generator selected"
<< newline;
}
// wrapper for the Time Generator's own GetState method
G4String Gen_MultiCombo::GetTimeState() const
{
if (fTimeGen)
return fTimeGen->GetState();
else
return
G4String("Gen_MultiCombo error: no time generator selected");
}
// SetVertexState and SetPosState have identical functionality:
//
// If the string passed is empty (or consists entirely of whitespace),
// display the current state on info,
// and the format of a state string on detail.
//
// Otherwise, use AddGenPair to try and interpret the string as a list
// of triples with which to construct a list of GenPairs, and add those
// GenPairs to fGenPairs
void Gen_MultiCombo::SetVertexState(G4String state)
{
if (state.length() == 0)
DisplayFormat();
else
AddGenPair(state);
}
// GetVertexState and GetPosState have identical functionality:
// return the StateStr as reconstructed by AddGenPair,
// which should be in a format that can be passed to Set(Vertex|Pos)State
G4String Gen_MultiCombo::GetVertexState() const
{
return fPairStateStr;
}
// See comment for SetVertexState
void Gen_MultiCombo::SetPosState(G4String state)
{
if (state.length() == 0)
DisplayFormat();
else
AddGenPair(state);
}
// See comment for GetVertexState
G4String Gen_MultiCombo::GetPosState() const
{
return fPairStateStr;
}
// GenerateEvents:
//
// If no GenPairs have been added yet, nothing can be done, so warn and exit
//
// Otherwise, choose a random GenPair,
// weighted by the weight member of each, using a flat distribution.
// Then use that GenPair to generate an event.
void Gen_MultiCombo::GenerateEvent(G4Event *event)
{
if(fGenPairs.empty()){
warn << "Multicombo generator has no vertex/position pairs "
<< "- unable to generate event!" << newline;
} else {
// Create a random number in (0,fWeightSum)
double rand = CLHEP::RandFlat::shoot(fWeightSum);
// Now we want to find which weight interval the random number falls
// into: (0,fWeightSum) = (0,w1)U(w1,w1+w2)U(w1+w2,w1+w2+w3)U...
vector::iterator it;
for(it=fGenPairs.begin(); itfWeight){
// If the random number is less than current GenPair's
// weight, we've found the right interval, exit the loop
break;
} else {
// Not in this interval, so subtract current weight from
// random number, so that we can just compare to weight
// above, rather than an increasing sum.
rand -= (*it)->fWeight;
}
}
// 'it' now points to the right generator.
G4ThreeVector pos;
(*it)->fPosGen->GeneratePosition(pos);
(*it)->fVtxGen->GeneratePrimaryVertex(event, pos, NextTime());
}
}
void Gen_MultiCombo::ResetTime(double offset)
{
fNextTime = fTimeGen->GenerateEventTime() + offset;
}
// Here we try and interpret a string as a list of fields
// with which to construct a list of GenPairs.
void Gen_MultiCombo::AddGenPair(G4String newValues)
{
newValues = trim(newValues);
vector values = split(newValues, "|");
Log::Assert((values.size() >= 3),
"Call to Multicombo Set(Vtx/Pos)State must have at least 3 fields.");
double w;
try{
w = to_double(values[2]);
} catch(std::invalid_argument error) {
Log::Die("Gen_MultiCombo: "+values[2]+
" could not be parsed as a number");
}
Log::Assert((w >= 0),
"Weight cannot be a negative number - skipping this origin set.");
fGenPairs.push_back(
new GenPair(fVertexGenType, values[0],
fPosGenType, values[1], w));
fWeightSum += w;
fPairStateStr += newline + newValues;
//TODO: need to check for success in creating the GenPair before
// adding it to the vector, weight sum and state string.
}
void Gen_MultiCombo::DisplayFormat()
{
info
<< "Current state of this Gen_MultiCombo:" << newline
<< " \"" << GetPosState() << "\"" << newline;
detail
<< "Format of call to Gen_MultiCombo::SetPosState"
<< " or Gen_MultiCombo::SetVtxState:" << newline
<< "\"/generator/vtx/set vtxState|posState|weight\"" << newline
<< "where:" << newline
<< "\t vtxState is the state to pass to VertexGen" << newline
<< "\t posState is the state to pass to PosGen" << newline
<< "\t and weight is the weight to give this pair" << newline;
}
} //namespace RAT