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 eventHeader.setFloatParameter("aprime_conversion_material_z",
30 event_info->getAPrimeConversionMaterialZ());
31}
32void SimulatorBase::onProcessEnd() {
33 run_manager_->TerminateEventLoop();
34 run_manager_->RunTermination();
35 // Delete Run Manager
36 // From Geant4 Basic Example B01:
37 // Job termination
38 // Free the store: user actions, physics list and detector descriptions
39 // are owned and deleted by the run manager, so they should not be
40 // deleted in the main() program
41 // This needs to happen here because otherwise, Geant4 objects are deleted
42 // twice:
43 // 1. When the histogram file is closed (all ROOT objects created during
44 // processing are put there because ROOT)
45 // 2. When Simulator is deleted because run_manager_ is a unique_ptr
46 run_manager_.reset(nullptr);
47
48 // Delete the G4UIsession
49 // I don't think this needs to happen here, but since we are cleaning up
50 // loose ends...
51 session_handle_.reset(nullptr);
52};
53void SimulatorBase::onProcessStart() {
54 // initialize run
55 run_manager_->Initialize();
56
57 for (const std::string& cmd : post_init_commands_) {
58 int g4_ret = ui_manager_->ApplyCommand(cmd);
59 if (g4_ret > 0) {
60 EXCEPTION_RAISE("PostInitCmd",
61 "Post Initialization command '" + cmd +
62 "' returned a failue status from Geant4: " +
63 std::to_string(g4_ret));
64 }
65 }
66
67 // Instantiate the scoring worlds including any parallel worlds.
68 run_manager_->ConstructScoringWorlds();
69
70 // Initialize the current run
71 run_manager_->RunInitialization();
72
73 // Initialize the event processing
74 run_manager_->InitializeEventLoop(1);
75
76 return;
77}
78void SimulatorBase::verifyParameters() const {
79 // in past versions of SimCore, the run number for the simulation was
80 // passed directly to the simulator class rather than pulled from central
81 // framework. This is here to prevent the user from accidentally using the
82 // old style.
83 if (parameters_.exists("runNumber")) {
84 EXCEPTION_RAISE("InvalidParam",
85 "Remove old-style of setting the simulation run number "
86 "(sim.runNumber)."
87 " Replace with using the Process object (p.run).");
88 }
89 // Looks for sub-strings matching the ones listed as an invalid command.
90 // These invalid commands are mostly commands where control has been handed
91 // over to Simulator.
92 for (const auto& invalid_command : INVALID_COMMANDS) {
93 for (const auto& cmd : pre_init_commands_) {
94 if (cmd.find(invalid_command) != std::string::npos) {
95 EXCEPTION_RAISE("PreInitCmd", "Pre Initialization command '" + cmd +
96 "' is not allowed because another "
97 "part of Simulator handles it.");
98 }
99 }
100 for (const auto& cmd : post_init_commands_) {
101 if (cmd.find(invalid_command) != std::string::npos) {
102 EXCEPTION_RAISE("PostInitCmd", "Post Initialization command '" + cmd +
103 "' is not allowed because another "
104 "part of Simulator handles it.");
105 }
106 }
107 }
108}
109
110void SimulatorBase::configure(framework::config::Parameters& parameters) {
111 // parameters used to configure the simulation
112 parameters_ = parameters;
113
114 pre_init_commands_ =
115 parameters_.get<std::vector<std::string>>("pre_init_commands", {});
116
117 // Get the extra simulation configuring commands
118 post_init_commands_ =
119 parameters_.get<std::vector<std::string>>("post_init_commands", {});
120
121 verifyParameters();
122 if (run_manager_) {
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 run_manager_ = std::make_unique<RunManager>(parameters_, conditions_intf_);
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 : pre_init_commands_) {
140 int g4_ret = ui_manager_->ApplyCommand(cmd);
141 if (g4_ret > 0) {
142 EXCEPTION_RAISE("PreInitCmd",
143 "Pre Initialization command '" + cmd +
144 "' returned a failure status from Geant4: " +
145 std::to_string(g4_ret));
146 }
147 }
148}
149void SimulatorBase::createLogging() {
150 auto logging_prefix = parameters_.get<std::string>("logging_prefix");
151 session_handle_ = std::make_unique<LoggedSession>(logging_prefix);
152
153 if (session_handle_ != nullptr)
154 ui_manager_->SetCoutDestination(session_handle_.get());
155}
156
157void SimulatorBase::saveTracks(framework::Event& event) {
158 TrackMap& tracks{g4user::TrackingAction::get()->getTrackMap()};
159 tracks.traceAncestry();
160 event.add("SimParticles", tracks.getParticleMap());
161}
162void SimulatorBase::saveSDHits(framework::Event& event) {
163 // Copy hit objects from SD hit collections into the output event.
164 SensitiveDetector::Factory::get().apply([&event](auto sd) {
165 sd->saveHits(event);
166 sd->onFinishedEvent();
167 });
168}
169
170void SimulatorBase::buildGeometry() {
171 // Instantiate the GDML parser and corresponding messenger owned and
172 // managed by DetectorConstruction
173 auto parser{simcore::geo::Parser::Factory::get().make("gdml", parameters_,
174 conditions_intf_)};
175 if (not parser) {
176 EXCEPTION_RAISE(
177 "UnableToCreate",
178 "Unable to find a parser registered under the name 'gdml'.");
179 }
180 auto parser_ptr{parser.value()};
181
182 // Set the DetectorConstruction instance used to build the detector
183 // from the GDML description.
184 run_manager_->SetUserInitialization(
185 new DetectorConstruction(parser_ptr, parameters_, conditions_intf_));
186
187 // Parse the detector geometry and validate if specified.
188 auto detector_path{parameters_.get<std::string>("detector")};
189 ldmx_log(trace) << "Reading in geometry from '" << detector_path << "'";
190 G4GeometryManager::GetInstance()->OpenGeometry();
191 parser_ptr->read();
192 run_manager_->DefineWorldVolume(parser_ptr->getWorldVolume());
193}
194} // 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:37
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 ...