95 {
96
97 std::vector<ISFParticle*> selectedParticles;
98 for (const auto isfp : particles) {
100 ATH_MSG_VERBOSE(
"ISFParticle " << *isfp <<
" does not pass selection. Ignoring.");
101 continue;
102 }
103 selectedParticles.push_back(isfp);
104 }
105 if (selectedParticles.empty()) {
107 return StatusCode::SUCCESS;
108 }
109
111 CLHEP::HepRandomEngine* randomEngine = m_randomEngine->getEngine(ctx);
115 << selectedParticles.size() << " particles for simulation.");
116
117
119 auto bField = std::make_shared<ATLASMagneticFieldWrapper>();
128
137
138 simulator.charged.interactions = ActsFatras::makeStandardChargedElectroMagneticInteractions(
m_interact_minPt * Acts::UnitConstants::MeV);
139
140
142
143
147
149 for (const auto isfp : selectedParticles) {
150
151
152
153
154
155
156 ATH_MSG_DEBUG(
name() <<
" Convert ISF::Particle(mass) " << isfp->id()<<
"|" << *isfp<<
"(" << isfp->mass() <<
")");
157 std::vector<ActsFatras::Particle>
input = std::vector<ActsFatras::Particle>{
158 ActsFatras::Particle(ActsFatras::Barcode().withVertexPrimary(0).withParticle(isfp->id()), static_cast<Acts::PdgParticle>(isfp->pdgCode()),
159 isfp->charge(),isfp->mass() * Acts::UnitConstants::MeV)
160 .setDirection(Acts::makeDirectionFromPhiEta(isfp->momentum().phi(), isfp->momentum().eta()))
161 .setAbsoluteMomentum(isfp->momentum().mag() * Acts::UnitConstants::MeV)
163 ATH_MSG_DEBUG(
name() <<
" Propagating ActsFatras::Particle vertex|particle|generation|subparticle, " << input[0]);
164 std::vector<ActsFatras::Particle> simulatedInitial;
165 std::vector<ActsFatras::Particle> simulatedFinal;
166 std::vector<ActsFatras::Hit>
hits;
167
168 auto result=simulator.simulate(anygctx, mctx, generator, input, simulatedInitial, simulatedFinal, hits);
169 auto simulatedFailure=
result.value();
170 if (simulatedFailure.size()>0){
171 for (const auto& simfail : simulatedFailure){
172 auto errCode = Acts::make_error_code(Acts::PropagatorError(simfail.error.value()));
173 ATH_MSG_WARNING(
name() <<
" Particle id " <<simfail.particle.particleId()<<
": fail to be simulated during Propagation: " << errCode.message());
174 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()));
175 return StatusCode::SUCCESS;
176 }
177 }
178
182 for (const auto& hit : hits) {
185 if (i>5) break;
186 }
187 ATH_MSG_DEBUG(
name() <<
" No. of particles after ActsFatras simulator: " << simulatedFinal.size());
188 if (!simulatedFinal.empty()){
190 auto itr = simulatedFinal.begin();
191
192 std::vector<ActsFatras::Hit> particle_hits;
193 if (itr->numberOfHits() > 0) {
194 std::copy(
hits.begin(),
hits.begin()+itr->numberOfHits(), std::back_inserter(particle_hits));
196 }
197
198 auto isKilled = !itr->isAlive();
199 int maxGeneration = simulatedFinal.back().particleId().generation();
201 for (
int gen = 0;
gen <= maxGeneration; ++
gen){
202 ATH_MSG_DEBUG(
name() <<
" start with generation "<< gen <<
"|" << maxGeneration <<
": "<< *itr);
203 auto vecsecisfp = std::make_unique<ISF::ISFParticleVector>();
204 std::unique_ptr<ISF::ISFParticle> newisfp = nullptr;
205
206 while (itr != simulatedFinal.end() && static_cast<int>(itr->particleId().generation()) == gen) {
207 ATH_MSG_DEBUG(
name() <<
" genration "<< gen <<
"|" << maxGeneration <<
": "<< *itr);
208 if(itr->isSecondary()){
209
212 double mass = itr->mass() / Acts::UnitConstants::MeV;
213 double charge = itr->charge();
214 int pdgid = itr->pdg();
218 auto secisfp = std::make_unique<ISF::ISFParticle>(pos,mom,mass,
charge,pdgid,status,properTime,*isfp,
id);
219 secisfp->setNextGeoID(
m_geoIDSvc->identifyNextGeoID(*secisfp));
222 << " pos=" << secisfp->position() << " mom=" << secisfp->momentum()
223 <<
" GeoID=" <<
m_geoIDSvc->identifyNextGeoID(*secisfp));
224 vecsecisfp->push_back(secisfp.release());
225 }
226 else{
227
229
230 if (!isKilled) {
231 auto fisfp = std::make_unique<ISF::ISFParticle>(*isfp);
234 ATH_MSG_DEBUG(
name() <<
" After simulation, primary particle state: " << *fisfp);
236 ATH_MSG_VERBOSE(
"ISFParticle" << fisfp <<
" after simulation does not pass selection. Ignoring for boundary check.");
237 continue;
238 }
240 <<
" new particle GeoID: " <<
m_geoIDSvc->identifyGeoID(*fisfp)
241 <<
", nextGeoID: " <<
m_geoIDSvc->identifyNextGeoID(*fisfp));
242
243
245
246
247 Acts::BoundTrackParameters startParams = Acts::BoundTrackParameters::createCurvilinear(
248 itr->fourPosition(), itr->direction(), itr->qOverP(), std::nullopt, itr->hypothesis());
249
250
251 auto do_exit_startsurface =
checkStartSurface(mctx, anygctx, surfaceCheckPropagator, startParams);
252 ATH_MSG_DEBUG(
name() <<
" checkStartSurface returned: " << do_exit_startsurface);
253 if (do_exit_startsurface) {
254 ATH_MSG_DEBUG(
name() <<
" Particle starts at a valid surface, doing extrapolation...");
255
256
259 try {
260 auto stepsResult =
m_extrapolationTool->propagationSteps(ctx, startParams, Acts::Direction::Forward());
261 auto steps = stepsResult.value().first;
263 if (
steps.size() != 0) {
264 for (const auto& step : steps) {
266 <<
" (eta " << Acts::VectorHelpers::eta(
step.position)
267 <<
") with GeoID " <<
step.geoID);
269 nextGeoID =
m_geoIDSvc->identifyGeoID(entryPos);
273 break;
274 }
275 }
276 } else {
278 }
279 }
280 catch (const std::exception& e) {
282 break;
283 }
284
287 double mass = itr->mass() / Acts::UnitConstants::MeV;
288 double charge = itr->charge();
289 int pdgid = itr->pdg();
291
292
293 newisfp = std::make_unique<ISF::ISFParticle>(entryPos, mom, mass,
charge, pdgid, isfp->status(), properTime, *isfp, isfp->id(), isfp->barcode());
294 newisfp->setNextGeoID(nextGeoID);
295 ATH_MSG_DEBUG(
name() <<
" Truthbinding of parent ISFParticle: " << (isfp->getTruthBinding() ?
"exists" :
"null"));
296 if (isfp->getTruthBinding()) {
297 ATH_MSG_DEBUG(
name() <<
" Current GenParticle: " << isfp->getTruthBinding()->getCurrentGenParticle());
298 }
301 << "(" << nextGeoID << ")");
302 }
303
304
308 << "(" << newisfp->nextGeoID() << ")");
309
310
312
313 switch(nextGeoID) {
317 break;
321 break;
322 default:
324 break;
325 }
326
328 vecsecisfp->push_back(newisfp.release());
329 } else {
331 }
332 }
333 }
334 else {
335 ATH_MSG_DEBUG(
name() <<
" No starting surface found, skipping boundary check and extrapolation.");
336 }
337 }
338 }
339 ++itr;
340 }
341
342
343 if (!vecsecisfp->empty()) {
344
345 int processCode = 0;
348
349 if (newisfp) {
350
351 processCode = 91;
352 geoID = newisfp->nextGeoID();
354 } else {
355
360 }
361
362 ISF::ISFTruthIncident truth(*isfp,
363 *vecsecisfp,
364 processCode,
365 geoID,
366 isParentKilled);
367
368 ATH_MSG_DEBUG(
name() <<
" Truth incident parentPt2(MinPt2) " << truth.parentPt2() <<
" (100 MeV)");
369 ATH_MSG_DEBUG(
name() <<
" Truth incident ChildPt2(MinPt2) " << truth.childrenPt2Pass(300) <<
" (300 MeV)");
371 truth.updateParentAfterIncidentProperties();
372 truth.updateChildParticleProperties();
373 for (auto *secisfp : *vecsecisfp){
374 if (secisfp->getTruthBinding()) {
375 secondaries.push_back(secisfp);
377 << *isfp << ")\n Secondary (" << *secisfp <<")");
378
379 ATH_MSG_DEBUG(
"Secondary particle push back to ISF, TruthBinding: " << secisfp->getTruthBinding()->getCurrentGenParticle() <<
" (current) | " << secisfp->getTruthBinding()->getPrimaryGenParticle() <<
" (primary) | " << secisfp->getTruthBinding()->getGenerationZeroGenParticle() <<
" (zero)");
380 if (secisfp->getTruthBinding()->getCurrentGenParticle() !=
nullptr)
ATH_MSG_DEBUG(
"Secondary particle GenParticle EndVertex: " << (secisfp->getTruthBinding()->getCurrentGenParticle()->end_vertex() ?
HepMC::barcode(secisfp->getTruthBinding()->getCurrentGenParticle()->end_vertex()) : 1));
381 } else {
382 ATH_MSG_WARNING(
"Secondary particle not written out to truth.\n Parent ("
383 << *isfp << ")\n Secondary (" << *secisfp <<")");
384 delete secisfp;
385 }
386 }
387 }
388 }
389 }
392
393 std::vector<ActsFatras::Particle>().swap(input);
394 std::vector<ActsFatras::Particle>().swap(simulatedInitial);
395 std::vector<ActsFatras::Particle>().swap(simulatedFinal);
396 std::vector<ActsFatras::Hit>().swap(hits);
397 }
398 return StatusCode::SUCCESS;
399}
double charge(const T &p)
static const char * getName(int region)
const std::string process
std::pair< Amg::Vector3D, double > convertMomFromActs(const Acts::Vector4 &actsMom)
Converts an Acts four-momentum vector into an pair of an Athena three-momentum and the paritcle's ene...
constexpr double timeToAthena(T actsT)
Converts a time unit from Acts to Athena units.
std::pair< Amg::Vector3D, double > convertPosFromActs(const Acts::Vector4 &actsPos)
Converts an Acts 4-vector into a pair of an Athena spatial vector and the passed time.
Acts::Vector4 convertPosToActs(const Amg::Vector3D &athenaPos, const double athenaTime=0.)
Converts a position vector & time from Athena units into Acts units.
AtlasRegion
A simple enum of ATLAS regions and sub-detectors.
constexpr int UNDEFINED_ID
constexpr int SIM_STATUS_THRESHOLD
Constant definiting the status threshold for simulated particles, eg. can be used to separate generat...
EntryLayer
Identifiers for the TrackRecordCollections on the boundaries between CaloEntry: Inner Detector - Calo...
generator
Configure Herwig7 These are the commands corresponding to what would go into the regular Herwig infil...