109 const EventContext& ctx = Gaudi::Hive::currentContext();
122 const Acts::MagneticFieldContext mfContext = Acts::MagneticFieldContext(fieldCondObj);
124 auto anygctx = gctx->
context();
129 if (!trackingGeometry) {
131 return StatusCode::FAILURE;
135 using Stepper = Acts::EigenStepper<>;
136 using Navigator = Acts::Navigator;
137 using Propagator = Acts::Propagator<Stepper,Navigator>;
138 using ActorList = Acts::ActorList<Acts::detail::SteppingLogger, Acts::MaterialInteractor, Acts::EndOfWorldReached>;
139 using PropagatorOptions = Propagator::Options<ActorList>;
141 Navigator::Config navCfg;
142 navCfg.trackingGeometry = trackingGeometry;
143 navCfg.resolveSensitive =
true;
144 navCfg.resolveMaterial=
false;
145 navCfg.resolvePassive =
true;
149 auto bField = std::make_shared<ATLASMagneticFieldWrapper>();
150 auto bfieldCache = bField->makeCache(mfContext);
152 auto stepper = Stepper(bField);
154 PropagatorOptions options(anygctx, mfContext);
163 auto& materialInteractor = options.actorList.get<Acts::MaterialInteractor>();
164 materialInteractor.energyLoss =
false;
165 materialInteractor.multipleScattering =
false;
166 materialInteractor.recordInteractions =
false;
168 Propagator propagator(std::move(stepper), std::move(navigator),
173 ATH_MSG_DEBUG(
"Processing truth particle with PDG ID: " << truthParticle->pdgId() <<
" ,pT: "
174 << truthParticle->pt() <<
" , p: " << truthParticle->p4().P() <<
", eta: " << truthParticle->eta() <<
" , phi: " << truthParticle->phi());
177 if(std::abs(truthParticle->pdgId()) != 13 && std::abs(truthParticle->pdgId()) != 998) {
178 ATH_MSG_VERBOSE(
"Skipping truth particle with PDG ID: " << truthParticle->pdgId()<<
" only muons or charged geantinos are being processed");
182 Acts::ParticleHypothesis actsParticleHypothesis = truthParticle->pdgId() == 998 ?
183 Acts::ParticleHypothesis::chargedGeantino() : Acts::ParticleHypothesis::muon();
187 std::vector<std::pair<const xAOD::MuonSegment*, std::vector<const xAOD::MuonSimHit*>>> muonSegmentWithSimHits;
188 const SegLink_t& segLink = segAcc(*truthParticle);
189 if (segLink.empty()) {
190 ATH_MSG_WARNING(
"No segment link found for truth particle with PDG ID: " << truthParticle->pdgId());
193 for(
const auto& truthSegLink: segLink) {
199 std::vector<const xAOD::MuonSimHit*> muonSimHits{unordedHits.begin(), unordedHits.end()};
201 muonSegmentWithSimHits.emplace_back(seg,muonSimHits);
205 const auto& particle = truthParticle->p4();
211 : Amg::Vector3D::Zero();
222 if(muonSegmentWithSimHits.empty()) {
223 ATH_MSG_DEBUG(
"No segments found for truth particle with PDG ID: " << truthParticle->pdgId());
227 std::ranges::sort(muonSegmentWithSimHits,
228 [](
const auto&
a,
const auto& b) {
229 return a.first->position().perp() < b.first->position().perp();
234 std::vector<const xAOD::MuonSimHit*>& muonSimHits = muonSegmentWithSimHits.front().second;
235 std::ranges::sort(muonSimHits,
239 return globalPos1.norm()<globalPos2.norm();
243 for(
const auto& simHit: muonSimHits){
249 startPropPos =
toGlobalTrf(*gctx, muonSimHits.front()->identify())*xAOD::toEigen(muonSimHits.front()->localPosition());
250 startPropDir =
toGlobalTrf(*gctx, muonSimHits.front()->identify()).linear()*xAOD::toEigen(muonSimHits.front()->localDirection());
251 startPropP =
energyToActs(muonSimHits.front()->kineticEnergy());
254 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);
260 <<
Amg::toString(startPropDir)<<
" and momentum "<<startPropP);
264 Acts::BoundTrackParameters start = Acts::BoundTrackParameters::createCurvilinear(
265 Acts::VectorHelpers::makeVector4(startPropPos, 0.), startPropDir,
266 truthParticle->charge() / startPropP,
268 actsParticleHypothesis);
271 auto result = propagator.propagate(start, options);
272 const Acts::detail::SteppingLogger::result_type state =
result.value().get<Acts::detail::SteppingLogger::result_type>();
273 const Acts::MaterialInteractor::result_type material =
result.value().get<Acts::MaterialInteractor::result_type>();
278 std::vector<PropagatorRecorder> propagatedHits;
280 for(
const auto& step : state.steps) {
295 PropagatorRecorder newRecord{};
297 newRecord.actsPropPos = toGap*step.position;
298 newRecord.actsGlobalPos = step.position;
299 newRecord.actsPropDir = toGap.linear()*step.momentum.unit();
300 newRecord.actsPropabsMomentum = step.momentum.norm();
301 newRecord.actsStepSize = step.stepSize.value();
306 const auto* tubeSurf =
dynamic_cast<const Acts::StrawSurface*
>(&sCache->
surface());
309 Amg::Vector3D wireDir = toGap.linear()*tubeSurf->lineDirection(anygctx);
312 double distToWire =
Amg::lineDistance(wirePos, wireDir, localPropHit, dirPropHit);
313 newRecord.actsHitWireDist = distToWire;
318 propagatedHits.emplace_back(newRecord);
323 for (
const auto&[segment, simHits] : muonSegmentWithSimHits) {
328 const Amg::Vector3D localPos = xAOD::toEigen(simHit->localPosition());
331 const Amg::Vector3D localDir = xAOD::toEigen(simHit->localDirection());
352 auto it_begin = std::ranges::find_if(propagatedHits,
353 [
this,
ID](
const auto& propagatedHit) {
359 if(it_begin == propagatedHits.end()){
371 auto it_end = std::find_if(it_begin, propagatedHits.end(),
372 [
this,
ID](
const auto& propagatedHit) {
373 return m_idHelperSvc->detElId(ID) != m_idHelperSvc->detElId(propagatedHit.id) ||
374 layerHash(ID) != layerHash(propagatedHit.id);
378 auto it = std::min_element(it_begin, it_end,
379 [&localPos](
const PropagatorRecorder&
a,
380 const PropagatorRecorder& b){
381 return (localPos -
a.actsPropPos).mag() < (localPos - b.actsPropPos).
mag();
386 <<
" and global position: " <<
Amg::toString(it->actsGlobalPos)
400 m_event = ctx.eventID().event_number();
407 return StatusCode::SUCCESS;