123 const Acts::MagneticFieldContext mfContext = Acts::MagneticFieldContext(fieldCondObj);
125 auto anygctx = gctx->
context();
130 if (!trackingGeometry) {
132 return StatusCode::FAILURE;
136 using Stepper = Acts::EigenStepper<>;
137 using Navigator = Acts::Navigator;
138 using Propagator = Acts::Propagator<Stepper,Navigator>;
139 using ActorList = Acts::ActorList<Acts::detail::SteppingLogger, Acts::MaterialInteractor, Acts::EndOfWorldReached>;
140 using PropagatorOptions = Propagator::Options<ActorList>;
142 Navigator::Config navCfg;
143 navCfg.trackingGeometry = trackingGeometry;
144 navCfg.resolveSensitive =
true;
145 navCfg.resolveMaterial=
false;
146 navCfg.resolvePassive =
true;
150 auto bField = std::make_shared<ATLASMagneticFieldWrapper>();
151 auto bfieldCache = bField->makeCache(mfContext);
153 auto stepper = Stepper(bField);
155 PropagatorOptions options(anygctx, mfContext);
164 auto& materialInteractor = options.actorList.get<Acts::MaterialInteractor>();
165 materialInteractor.energyLoss =
false;
166 materialInteractor.multipleScattering =
false;
167 materialInteractor.recordInteractions =
false;
169 Propagator propagator(std::move(stepper), std::move(navigator),
174 ATH_MSG_DEBUG(
"Processing truth particle with PDG ID: " << truthParticle->pdgId() <<
" ,pT: "
175 << truthParticle->pt() <<
" , p: " << truthParticle->p4().P() <<
", eta: " << truthParticle->eta() <<
" , phi: " << truthParticle->phi());
178 if(std::abs(truthParticle->pdgId()) != 13 && std::abs(truthParticle->pdgId()) != 998) {
179 ATH_MSG_VERBOSE(
"Skipping truth particle with PDG ID: " << truthParticle->pdgId()<<
" only muons or charged geantinos are being processed");
183 Acts::ParticleHypothesis actsParticleHypothesis = truthParticle->pdgId() == 998 ?
184 Acts::ParticleHypothesis::chargedGeantino() : Acts::ParticleHypothesis::muon();
188 std::vector<std::pair<const xAOD::MuonSegment*, std::vector<const xAOD::MuonSimHit*>>> muonSegmentWithSimHits;
189 const SegLink_t& segLink = segAcc(*truthParticle);
190 if (segLink.empty()) {
191 ATH_MSG_WARNING(
"No segment link found for truth particle with PDG ID: " << truthParticle->pdgId());
194 for(
const auto& truthSegLink: segLink) {
200 std::vector<const xAOD::MuonSimHit*> muonSimHits{unordedHits.begin(), unordedHits.end()};
202 muonSegmentWithSimHits.emplace_back(seg,muonSimHits);
206 const auto& particle = truthParticle->p4();
209 m_eta = particle.Eta();
210 m_phi = particle.Phi();
214 : Amg::Vector3D::Zero();
225 if(muonSegmentWithSimHits.empty()) {
226 ATH_MSG_DEBUG(
"No segments found for truth particle with PDG ID: " << truthParticle->pdgId());
230 std::ranges::sort(muonSegmentWithSimHits,
231 [](
const auto&
a,
const auto& b) {
232 return a.first->position().perp() < b.first->position().perp();
237 std::vector<const xAOD::MuonSimHit*>& muonSimHits = muonSegmentWithSimHits.front().second;
238 std::ranges::sort(muonSimHits,
242 return globalPos1.norm()<globalPos2.norm();
246 for(
const auto& simHit: muonSimHits){
252 startPropPos =
toGlobalTrf(*gctx, muonSimHits.front()->identify())*xAOD::toEigen(muonSimHits.front()->localPosition());
253 startPropDir =
toGlobalTrf(*gctx, muonSimHits.front()->identify()).linear()*xAOD::toEigen(muonSimHits.front()->localDirection());
254 startPropP =
energyToActs(muonSimHits.front()->kineticEnergy());
257 ATH_MSG_VERBOSE(
"Kinetic Energy from the simHit: "<<startPropP / Gaudi::Units::GeV<<
" and mass: "<<muonSimHits.front()->mass()<<
" and energy deposit: "<<muonSimHits.front()->energyDeposit() / Gaudi::Units::eV);
263 <<
Amg::toString(startPropDir)<<
" and momentum "<<startPropP);
267 Acts::BoundTrackParameters start = Acts::BoundTrackParameters::createCurvilinear(
268 Acts::VectorHelpers::makeVector4(startPropPos, 0.), startPropDir,
269 truthParticle->charge() / startPropP,
271 actsParticleHypothesis);
276 const auto propagationStart = std::chrono::steady_clock::now();
277 auto result = propagator.propagate(start, options);
278 const auto propagationEnd = std::chrono::steady_clock::now();
280 const Acts::detail::SteppingLogger::result_type state = result.value().get<Acts::detail::SteppingLogger::result_type>();
281 const Acts::MaterialInteractor::result_type material = result.value().get<Acts::MaterialInteractor::result_type>();
284 m_propTime = (std::chrono::duration<double>(propagationEnd - propagationStart).count()) * 1000;
288 std::vector<PropagatorRecorder> propagatedHits;
290 for(
const auto& step : state.steps) {
295 const auto* sCache =
dynamic_cast<const ISurfacePlacement*
>(step.surface->surfacePlacement());
305 PropagatorRecorder newRecord{};
307 newRecord.actsPropPos = toGap*step.position;
308 newRecord.actsGlobalPos = step.position;
309 newRecord.actsPropDir = toGap.linear()*step.momentum.unit();
310 newRecord.actsPropabsMomentum = step.momentum.norm();
311 newRecord.actsStepSize = step.stepSize.value();
316 const auto* tubeSurf =
dynamic_cast<const Acts::StrawSurface*
>(&sCache->surface());
319 Amg::Vector3D wireDir = toGap.linear()*tubeSurf->lineDirection(anygctx);
322 double distToWire =
Amg::lineDistance(wirePos, wireDir, localPropHit, dirPropHit);
323 newRecord.actsHitWireDist = distToWire;
328 propagatedHits.emplace_back(newRecord);
333 for (
const auto&[segment, simHits] : muonSegmentWithSimHits) {
338 const Amg::Vector3D localPos = xAOD::toEigen(simHit->localPosition());
341 const Amg::Vector3D localDir = xAOD::toEigen(simHit->localDirection());
362 auto it_begin = std::ranges::find_if(propagatedHits,
363 [
this, ID](
const auto& propagatedHit) {
369 if(it_begin == propagatedHits.end()){
381 auto it_end = std::find_if(it_begin, propagatedHits.end(),
382 [
this, ID](
const auto& propagatedHit) {
383 return m_idHelperSvc->detElId(ID) != m_idHelperSvc->detElId(propagatedHit.id) ||
384 layerHash(ID) != layerHash(propagatedHit.id);
388 auto it = std::min_element(it_begin, it_end,
389 [&localPos](
const PropagatorRecorder&
a,
390 const PropagatorRecorder& b){
391 return (localPos -
a.actsPropPos).mag() < (localPos - b.actsPropPos).
mag();
396 <<
" and global position: " <<
Amg::toString(it->actsGlobalPos)
410 m_event = ctx.eventID().event_number();
417 return StatusCode::SUCCESS;