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 
14 
15 using namespace Acts::UnitLiterals;
16 
18  const std::string& name,
19  const IInterface* parent)
21 
23 
26  ATH_MSG_INFO("ISF::ActsFatrasSimTool update with ACTS 37.0.0");
27  // Retrieve particle filter
28  if (!m_particleFilter.empty()) ATH_CHECK(m_particleFilter.retrieve());
29 
30  // setup logger
31  m_logger = makeActsAthenaLogger(this, std::string("ActsFatras"),std::string("ActsFatrasSimTool"));
32 
33  // retrive tracking geo tool
34  ATH_CHECK(m_trackingGeometryTool.retrieve());
35  m_trackingGeometry = m_trackingGeometryTool->trackingGeometry();
36 
37  //retrive Magnetfield tool
38  ATH_MSG_VERBOSE("Using ATLAS magnetic field service");
39  ATH_CHECK( m_fieldCacheCondObjInputKey.initialize());
40 
41  // Random number service
42  if (m_rngSvc.retrieve().isFailure()) {
43  ATH_MSG_FATAL("Could not retrieve " << m_rngSvc);
44  return StatusCode::FAILURE;
45  }
46  // Get own engine with own seeds
47  m_randomEngine = m_rngSvc->getEngine(this, m_randomEngineName.value());
48  if (!m_randomEngine) {
49  ATH_MSG_FATAL("Could not get random engine '" << m_randomEngineName.value() << "'");
50  return StatusCode::FAILURE;
51  }
52 
53  // ISF truth service
54  ATH_CHECK (m_truthRecordSvc.retrieve());
55  ATH_MSG_DEBUG( "- Using ISF TruthRecordSvc : " << m_truthRecordSvc.typeAndName() );
56  return StatusCode::SUCCESS;
57 }
58 
60  ISFParticle& isp, ISFParticleContainer& secondaries,
61  McEventCollection* mcEventCollection) {
62  ATH_MSG_VERBOSE("Particle " << isp << " received for simulation.");
63  // Check if particle passes filter, if there is one
64  if (!m_particleFilter.empty() && !m_particleFilter->passFilter(isp)) {
65  ATH_MSG_VERBOSE("ISFParticle " << isp << " does not pass selection. Ignoring.");
66  return StatusCode::SUCCESS;
67  }
68  // Process ParticleState from particle stack
69  // Wrap the input ISFParticle in an STL vector with size of 1
70  const ISF::ISFParticleVector ispVector(1, &isp);
71  ATH_CHECK(m_truthRecordSvc->initializeTruthCollection());
72  ATH_CHECK(this->simulateVector(ctx, ispVector, secondaries, mcEventCollection));
73  ATH_MSG_VERBOSE("Simulation done");
74  return StatusCode::SUCCESS;
75 }
76 
78  const EventContext& ctx,
80  ISFParticleContainer& secondaries,
81  McEventCollection* /*mcEventCollection*/, McEventCollection *) {
82 
83  m_randomEngine->setSeed(m_randomEngineName, ctx);
84  CLHEP::HepRandomEngine* randomEngine = m_randomEngine->getEngine(ctx);
85  Generator generator(CLHEP::RandFlat::shoot(randomEngine->flat()));
86  ATH_MSG_VERBOSE(name() << " RNG seed " << CLHEP::RandFlat::shoot(randomEngine->flat()));
87  ATH_MSG_VERBOSE(name() << " received vector of size "
88  << particles.size() << " particles for simulation.");
89 
90  // construct the ACTS simulator
91  Acts::Navigator navigator( Acts::Navigator::Config{ m_trackingGeometry }, m_logger);
92  auto bField = std::make_shared<ATLASMagneticFieldWrapper>();
93  auto chargedStepper = ChargedStepper(std::move(bField));
94  auto neutralStepper = NeutralStepper();
95  auto chargedPropagator = ChargedPropagator(chargedStepper, navigator, m_logger->clone(Acts::Logging::Level::FATAL));
96  auto neutralPropagator = NeutralPropagator(neutralStepper, navigator, m_logger->clone(Acts::Logging::Level::FATAL));
97  ChargedSimulation simulatorCharged(std::move(chargedPropagator), m_logger->clone());
98  NeutralSimulation simulatorNeutral(std::move(neutralPropagator), m_logger->clone());
99  Simulation simulator=Simulation(std::move(simulatorCharged),std::move(simulatorNeutral));
100  ATH_MSG_VERBOSE(name() << " Min pT for interaction " << m_interact_minPt * Acts::UnitConstants::MeV << " GeV");
101  // Acts propagater options
102  simulator.charged.maxStepSize = m_maxStepSize;
103  simulator.charged.maxStep = m_maxStep;
104  simulator.charged.pathLimit = m_pathLimit;
105  simulator.charged.maxRungeKuttaStepTrials = m_maxRungeKuttaStepTrials;
106  simulator.charged.loopProtection = m_loopProtection;
107  simulator.charged.loopFraction = m_loopFraction;
108  simulator.charged.targetTolerance = m_tolerance;
109  simulator.charged.stepSizeCutOff = m_stepSizeCutOff;
110  // Create interaction list
111  simulator.charged.interactions = ActsFatras::makeStandardChargedElectroMagneticInteractions(m_interact_minPt * Acts::UnitConstants::MeV);
112  // get Geo and Mag map
113  ATH_MSG_VERBOSE(name() << " Getting per event Geo and Mag map");
114  Acts::MagneticFieldContext mctx = getMagneticFieldContext(ctx);
115  const ActsGeometryContext& gctx = m_trackingGeometryTool->getNominalGeometryContext();
116  auto anygctx = gctx.context();
117  // Loop over ISFParticleVector and process each separately
118  ATH_MSG_VERBOSE(name() << " Processing particles in ISFParticleVector.");
119  // For sihit creation
120  SiHitCollection pixelSiHits;
121  SiHitCollection sctSiHits;
122  for (const auto isfp : particles) {
123  // ====ACTSFatras Simulation====
124  // //
125  // input/output particle and hits containers
126  // Convert to ActsFatras::Particle
127  // ISF: Energy, mass, and momentum are in MeV, position in mm
128  // Acts: Energy, mass, and momentum are in GeV, position in mm
129  std::vector<ActsFatras::Particle> input = std::vector<ActsFatras::Particle>{
130  ActsFatras::Particle(ActsFatras::Barcode().setVertexPrimary(0).setParticle(
131  HepMC::barcode(isfp)), static_cast<Acts::PdgParticle>(isfp->pdgCode()),
132  isfp->charge(),isfp->mass() * Acts::UnitConstants::MeV)
133  .setDirection(Acts::makeDirectionFromPhiEta(
134  isfp->momentum().phi(), isfp->momentum().eta()))
135  .setAbsoluteMomentum(isfp->momentum().mag() * Acts::UnitConstants::MeV)
136  .setPosition4(isfp->position().x(), isfp->position().y(),
137  isfp->position().z(), isfp->timeStamp())};
138  std::vector<ActsFatras::Particle> simulatedInitial;
139  std::vector<ActsFatras::Particle> simulatedFinal;
140  std::vector<ActsFatras::Hit> hits;
141  ATH_MSG_DEBUG(name() << " Convert ISF::Particle " << isfp->barcode() << " to ActsFatras::Particle " << input[0].particleId().value());
142  ATH_MSG_DEBUG(name() << " Propagating ActsFatras::Particle vertex|particle|generation|subparticle, " << input[0]);
143  // simulate
144  auto result=simulator.simulate(anygctx, mctx, generator, input, simulatedInitial, simulatedFinal, hits);
145  auto simulatedFailure=result.value();
146  if (simulatedFailure.size()>0){
147  for (const auto& simfail : simulatedFailure){
148  auto errCode = Acts::make_error_code(Acts::PropagatorError(simfail.error.value()));
149  ATH_MSG_WARNING(name() << " Particle id " <<simfail.particle.particleId()<< ": fail to be simulated during Propagation: " << errCode.message());
150  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()));
151  return StatusCode::SUCCESS;
152  }
153  }
154 
155  ATH_MSG_DEBUG(name() << " initial particle " << simulatedInitial[0]);
156  ATH_MSG_DEBUG(name() << " ActsFatras simulator hits: " << hits.size());
157  int i = 0;
158  for (const auto& hit : hits) {
159  ATH_MSG_DEBUG(name() << " hit pos: " << hit.position() );
160  ++i;
161  if (i>5) break;
162  }
163  ATH_MSG_DEBUG(name() << " No. of particles after ActsFatras simulator: " << simulatedFinal.size());
164  if (simulatedFinal.size()>1){
165  ATH_MSG_DEBUG(name() << " start procesing secondaries");
166  // convert final particles to ISF::particle
167  auto isAlive = ISF::fPrimarySurvives;
168  // int generation = simulatedFinal[-1].particleId().generation();
169  int n = 1;
170  for (std::vector<ActsFatras::Particle>::iterator itr=simulatedFinal.begin()+1;itr!=simulatedFinal.end();++itr){
171  ATH_MSG_DEBUG(name() << " secondaries particle " <<n<<"/"<< simulatedFinal.size()-1<<": "<< *itr);
172  ++n;
173  const auto pos = Amg::Vector3D(itr->position()[Acts::ePos0],itr->position()[Acts::ePos1],itr->position()[Acts::ePos2]);
174  const auto mom = Amg::Vector3D(itr->fourMomentum()[Acts::eMom0] / Acts::UnitConstants::MeV,itr->fourMomentum()[Acts::eMom1] / Acts::UnitConstants::MeV,itr->fourMomentum()[Acts::eMom2] / Acts::UnitConstants::MeV);
175  double mass = itr->mass() / Acts::UnitConstants::MeV;
176  double charge = itr->charge();
177  int pdgid = itr->pdg();
178  double properTime = itr->properTime();
179  const int status = 1 + HepMC::SIM_STATUS_THRESHOLD;
180  const int id = HepMC::UNDEFINED_ID;
181  ATH_MSG_DEBUG(name() << " secondaries particle process code " << itr->process());
182  auto secisfp = new ISF::ISFParticle (pos,mom,mass,charge,pdgid,status,properTime,*isfp,id);
183  auto vecsecisfp = std::make_unique<ISF::ISFParticleVector>();
184  vecsecisfp->push_back(secisfp);
185  ATH_MSG_DEBUG(name() << " vecsecisfp barcode|p: " << (*vecsecisfp)[0]->barcode() <<"|"<< (*vecsecisfp)[0]->momentum().mag());
186  if(!itr->isAlive()) isAlive = ISF::fKillsPrimary;
187  ISF::ISFTruthIncident truth(*isfp,
188  *vecsecisfp,
189  getATLASProcessCode(itr->process()),
190  isfp->nextGeoID(), // inherits from the parent
191  isAlive
192  );
193  ATH_MSG_DEBUG(name() << " Truth incident physicsProcessCode()" << truth.physicsProcessCode());
194  m_truthRecordSvc->registerTruthIncident(truth, true);
196  ATH_MSG_DEBUG(name() << " Create secondariy ISF::Particle " << secisfp->barcode());
197  if (secisfp->getTruthBinding()) {
198  ATH_MSG_DEBUG(name() << " Save secondariy " << *secisfp);
199  secondaries.push_back(secisfp);
200  }
201  else {
202  ATH_MSG_WARNING("Secondary particle not written out to truth.\n Parent (" << isfp << ")\n Secondary (" << *secisfp <<")");
203  }
204  }
205  }//end of secondaries
206  ATH_MSG_VERBOSE(name() << " No. of secondaries: " << secondaries.size());
207  ATH_MSG_DEBUG(name() << " End of particle " << isfp->barcode());
208  m_ActsFatrasWriteHandler->createHits(*isfp, m_trackingGeometry,hits,pixelSiHits,sctSiHits);
209 
210  std::vector<ActsFatras::Particle>().swap(input);
211  std::vector<ActsFatras::Particle>().swap(simulatedInitial);
212  std::vector<ActsFatras::Particle>().swap(simulatedFinal);
213  std::vector<ActsFatras::Hit>().swap(hits);
214  } // end of isfp loop
215  std::vector<SiHitCollection> hitcolls;
216  hitcolls.push_back(pixelSiHits);
217  hitcolls.push_back(sctSiHits);
218  ATH_CHECK(m_ActsFatrasWriteHandler->WriteHits(hitcolls,ctx));
219  return StatusCode::SUCCESS;
220 }
221 
222 Acts::MagneticFieldContext ISF::ActsFatrasSimTool::getMagneticFieldContext(const EventContext& ctx) const {
223  SG::ReadCondHandle<AtlasFieldCacheCondObj> readHandle{m_fieldCacheCondObjInputKey, ctx};
224  if (!readHandle.isValid()) {
225  ATH_MSG_ERROR(name() + ": Failed to retrieve magnetic field condition data " + m_fieldCacheCondObjInputKey.key() + ".");
226  }
227  else ATH_MSG_DEBUG(name() << "retrieved magnetic field condition data "<< m_fieldCacheCondObjInputKey.key());
228  const AtlasFieldCacheCondObj* fieldCondObj{*readHandle};
229 
230  return Acts::MagneticFieldContext(fieldCondObj);
231 }
ISF::ISFParticleContainer
std::list< ISF::ISFParticle * > ISFParticleContainer
generic ISFParticle container (not necessarily a std::list!)
Definition: ISFParticleContainer.h:23
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
ISF::ActsFatrasSimTool::ChargedPropagator
Acts::Propagator< ChargedStepper, Navigator > ChargedPropagator
Definition: ActsFatrasSimTool.h:177
ISF::ActsFatrasSimTool::Generator
std::ranlux48 Generator
Definition: ActsFatrasSimTool.h:172
ISF::ISFTruthIncident::updateChildParticleProperties
void updateChildParticleProperties()
Update the id and particleLink properties of the child particles (to be called after registerTruthInc...
Definition: ISFTruthIncident.cxx:239
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
ISF::ISFTruthIncident::physicsProcessCode
int physicsProcessCode() const override final
Return specific physics process code of the truth incident (eg ionisation, bremsstrahlung,...
Definition: ISFTruthIncident.cxx:73
ISF::ActsFatrasSimTool::~ActsFatrasSimTool
virtual ~ActsFatrasSimTool()
Definition: ActsFatrasSimTool.cxx:22
TRTCalib_Extractor.hits
hits
Definition: TRTCalib_Extractor.py:35
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:180
Base_Fragment.mass
mass
Definition: Sherpa_i/share/common/Base_Fragment.py:59
ISF::ActsFatrasSimTool::ChargedStepper
Acts::EigenStepper< Acts::EigenStepperDefaultExtension > ChargedStepper
Definition: ActsFatrasSimTool.h:176
ActsTrk::detail::Navigator
Acts::Navigator Navigator
Definition: Tracking/Acts/ActsTrackReconstruction/src/detail/Definitions.h:31
python.SystemOfUnits.MeV
int MeV
Definition: SystemOfUnits.py:154
AtlasHitsVector
Definition: AtlasHitsVector.h:33
McEventCollection
McEventCollection
Definition: GeneratorObjectsTPCnv.cxx:60
ISF::ISFParticle
Definition: ISFParticle.h:42
ISFTruthIncident.h
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
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
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
ISF::ActsFatrasSimTool::simulateVector
virtual StatusCode simulateVector(const EventContext &ctx, const ISFParticleVector &particles, ISFParticleContainer &secondaries, McEventCollection *mcEventCollection, McEventCollection *shadowTruth=nullptr) override
Simulation call for vectors of particles.
Definition: ActsFatrasSimTool.cxx:77
ParticleGun_EoverP_Config.momentum
momentum
Definition: ParticleGun_EoverP_Config.py:63
ISF::ISFTruthIncident
Definition: ISFTruthIncident.h:35
lumiFormat.i
int i
Definition: lumiFormat.py:85
ISF::ActsFatrasSimTool::initialize
virtual StatusCode initialize() override
Definition: ActsFatrasSimTool.cxx:24
beamspotman.n
n
Definition: beamspotman.py:731
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
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:88
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
ISF::ActsFatrasSimTool::NeutralStepper
Acts::StraightLineStepper NeutralStepper
Definition: ActsFatrasSimTool.h:179
ISF::ActsFatrasSimTool::ActsFatrasSimTool
ActsFatrasSimTool(const std::string &type, const std::string &name, const IInterface *parent)
Definition: ActsFatrasSimTool.cxx:17
ActsGeometryContext
Include the GeoPrimitives which need to be put first.
Definition: ActsGeometryContext.h:27
HepMC::UNDEFINED_ID
constexpr int UNDEFINED_ID
Definition: MagicNumbers.h:56
HepMC::SIM_STATUS_THRESHOLD
constexpr int SIM_STATUS_THRESHOLD
Constant definiting the status threshold for simulated particles, eg. can be used to separate generat...
Definition: MagicNumbers.h:46
ISF::BaseSimulatorTool
Definition: BaseSimulatorTool.h:36
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:228
MagicNumbers.h
charge
double charge(const T &p)
Definition: AtlasPID.h:756
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:222
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:18
ISF::ActsFatrasSimTool::simulate
virtual StatusCode simulate(const EventContext &ctx, ISFParticle &isp, ISFParticleContainer &, McEventCollection *) override
Definition: ActsFatrasSimTool.cxx:59
ISF::BaseSimulatorTool::initialize
virtual StatusCode initialize() override
Definition: BaseSimulatorTool.h:57
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
merge.status
status
Definition: merge.py:17
ISF::fPrimarySurvives
@ fPrimarySurvives
Definition: ISFTruthIncident.h:24
ActsFatrasSimTool.h
mag
Scalar mag() const
mag method
Definition: AmgMatrixBasePlugin.h:26
ISF::fKillsPrimary
@ fKillsPrimary
Definition: ISFTruthIncident.h:25