ATLAS Offline Software
ActsFatrasSimTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 #include <algorithm>
5 #include <random>
6 
7 #include "ActsFatrasSimTool.h"
8 
9 #include "CLHEP/Random/RandFlat.h"
10 #include "CLHEP/Random/RandomEngine.h"
11 
13 
14 using namespace Acts::UnitLiterals;
15 
17  const std::string& name,
18  const IInterface* parent)
20 
22 
25  ATH_MSG_INFO("ISF::ActsFatrasSimTool update with ACTS 32.2.0");
26  // Retrieve particle filter
27  if (!m_particleFilter.empty()) ATH_CHECK(m_particleFilter.retrieve());
28 
29  // setup logger
30  m_logger = makeActsAthenaLogger(this, std::string("ActsFatras"),std::string("ActsFatrasSimTool"));
31 
32  // retrive tracking geo tool
33  ATH_CHECK(m_trackingGeometryTool.retrieve());
34  m_trackingGeometry = m_trackingGeometryTool->trackingGeometry();
35 
36  //retrive Magnetfield tool
37  ATH_MSG_VERBOSE("Using ATLAS magnetic field service");
38  ATH_CHECK( m_fieldCacheCondObjInputKey.initialize());
39 
40  // Random number service
41  if (m_rngSvc.retrieve().isFailure()) {
42  ATH_MSG_FATAL("Could not retrieve " << m_rngSvc);
43  return StatusCode::FAILURE;
44  }
45  // Get own engine with own seeds
46  m_randomEngine = m_rngSvc->getEngine(this, m_randomEngineName.value());
47  if (!m_randomEngine) {
48  ATH_MSG_FATAL("Could not get random engine '" << m_randomEngineName.value() << "'");
49  return StatusCode::FAILURE;
50  }
51 
52  return StatusCode::SUCCESS;
53 }
54 
56  ISFParticle& isp, ISFParticleContainer& secondaries,
57  McEventCollection* mcEventCollection) {
58  ATH_MSG_VERBOSE("Particle " << isp << " received for simulation.");
59  // Check if particle passes filter, if there is one
60  if (!m_particleFilter.empty() && !m_particleFilter->passFilter(isp)) {
61  ATH_MSG_VERBOSE("ISFParticle " << isp << " does not pass selection. Ignoring.");
62  return StatusCode::SUCCESS;
63  }
64  // Process ParticleState from particle stack
65  // Wrap the input ISFParticle in an STL vector with size of 1
66  const ISF::ISFParticleVector ispVector(1, &isp);
67  ATH_CHECK(this->simulateVector(ispVector, secondaries, mcEventCollection));
68  ATH_MSG_VERBOSE("Simulation done");
69  return StatusCode::SUCCESS;
70 }
71 
74  ISFParticleContainer& secondaries,
75  McEventCollection* /*mcEventCollection*/, McEventCollection *) {
76 
77  const EventContext& ctx = Gaudi::Hive::currentContext();
78  m_randomEngine->setSeed(m_randomEngineName, ctx);
79  CLHEP::HepRandomEngine* randomEngine = m_randomEngine->getEngine(ctx);
80  Generator generator(CLHEP::RandFlat::shoot(randomEngine->flat()));
81  ATH_MSG_VERBOSE(name() << " RNG seed " << CLHEP::RandFlat::shoot(randomEngine->flat()));
82  ATH_MSG_VERBOSE(name() << " received vector of size "
83  << particles.size() << " particles for simulation.");
84 
85  // construct the ACTS simulator
86  Acts::Navigator navigator( Acts::Navigator::Config{ m_trackingGeometry }, m_logger);
87  auto bField = std::make_shared<ATLASMagneticFieldWrapper>();
88  auto chargedStepper = ChargedStepper(std::move(bField));
89  auto neutralStepper = NeutralStepper();
90  auto chargedPropagator = ChargedPropagator(chargedStepper, navigator, m_logger->clone(Acts::Logging::Level::FATAL));
91  auto neutralPropagator = NeutralPropagator(neutralStepper, navigator, m_logger->clone(Acts::Logging::Level::FATAL));
92  ChargedSimulation simulatorCharged(std::move(chargedPropagator), m_logger->clone());
93  NeutralSimulation simulatorNeutral(std::move(neutralPropagator), m_logger->clone());
94  Simulation simulator=Simulation(std::move(simulatorCharged),std::move(simulatorNeutral));
95  ATH_MSG_VERBOSE(name() << " Min pT for interaction " << m_interact_minPt * Acts::UnitConstants::MeV << " GeV");
96  // Acts propagater options
97  simulator.charged.maxStepSize = m_maxStepSize;
98  simulator.charged.maxStep = m_maxStep;
99  simulator.charged.pathLimit = m_pathLimit;
100  simulator.charged.maxRungeKuttaStepTrials = m_maxRungeKuttaStepTrials;
101  simulator.charged.loopProtection = m_loopProtection;
102  simulator.charged.loopFraction = m_loopFraction;
103  simulator.charged.targetTolerance = m_tolerance;
104  simulator.charged.stepSizeCutOff = m_stepSizeCutOff;
105  // Create interaction list
106  simulator.charged.interactions = ActsFatras::makeStandardChargedElectroMagneticInteractions(m_interact_minPt * Acts::UnitConstants::MeV);
107  // get Geo and Mag map
108  ATH_MSG_VERBOSE(name() << " Getting per event Geo and Mag map");
109  Acts::MagneticFieldContext mctx = getMagneticFieldContext(ctx);
110  const ActsGeometryContext& gctx = m_trackingGeometryTool->getNominalGeometryContext();
111  auto anygctx = gctx.context();
112  // Loop over ISFParticleVector and process each separately
113  ATH_MSG_VERBOSE(name() << " Processing particles in ISFParticleVector.");
114  for (const auto isfp : particles) {
115  // ====ACTSFatras Simulation====
116  // //
117  // input/output particle and hits containers
118  // Convert to ActsFatras::Particle
119  // ISF: Energy, mass, and momentum are in MeV, position in mm
120  // Acts: Energy, mass, and momentum are in GeV, position in mm
121  std::vector<ActsFatras::Particle> input = std::vector<ActsFatras::Particle>{
122  ActsFatras::Particle(ActsFatras::Barcode().setVertexPrimary(0).setParticle(
123  HepMC::barcode(isfp)), static_cast<Acts::PdgParticle>(isfp->pdgCode()),
124  isfp->charge(),isfp->mass() * Acts::UnitConstants::MeV)
125  .setDirection(Acts::makeDirectionFromPhiEta(
126  isfp->momentum().phi(), isfp->momentum().eta()))
127  .setAbsoluteMomentum(isfp->momentum().mag() * Acts::UnitConstants::MeV)
128  .setPosition4(isfp->position().x(), isfp->position().y(),
129  isfp->position().z(), isfp->timeStamp())};
130  std::vector<ActsFatras::Particle> simulatedInitial;
131  std::vector<ActsFatras::Particle> simulatedFinal;
132  std::vector<ActsFatras::Hit> hits;
133  ATH_MSG_DEBUG(name() << " Propagating ActsFatras::Particle vertex|particle|generation|subparticle, " << input[0]);
134  // simulate
135  auto result=simulator.simulate(anygctx, mctx, generator, input, simulatedInitial, simulatedFinal, hits);
136  auto simulatedFailure=result.value();
137  if (simulatedFailure.size()>0){
138  for (const auto& simfail : simulatedFailure){
139  auto errCode = Acts::make_error_code(Acts::PropagatorError(simfail.error.value()));
140  ATH_MSG_WARNING(name() << " Particle id " <<simfail.particle.particleId()<< ": fail to be simulated during Propagation: " << errCode.message());
141  ATH_MSG_WARNING(name() << " Particle vertex|particle|generation|subparticle"<<simfail.particle << " starts from position" << Acts::toString(simfail.particle.position()) << " and direction " << Acts::toString(simfail.particle.direction()));
142  return StatusCode::SUCCESS;
143  }
144  }
145 
146  ATH_MSG_DEBUG(name() << " initial particle " << simulatedInitial[0]);
147  ATH_MSG_DEBUG(name() << " No. of particles after ActsFatras simulator: " << simulatedFinal.size());
148  // convert final particles to ISF::particle
149  for (const auto& factsp : simulatedFinal){
150  const auto pos = Amg::Vector3D(factsp.position()[Acts::ePos0],factsp.position()[Acts::ePos1],factsp.position()[Acts::ePos2]);
151  const auto mom = Amg::Vector3D(factsp.fourMomentum()[Acts::eMom0] / Acts::UnitConstants::MeV,factsp.fourMomentum()[Acts::eMom1] / Acts::UnitConstants::MeV,factsp.fourMomentum()[Acts::eMom2] / Acts::UnitConstants::MeV);
152  double mass = factsp.mass() / Acts::UnitConstants::MeV;
153  double charge = factsp.charge();
154  int pdgid = factsp.pdg();
155  double properTime = factsp.properTime();
156 
157  if (factsp.particleId() == simulatedInitial[0].particleId()) {
158  ATH_MSG_DEBUG(name() << " final particle " << factsp);
159  }
160  else {
161  ATH_MSG_DEBUG(name() << " secondaries particle " << factsp);
162  auto secisfp = std::make_unique<ISF::ISFParticle>(pos,
163  mom,
164  mass,
165  charge,
166  pdgid,
167  1, //status
168  properTime,
169  *isfp,
170  HepMC::UNDEFINED_ID // id
171  );
172  secondaries.push_back(secisfp.release());
173 
174  }
175  }
176  ATH_MSG_DEBUG(name() << " ActsFatras simulator hits: " << hits.size());
177  int i = 0;
178  for (const auto& hit : hits) {
179  ATH_MSG_DEBUG(name() << " hit pos: " << hit.position() );
180  ++i;
181  if (i>5) break;
182  }
183  ATH_MSG_DEBUG(name() << " No. of secondaries: " << secondaries.size());
184 
185  std::vector<ActsFatras::Particle>().swap(input);
186  std::vector<ActsFatras::Particle>().swap(simulatedInitial);
187  std::vector<ActsFatras::Particle>().swap(simulatedFinal);
188  std::vector<ActsFatras::Hit>().swap(hits);
189  }
190  return StatusCode::SUCCESS;
191 }
192 
193 Acts::MagneticFieldContext ISF::ActsFatrasSimTool::getMagneticFieldContext(const EventContext& ctx) const {
194  SG::ReadCondHandle<AtlasFieldCacheCondObj> readHandle{m_fieldCacheCondObjInputKey, ctx};
195  if (!readHandle.isValid()) {
196  ATH_MSG_ERROR(name() + ": Failed to retrieve magnetic field condition data " + m_fieldCacheCondObjInputKey.key() + ".");
197  }
198  else ATH_MSG_DEBUG(name() << "retrieved magnetic field condition data "<< m_fieldCacheCondObjInputKey.key());
199  const AtlasFieldCacheCondObj* fieldCondObj{*readHandle};
200 
201  return Acts::MagneticFieldContext(fieldCondObj);
202 }
ISF::ISFParticleContainer
std::list< ISF::ISFParticle * > ISFParticleContainer
generic ISFParticle container (not necessarily a std::list!)
Definition: ISFParticleContainer.h:23
ISF::ActsFatrasSimTool::ChargedPropagator
Acts::Propagator< ChargedStepper, Navigator > ChargedPropagator
Definition: ActsFatrasSimTool.h:180
ISF::ActsFatrasSimTool::Generator
std::ranlux48 Generator
Definition: ActsFatrasSimTool.h:171
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
ISF::ActsFatrasSimTool::~ActsFatrasSimTool
virtual ~ActsFatrasSimTool()
Definition: ActsFatrasSimTool.cxx:21
get_generator_info.result
result
Definition: get_generator_info.py:21
python.Constants.FATAL
int FATAL
Definition: Control/AthenaCommon/python/Constants.py:19
SG::ReadCondHandle
Definition: ReadCondHandle.h:44
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
AtlasFieldCacheCondObj
Definition: AtlasFieldCacheCondObj.h:19
ISF::ActsFatrasSimTool::NeutralPropagator
Acts::Propagator< NeutralStepper, Navigator > NeutralPropagator
Definition: ActsFatrasSimTool.h:183
ISF::ActsFatrasSimTool::simulateVector
virtual StatusCode simulateVector(const ISFParticleVector &particles, ISFParticleContainer &secondaries, McEventCollection *mcEventCollection, McEventCollection *shadowTruth=nullptr) override
Simulation call for vectors of particles.
Definition: ActsFatrasSimTool.cxx:72
python.SystemOfUnits.MeV
int MeV
Definition: SystemOfUnits.py:154
McEventCollection
McEventCollection
Definition: GeneratorObjectsTPCnv.cxx:60
ISF::ISFParticle
Definition: ISFParticle.h:42
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
xAOD::Particle
Particle_v1 Particle
Define the latest version of the particle class.
Definition: Event/xAOD/xAODParticleEvent/xAODParticleEvent/Particle.h:17
dqt_zlumi_pandas.mass
mass
Definition: dqt_zlumi_pandas.py:170
makeActsAthenaLogger
std::unique_ptr< const Acts::Logger > makeActsAthenaLogger(IMessageSvc *svc, const std::string &name, int level, std::optional< std::string > parent_name)
Definition: Tracking/Acts/ActsInterop/src/Logger.cxx:64
ActsGeometryContext::context
Acts::GeometryContext context() const
Definition: ActsGeometryContext.h:45
ISF::ActsFatrasSimTool::ChargedStepper
Acts::EigenStepper< Acts::StepperExtensionList< Acts::DefaultExtension, Acts::DenseEnvironmentExtension > > ChargedStepper
Definition: ActsFatrasSimTool.h:179
ParticleGun_EoverP_Config.mom
mom
Definition: ParticleGun_EoverP_Config.py:63
Amg::toString
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Definition: GeoPrimitivesToStringConverter.h:40
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
lumiFormat.i
int i
Definition: lumiFormat.py:92
ISF::ActsFatrasSimTool::initialize
virtual StatusCode initialize() override
Definition: ActsFatrasSimTool.cxx:23
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
HepMC::barcode
int barcode(const T *p)
Definition: Barcode.h:16
LArG4ShowerLibProcessing.hits
hits
Definition: LArG4ShowerLibProcessing.py:136
PlotPulseshapeFromCool.input
input
Definition: PlotPulseshapeFromCool.py:106
ISF::ISFParticleVector
std::vector< ISF::ISFParticle * > ISFParticleVector
ISFParticle vector.
Definition: ISFParticleContainer.h:26
test_pyathena.parent
parent
Definition: test_pyathena.py:15
ISF::ActsFatrasSimTool::SingleParticleSimulation
Single particle simulation with fixed propagator, interactions, and decay.
Definition: ActsFatrasSimTool.h:85
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
ISF::ActsFatrasSimTool::NeutralStepper
Acts::StraightLineStepper NeutralStepper
Definition: ActsFatrasSimTool.h:182
ISF::ActsFatrasSimTool::ActsFatrasSimTool
ActsFatrasSimTool(const std::string &type, const std::string &name, const IInterface *parent)
Definition: ActsFatrasSimTool.cxx:16
ActsGeometryContext
Include the GeoPrimitives which need to be put first.
Definition: ActsGeometryContext.h:27
HepMC::UNDEFINED_ID
constexpr int UNDEFINED_ID
Definition: MagicNumbers.h:55
ISF::BaseSimulatorTool
Definition: BaseSimulatorTool.h:36
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
MagicNumbers.h
charge
double charge(const T &p)
Definition: AtlasPID.h:494
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
ISF::ActsFatrasSimTool::getMagneticFieldContext
virtual Acts::MagneticFieldContext getMagneticFieldContext(const EventContext &) const
Definition: ActsFatrasSimTool.cxx:193
ISF::ActsFatrasSimTool::simulate
virtual StatusCode simulate(ISFParticle &isp, ISFParticleContainer &, McEventCollection *) override
Definition: ActsFatrasSimTool.cxx:55
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:18
ISF::BaseSimulatorTool::initialize
virtual StatusCode initialize() override
Definition: BaseSimulatorTool.h:59
mc.generator
generator
Configure Herwig7 These are the commands corresponding to what would go into the regular Herwig infil...
Definition: mc.MGH7_FxFx_H71-DEFAULT_test.py:18
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
LArG4FSStartPointFilter.particles
list particles
Definition: LArG4FSStartPointFilter.py:84
Simulation
Definition: BeamEffectsAlg.cxx:21
TileCalibBlobPython_writeDefaultCs.Simulation
Simulation
Definition: TileCalibBlobPython_writeDefaultCs.py:12
ActsFatrasSimTool.h