121 const Acts::MagneticFieldContext mfContext = Acts::MagneticFieldContext(fieldCondObj);
123 auto anygctx = gctx->
context();
128 if (!trackingGeometry) {
130 return StatusCode::FAILURE;
134 using Stepper = Acts::EigenStepper<>;
135 using Navigator = Acts::Navigator;
136 using Propagator = Acts::Propagator<Stepper,Navigator>;
137 using ActorList = Acts::ActorList<Acts::detail::SteppingLogger, Acts::MaterialInteractor, Acts::EndOfWorldReached>;
138 using PropagatorOptions = Propagator::Options<ActorList>;
140 Navigator::Config navCfg;
141 navCfg.trackingGeometry = trackingGeometry;
142 navCfg.resolveSensitive =
true;
143 navCfg.resolveMaterial=
false;
144 navCfg.resolvePassive =
true;
148 auto bField = std::make_shared<ATLASMagneticFieldWrapper>();
149 auto bfieldCache = bField->makeCache(mfContext);
151 auto stepper = Stepper(bField);
153 PropagatorOptions options(anygctx, mfContext);
162 auto& materialInteractor = options.actorList.get<Acts::MaterialInteractor>();
163 materialInteractor.energyLoss =
false;
164 materialInteractor.multipleScattering =
false;
165 materialInteractor.recordInteractions =
false;
167 Propagator propagator(std::move(stepper), std::move(navigator),
172 ATH_MSG_DEBUG(
"Processing truth particle with PDG ID: " << truthParticle->pdgId() <<
" ,pT: "
173 << truthParticle->pt() <<
" , p: " << truthParticle->p4().P() <<
", eta: " << truthParticle->eta() <<
" , phi: " << truthParticle->phi());
176 if(std::abs(truthParticle->pdgId()) != 13 && std::abs(truthParticle->pdgId()) != 998) {
177 ATH_MSG_VERBOSE(
"Skipping truth particle with PDG ID: " << truthParticle->pdgId()<<
" only muons or charged geantinos are being processed");
181 Acts::ParticleHypothesis actsParticleHypothesis = truthParticle->pdgId() == 998 ?
182 Acts::ParticleHypothesis::chargedGeantino() : Acts::ParticleHypothesis::muon();
186 std::vector<std::pair<const xAOD::MuonSegment*, std::vector<const xAOD::MuonSimHit*>>> muonSegmentWithSimHits;
187 const SegLink_t& segLink = segAcc(*truthParticle);
188 if (segLink.empty()) {
189 ATH_MSG_WARNING(
"No segment link found for truth particle with PDG ID: " << truthParticle->pdgId());
192 for(
const auto& truthSegLink: segLink) {
198 std::vector<const xAOD::MuonSimHit*> muonSimHits{unordedHits.begin(), unordedHits.end()};
200 muonSegmentWithSimHits.emplace_back(seg,muonSimHits);
204 const auto& particle = truthParticle->p4();
210 : Amg::Vector3D::Zero();
221 if(muonSegmentWithSimHits.empty()) {
222 ATH_MSG_DEBUG(
"No segments found for truth particle with PDG ID: " << truthParticle->pdgId());
226 std::ranges::sort(muonSegmentWithSimHits,
227 [](
const auto&
a,
const auto& b) {
228 return a.first->position().perp() < b.first->position().perp();
233 std::vector<const xAOD::MuonSimHit*>& muonSimHits = muonSegmentWithSimHits.front().second;
234 std::ranges::sort(muonSimHits,
238 return globalPos1.norm()<globalPos2.norm();
242 for(
const auto& simHit: muonSimHits){
248 startPropPos =
toGlobalTrf(*gctx, muonSimHits.front()->identify())*xAOD::toEigen(muonSimHits.front()->localPosition());
249 startPropDir =
toGlobalTrf(*gctx, muonSimHits.front()->identify()).linear()*xAOD::toEigen(muonSimHits.front()->localDirection());
250 startPropP =
energyToActs(muonSimHits.front()->kineticEnergy());
253 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);
259 <<
Amg::toString(startPropDir)<<
" and momentum "<<startPropP);
263 Acts::BoundTrackParameters start = Acts::BoundTrackParameters::createCurvilinear(
264 Acts::VectorHelpers::makeVector4(startPropPos, 0.), startPropDir,
265 truthParticle->charge() / startPropP,
267 actsParticleHypothesis);
270 auto result = propagator.propagate(start, options);
271 const Acts::detail::SteppingLogger::result_type state = result.value().get<Acts::detail::SteppingLogger::result_type>();
272 const Acts::MaterialInteractor::result_type material = result.value().get<Acts::MaterialInteractor::result_type>();
277 std::vector<PropagatorRecorder> propagatedHits;
279 for(
const auto& step : state.steps) {
294 PropagatorRecorder newRecord{};
296 newRecord.actsPropPos = toGap*step.position;
297 newRecord.actsGlobalPos = step.position;
298 newRecord.actsPropDir = toGap.linear()*step.momentum.unit();
299 newRecord.actsPropabsMomentum = step.momentum.norm();
300 newRecord.actsStepSize = step.stepSize.value();
305 const auto* tubeSurf =
dynamic_cast<const Acts::StrawSurface*
>(&sCache->
surface());
308 Amg::Vector3D wireDir = toGap.linear()*tubeSurf->lineDirection(anygctx);
311 double distToWire =
Amg::lineDistance(wirePos, wireDir, localPropHit, dirPropHit);
312 newRecord.actsHitWireDist = distToWire;
317 propagatedHits.emplace_back(newRecord);
322 for (
const auto&[segment, simHits] : muonSegmentWithSimHits) {
327 const Amg::Vector3D localPos = xAOD::toEigen(simHit->localPosition());
330 const Amg::Vector3D localDir = xAOD::toEigen(simHit->localDirection());
351 auto it_begin = std::ranges::find_if(propagatedHits,
352 [
this, ID](
const auto& propagatedHit) {
358 if(it_begin == propagatedHits.end()){
370 auto it_end = std::find_if(it_begin, propagatedHits.end(),
371 [
this, ID](
const auto& propagatedHit) {
372 return m_idHelperSvc->detElId(ID) != m_idHelperSvc->detElId(propagatedHit.id) ||
373 layerHash(ID) != layerHash(propagatedHit.id);
377 auto it = std::min_element(it_begin, it_end,
378 [&localPos](
const PropagatorRecorder&
a,
379 const PropagatorRecorder& b){
380 return (localPos -
a.actsPropPos).mag() < (localPos - b.actsPropPos).
mag();
385 <<
" and global position: " <<
Amg::toString(it->actsGlobalPos)
399 m_event = ctx.eventID().event_number();
406 return StatusCode::SUCCESS;