LDMX Software
SimulatorBase.cxx
1#include "SimCore/SimulatorBase.h"
2
3namespace simcore {
4
5const std::vector<std::string> SimulatorBase::INVALID_COMMANDS = {
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), conditions_intf_(this) {
16 ui_manager_ = G4UImanager::GetUIpointer();
17}
18void SimulatorBase::updateEventHeader(ldmx::EventHeader& eventHeader) const {
19 auto event_info = static_cast<UserEventInformation*>(
20 run_manager_->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 run_manager_->TerminateEventLoop();
32 run_manager_->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 run_manager_ is a unique_ptr
44 run_manager_.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 session_handle_.reset(nullptr);
50};
51void SimulatorBase::onProcessStart() {
52 // initialize run
53 run_manager_->Initialize();
54
55 for (const std::string& cmd : post_init_commands_) {
56 int g4_ret = ui_manager_->ApplyCommand(cmd);
57 if (g4_ret > 0) {
58 EXCEPTION_RAISE("PostInitCmd",
59 "Post Initialization command '" + cmd +
60 "' returned a failue status from Geant4: " +
61 std::to_string(g4_ret));
62 }
63 }
64
65 // Instantiate the scoring worlds including any parallel worlds.
66 run_manager_->ConstructScoringWorlds();
67
68 // Initialize the current run
69 run_manager_->RunInitialization();
70
71 // Initialize the event processing
72 run_manager_->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& invalid_command : INVALID_COMMANDS) {
91 for (const auto& cmd : pre_init_commands_) {
92 if (cmd.find(invalid_command) != 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 : post_init_commands_) {
99 if (cmd.find(invalid_command) != 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
112 pre_init_commands_ =
113 parameters_.get<std::vector<std::string>>("preInitCommands", {});
114
115 // Get the extra simulation configuring commands
116 post_init_commands_ =
117 parameters_.get<std::vector<std::string>>("postInitCommands", {});
118
119 verifyParameters();
120 if (run_manager_) {
121 // TODO: This won't work, need to think of a better solution
122 EXCEPTION_RAISE(
123 "MultipleSimulators",
124 "A simulator or resimulator producer has already been created. Only "
125 "one of them can be present in a given run. To run the resimulator, "
126 "use a an existing eventFile as input.");
127 }
128 // Set up logging before creating the run manager so that output from the
129 // creation of the runManager goes to the appropriate place.
130 createLogging();
131 run_manager_ = std::make_unique<RunManager>(parameters_, conditions_intf_);
132 // Instantiate the class so cascade parameters can be set.
133 // TODO: Are we actually using this?
134 G4CascadeParameters::Instance();
135
136 buildGeometry();
137 for (const std::string& cmd : pre_init_commands_) {
138 int g4_ret = ui_manager_->ApplyCommand(cmd);
139 if (g4_ret > 0) {
140 EXCEPTION_RAISE("PreInitCmd",
141 "Pre Initialization command '" + cmd +
142 "' returned a failure status from Geant4: " +
143 std::to_string(g4_ret));
144 }
145 }
146}
147void SimulatorBase::createLogging() {
148 auto logging_prefix = parameters_.get<std::string>("logging_prefix");
149 session_handle_ = std::make_unique<LoggedSession>(logging_prefix);
150
151 if (session_handle_ != nullptr)
152 ui_manager_->SetCoutDestination(session_handle_.get());
153}
154
155void SimulatorBase::saveTracks(framework::Event& event) {
156 TrackMap& tracks{g4user::TrackingAction::get()->getTrackMap()};
157 tracks.traceAncestry();
158 event.add("SimParticles", tracks.getParticleMap());
159}
160void SimulatorBase::saveSDHits(framework::Event& event) {
161 // Copy hit objects from SD hit collections into the output event.
162 SensitiveDetector::Factory::get().apply([&event](auto sd) {
163 sd->saveHits(event);
164 sd->onFinishedEvent();
165 });
166}
167
168void SimulatorBase::buildGeometry() {
169 // Instantiate the GDML parser and corresponding messenger owned and
170 // managed by DetectorConstruction
171 auto parser{simcore::geo::Parser::Factory::get().make("gdml", parameters_,
172 conditions_intf_)};
173 if (not parser) {
174 EXCEPTION_RAISE(
175 "UnableToCreate",
176 "Unable to find a parser registered under the name 'gdml'.");
177 }
178 auto parser_ptr{parser.value()};
179
180 // Set the DetectorConstruction instance used to build the detector
181 // from the GDML description.
182 run_manager_->SetUserInitialization(
183 new DetectorConstruction(parser_ptr, parameters_, conditions_intf_));
184
185 // Parse the detector geometry and validate if specified.
186 auto detector_path{parameters_.get<std::string>("detector")};
187 ldmx_log(trace) << "Reading in geometry from '" << detector_path << "'";
188 G4GeometryManager::GetInstance()->OpenGeometry();
189 parser_ptr->read();
190 run_manager_->DefineWorldVolume(parser_ptr->getWorldVolume());
191}
192} // namespace simcore
Implements an event buffer system for storing event data.
Definition Event.h:42
Class which represents the process under execution.
Definition Process.h:36
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:29
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:78
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 > INVALID_COMMANDS
Commands not allowed to be passed from python config file This is because Simulator already runs them...
All classes in the ldmx-sw project use this namespace.
Dynamically loadable photonuclear models either from SimCore or external libraries implementing this ...