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