forked from sPHENIX-Collaboration/acts
/
FatrasSimulationBase.cpp
217 lines (198 loc) · 8.94 KB
/
FatrasSimulationBase.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// This file is part of the Acts project.
//
// Copyright (C) 2019 CERN for the benefit of the Acts project
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "FatrasSimulationBase.hpp"
#include <boost/program_options.hpp>
#include "ACTFW/EventData/SimHit.hpp"
#include "ACTFW/EventData/SimParticle.hpp"
#include "ACTFW/Fatras/FatrasAlgorithm.hpp"
#include "ACTFW/Fatras/FatrasOptions.hpp"
#include "ACTFW/Framework/RandomNumbers.hpp"
#include "ACTFW/Framework/Sequencer.hpp"
#include "ACTFW/Generators/FlattenEvent.hpp"
#include "ACTFW/Generators/ParticleSelector.hpp"
#include "ACTFW/Io/Csv/CsvParticleWriter.hpp"
#include "ACTFW/Io/Root/RootParticleWriter.hpp"
#include "ACTFW/Io/Root/RootSimHitWriter.hpp"
#include "ACTFW/Options/CommonOptions.hpp"
#include "ACTFW/Plugins/BField/BFieldOptions.hpp"
#include "ACTFW/Plugins/BField/ScalableBField.hpp"
#include "ACTFW/Utilities/Paths.hpp"
#include "Acts/Geometry/GeometryID.hpp"
#include "Acts/Geometry/TrackingGeometry.hpp"
#include "Acts/MagneticField/ConstantBField.hpp"
#include "Acts/MagneticField/InterpolatedBFieldMap.hpp"
#include "Acts/MagneticField/SharedBField.hpp"
#include "Acts/Propagator/EigenStepper.hpp"
#include "Acts/Propagator/Navigator.hpp"
#include "Acts/Propagator/Propagator.hpp"
#include "Acts/Propagator/StraightLineStepper.hpp"
#include "Acts/Surfaces/Surface.hpp"
#include "ActsFatras/Kernel/PhysicsList.hpp"
#include "ActsFatras/Kernel/Process.hpp"
#include "ActsFatras/Kernel/Simulator.hpp"
#include "ActsFatras/Physics/EnergyLoss/BetheBloch.hpp"
#include "ActsFatras/Physics/EnergyLoss/BetheHeitler.hpp"
#include "ActsFatras/Physics/Scattering/Highland.hpp"
#include "ActsFatras/Selectors/ChargeSelectors.hpp"
#include "ActsFatras/Selectors/KinematicCasts.hpp"
#include "ActsFatras/Selectors/SelectorHelpers.hpp"
namespace {
/// Simple struct to select surfaces where hits should be generated.
struct HitSurfaceSelector {
bool sensitive = false;
bool material = false;
bool passive = false;
/// Check if the surface should be used.
bool operator()(const Acts::Surface& surface) const {
if (sensitive and surface.associatedDetectorElement()) {
return true;
}
if (material and surface.surfaceMaterial()) {
return true;
}
if (passive) {
return true;
}
return false;
}
};
/// @brief Simulation setup for the FatrasAlgorithm
///
/// @tparam bfield_t Type of the bfield for the simulation to be set up
///
/// @param fieldMap The field map for the simulation setup
/// @param sequencer The framework sequencer
/// @param variables The boost variable map to resolve
/// @param tGeometry The TrackingGeometry for the tracking setup
/// @param barcodesSvc The barcode service to be used for the simulation
/// @param randomNumberSvc The random number service to be used for the
/// simulation
template <typename magnetic_field_t>
void setupSimulationAlgorithms(
const FW::Options::Variables& variables, FW::Sequencer& sequencer,
std::shared_ptr<const FW::RandomNumbers> randomNumbers,
std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry,
magnetic_field_t&& magneticField) {
// Read the log level
Acts::Logging::Level logLevel = FW::Options::readLogLevel(variables);
// Convert generated events to selected particles
auto select = FW::ParticleSelector::readConfig(variables);
select.inputEvent = "event_generated";
select.outputEvent = "event_selected";
sequencer.addAlgorithm(
std::make_shared<FW::ParticleSelector>(select, logLevel));
FW::FlattenEvent::Config flatten;
flatten.inputEvent = select.outputEvent;
flatten.outputParticles = "particles_selected";
sequencer.addAlgorithm(std::make_shared<FW::FlattenEvent>(flatten, logLevel));
// setup propagator-related types
// use the default navigation
using Navigator = Acts::Navigator;
// propagate charged particles numerically in the given magnetic field
using ChargedStepper = Acts::EigenStepper<magnetic_field_t>;
using ChargedPropagator = Acts::Propagator<ChargedStepper, Navigator>;
// propagate neutral particles with just straight lines
using NeutralStepper = Acts::StraightLineStepper;
using NeutralPropagator = Acts::Propagator<NeutralStepper, Navigator>;
// setup simulator-related types
using MinP = ActsFatras::Min<ActsFatras::Casts::P>;
// charged particles w/ standard em physics list and selectable hits
using ChargedSelector =
ActsFatras::CombineAnd<ActsFatras::ChargedSelector, MinP>;
using ChargedSimulator = ActsFatras::ParticleSimulator<
ChargedPropagator, ActsFatras::ChargedElectroMagneticPhysicsList,
HitSurfaceSelector>;
// neutral particles w/o physics and no hits
using NeutralSelector =
ActsFatras::CombineAnd<ActsFatras::NeutralSelector, MinP>;
using NeutralSimulator = ActsFatras::ParticleSimulator<
NeutralPropagator, ActsFatras::PhysicsList<>, ActsFatras::NoSurface>;
// full simulator type for charged and neutrals
using Simulator = ActsFatras::Simulator<ChargedSelector, ChargedSimulator,
NeutralSelector, NeutralSimulator>;
// final algorihm type
using SimulationAlgorithm = FW::FatrasAlgorithm<Simulator>;
// construct the simulator
Navigator navigator(trackingGeometry);
// construct the charged simulator
ChargedStepper chargedStepper(std::move(magneticField));
ChargedPropagator chargedPropagator(std::move(chargedStepper), navigator);
ChargedSimulator chargedSimulator(std::move(chargedPropagator), logLevel);
// construct the neutral simulator
NeutralStepper neutralStepper;
NeutralPropagator neutralPropagator(std::move(neutralStepper), navigator);
NeutralSimulator neutralSimulator(std::move(neutralPropagator), logLevel);
// construct the combined simulator
Simulator simulator(std::move(chargedSimulator), std::move(neutralSimulator));
// construct/add the simulation algorithm
auto fatras = FW::Options::readFatrasConfig(variables, std::move(simulator));
fatras.inputParticles = flatten.outputParticles;
fatras.outputParticlesInitial = "particles_initial";
fatras.outputParticlesFinal = "particles_final";
fatras.outputHits = "hits";
fatras.randomNumbers = randomNumbers;
sequencer.addAlgorithm(
std::make_shared<SimulationAlgorithm>(fatras, logLevel));
// Output directory
const auto outputDir = FW::ensureWritableDirectory(
variables["output-dir"].template as<std::string>());
// Write simulation information as CSV files
if (variables["output-csv"].template as<bool>()) {
FW::CsvParticleWriter::Config writeInitial;
writeInitial.inputParticles = fatras.outputParticlesInitial;
writeInitial.outputDir = outputDir;
writeInitial.outputStem = fatras.outputParticlesInitial;
sequencer.addWriter(
std::make_shared<FW::CsvParticleWriter>(writeInitial, logLevel));
FW::CsvParticleWriter::Config writeFinal;
writeFinal.inputParticles = fatras.outputParticlesFinal;
writeFinal.outputDir = outputDir;
writeFinal.outputStem = fatras.outputParticlesFinal;
sequencer.addWriter(
std::make_shared<FW::CsvParticleWriter>(writeFinal, logLevel));
}
// Write simulation information as ROOT files
if (variables["output-root"].template as<bool>()) {
// write initial simulated particles
FW::RootParticleWriter::Config writeInitial;
writeInitial.inputParticles = fatras.outputParticlesInitial;
writeInitial.filePath =
FW::joinPaths(outputDir, fatras.outputParticlesInitial + ".root");
sequencer.addWriter(
std::make_shared<FW::RootParticleWriter>(writeInitial, logLevel));
// write final simulated particles
FW::RootParticleWriter::Config writeFinal;
writeFinal.inputParticles = fatras.outputParticlesFinal;
writeFinal.filePath =
FW::joinPaths(outputDir, fatras.outputParticlesFinal + ".root");
sequencer.addWriter(
std::make_shared<FW::RootParticleWriter>(writeFinal, logLevel));
// write simulated hits
FW::RootSimHitWriter::Config writeHits;
writeHits.inputSimulatedHits = fatras.outputHits;
writeHits.filePath = FW::joinPaths(outputDir, fatras.outputHits + ".root");
sequencer.addWriter(
std::make_shared<FW::RootSimHitWriter>(writeHits, logLevel));
}
}
} // namespace
void FW::setupSimulation(
const FW::Options::Variables& variables, FW::Sequencer& sequencer,
std::shared_ptr<const RandomNumbers> randomNumbers,
std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry) {
auto magneticFieldVariant = FW::Options::readBField(variables);
std::visit(
[&](auto&& inputField) {
using magnetic_field_t =
typename std::decay_t<decltype(inputField)>::element_type;
Acts::SharedBField<magnetic_field_t> magneticField(inputField);
setupSimulationAlgorithms(variables, sequencer, randomNumbers,
trackingGeometry, std::move(magneticField));
},
magneticFieldVariant);
}