LDMX Software
SimulatorBase.cxx
1#include "SimCore/SimulatorBase.h"
2
3namespace simcore {
4
5const std::vector<std::string> SimulatorBase::invalidCommands_ = {
6 "/run/initialize", // hard coded at the right time
7 "/run/beamOn", // passed commands should only be sim setup
8 "/random/setSeeds", // handled by own config parameter (if passed)
9 "ldmx", // all ldmx messengers have been removed
10 "/persistency/gdml/read" // detector description is read after passed a
11 // path to the detector description (required)
12};
13SimulatorBase::SimulatorBase(const std::string& name,
14 framework::Process& process)
15 : framework::Producer(name, process), conditionsIntf_(this) {
16 uiManager_ = G4UImanager::GetUIpointer();
17}
18void SimulatorBase::updateEventHeader(ldmx::EventHeader& eventHeader) const {
19 auto event_info = static_cast<UserEventInformation*>(
20 runManager_->GetCurrentEvent()->GetUserInformation());
21
22 eventHeader.setWeight(event_info->getWeight());
23 eventHeader.setFloatParameter("total_photonuclear_energy",
24 event_info->getPNEnergy());
25 eventHeader.setFloatParameter("total_electronuclear_energy",
26 event_info->getENEnergy());
27 eventHeader.setFloatParameter("db_material_z",
28 event_info->getDarkBremMaterialZ());
29}
30void SimulatorBase::onProcessEnd() {
31 runManager_->TerminateEventLoop();
32 runManager_->RunTermination();
33 // Delete Run Manager
34 // From Geant4 Basic Example B01:
35 // Job termination
36 // Free the store: user actions, physics list and detector descriptions
37 // are owned and deleted by the run manager, so they should not be
38 // deleted in the main() program
39 // This needs to happen here because otherwise, Geant4 objects are deleted
40 // twice:
41 // 1. When the histogram file is closed (all ROOT objects created during
42 // processing are put there because ROOT)
43 // 2. When Simulator is deleted because runManager_ is a unique_ptr
44 runManager_.reset(nullptr);
45
46 // Delete the G4UIsession
47 // I don't think this needs to happen here, but since we are cleaning up
48 // loose ends...
49 sessionHandle_.reset(nullptr);
50};
51void SimulatorBase::onProcessStart() {
52 // initialize run
53 runManager_->Initialize();
54
55 for (const std::string& cmd : postInitCommands_) {
56 int g4Ret = uiManager_->ApplyCommand(cmd);
57 if (g4Ret > 0) {
58 EXCEPTION_RAISE("PostInitCmd",
59 "Post Initialization command '" + cmd +
60 "' returned a failue status from Geant4: " +
61 std::to_string(g4Ret));
62 }
63 }
64
65 // Instantiate the scoring worlds including any parallel worlds.
66 runManager_->ConstructScoringWorlds();
67
68 // Initialize the current run
69 runManager_->RunInitialization();
70
71 // Initialize the event processing
72 runManager_->InitializeEventLoop(1);
73
74 return;
75}
76void SimulatorBase::verifyParameters() const {
77 // in past versions of SimCore, the run number for the simulation was
78 // passed directly to the simulator class rather than pulled from central
79 // framework. This is here to prevent the user from accidentally using the
80 // old style.
81 if (parameters_.exists("runNumber")) {
82 EXCEPTION_RAISE("InvalidParam",
83 "Remove old-style of setting the simulation run number "
84 "(sim.runNumber)."
85 " Replace with using the Process object (p.run).");
86 }
87 // Looks for sub-strings matching the ones listed as an invalid command.
88 // These invalid commands are mostly commands where control has been handed
89 // over to Simulator.
90 for (const auto& invalidCommand : invalidCommands_) {
91 for (const auto& cmd : preInitCommands_) {
92 if (cmd.find(invalidCommand) != std::string::npos) {
93 EXCEPTION_RAISE("PreInitCmd", "Pre Initialization command '" + cmd +
94 "' is not allowed because another "
95 "part of Simulator handles it.");
96 }
97 }
98 for (const auto& cmd : postInitCommands_) {
99 if (cmd.find(invalidCommand) != std::string::npos) {
100 EXCEPTION_RAISE("PostInitCmd", "Post Initialization command '" + cmd +
101 "' is not allowed because another "
102 "part of Simulator handles it.");
103 }
104 }
105 }
106}
107
108void SimulatorBase::configure(framework::config::Parameters& parameters) {
109 // parameters used to configure the simulation
110 parameters_ = parameters;
111 // Set the verbosity level. The default level is 0.
112 verbosity_ = parameters_.getParameter<int>("verbosity");
113
114 preInitCommands_ =
115 parameters_.getParameter<std::vector<std::string>>("preInitCommands", {});
116
117 // Get the extra simulation configuring commands
118 postInitCommands_ = parameters_.getParameter<std::vector<std::string>>(
119 "postInitCommands", {});
120
121 verifyParameters();
122 if (runManager_) {
123 // TODO: This won't work, need to think of a better solution
124 EXCEPTION_RAISE(
125 "MultipleSimulators",
126 "A simulator or resimulator producer has already been created. Only "
127 "one of them can be present in a given run. To run the resimulator, "
128 "use a an existing eventFile as input.");
129 }
130 // Set up logging before creating the run manager so that output from the
131 // creation of the runManager goes to the appropriate place.
132 createLogging();
133 runManager_ = std::make_unique<RunManager>(parameters_, conditionsIntf_);
134 // Instantiate the class so cascade parameters can be set.
135 // TODO: Are we actually using this?
136 G4CascadeParameters::Instance();
137
138 buildGeometry();
139 for (const std::string& cmd : preInitCommands_) {
140 int g4Ret = uiManager_->ApplyCommand(cmd);
141 if (g4Ret > 0) {
142 EXCEPTION_RAISE("PreInitCmd",
143 "Pre Initialization command '" + cmd +
144 "' returned a failure status from Geant4: " +
145 std::to_string(g4Ret));
146 }
147 }
148}
149
150void SimulatorBase::createLogging() {
151 auto loggingPrefix = parameters_.getParameter<std::string>("logging_prefix");
152 if (verbosity_ == 0)
153 sessionHandle_ = std::make_unique<BatchSession>();
154 else if (verbosity_ > 1) {
155 if (loggingPrefix.empty())
156 sessionHandle_ = std::make_unique<LoggedSession>();
157 else
158 sessionHandle_ = std::make_unique<LoggedSession>(
159 loggingPrefix + "_G4cout.log", loggingPrefix + "_G4cerr.log");
160 }
161 if (sessionHandle_ != nullptr)
162 uiManager_->SetCoutDestination(sessionHandle_.get());
163}
164
165void SimulatorBase::saveTracks(framework::Event& event) {
166 TrackMap& tracks{g4user::TrackingAction::get()->getTrackMap()};
167 tracks.traceAncestry();
168 event.add("SimParticles", tracks.getParticleMap());
169}
170void SimulatorBase::saveSDHits(framework::Event& event) {
171 // Copy hit objects from SD hit collections into the output event.
172 SensitiveDetector::Factory::get().apply([&event](auto sd) {
173 sd->saveHits(event);
174 sd->OnFinishedEvent();
175 });
176}
177
178void SimulatorBase::buildGeometry() {
179 // Instantiate the GDML parser and corresponding messenger owned and
180 // managed by DetectorConstruction
182 "gdml", parameters_, conditionsIntf_)};
183
184 // Set the DetectorConstruction instance used to build the detector
185 // from the GDML description.
186 runManager_->SetUserInitialization(
187 new DetectorConstruction(parser, parameters_, conditionsIntf_));
188
189 // Parse the detector geometry and validate if specified.
190 auto detectorPath{parameters_.getParameter<std::string>("detector")};
191 if (verbosity_ > 0) {
192 std::cout << "[ Simulator ] : Reading in geometry from '" << detectorPath
193 << "'... " << std::flush;
194 }
195 G4GeometryManager::GetInstance()->OpenGeometry();
196 parser->read();
197 runManager_->DefineWorldVolume(parser->GetWorldVolume());
198}
199} // namespace simcore
Implements an event buffer system for storing event data.
Definition Event.h:41
Class which represents the process under execution.
Definition Process.h:36
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:27
T getParameter(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:89
Provides header information an event such as event number and timestamp.
Definition EventHeader.h:44
void setWeight(double weight)
Set the event weight.
void setFloatParameter(const std::string &name, float value)
Set a float parameter value.
static const std::vector< std::string > invalidCommands_
Commands not allowed to be passed from python config file This is because Simulator already runs them...
Parser * createParser(const std::string &name, framework::config::Parameters &parameters, simcore::ConditionsInterface &ci)
Create an instance of the parser of the given type.
static ParserFactory & getInstance()
Get the instance to this factory.
virtual void read()=0
Parse the detector geometry and read it into memory.
All classes in the ldmx-sw project use this namespace.
Definition PerfDict.cxx:45