10 #include "Acts/Definitions/Units.hpp"
11 #include "Acts/Propagator/ActorList.hpp"
12 #include "Acts/Propagator/Propagator.hpp"
13 #include "Acts/Propagator/MaterialInteractor.hpp"
14 #include "Acts/Propagator/EigenStepper.hpp"
15 #include "Acts/Propagator/AtlasStepper.hpp"
16 #include "Acts/Utilities/VectorHelpers.hpp"
17 #include "Acts/Visualization/ObjVisualization3D.hpp"
18 #include "Acts/Visualization/GeometryView3D.hpp"
19 #include "Acts/EventData/ParticleHypothesis.hpp"
20 #include "Acts/Propagator/detail/SteppingLogger.hpp"
31 using namespace Acts::UnitLiterals;
35 using SegLink_t = std::vector<ElementLink<xAOD::MuonSegmentContainer>>;
38 struct PropagatorRecorder{
54 double atlasPropabsMomentum{0.};
56 double actsPropabsMomentum{0.};
58 double actsStepSize{0.};
78 IdentifierHash MuonDetectorNavTest::layerHash(
const Identifier&
id)
const {
79 return m_r4DetMgr->getReadoutElement(
id)->layerHash(
id);
85 ATH_CHECK(m_fieldCacheCondObjInputKey.initialize());
86 ATH_CHECK(m_truthParticleKey.initialize());
87 ATH_CHECK(m_truthSegLinkKey.initialize());
91 ATH_CHECK(m_truthSegLinkKey.initialize());
96 return StatusCode::SUCCESS;
102 return StatusCode::SUCCESS;
106 const EventContext& ctx{Gaudi::Hive::currentContext()};
107 ATH_MSG_DEBUG(
"Execute in event "<<ctx.eventID().event_number());
108 m_event = ctx.eventID().event_number();
112 if (!gctx.isValid() or !truthParticles.isValid() or !magFieldHandle.isValid()) {
113 ATH_MSG_FATAL(
"Failed to retrieve either the geometry context, truth particles or magnetic field");
114 return StatusCode::FAILURE;
119 const Acts::GeometryContext geoContext = gctx->context();
121 Acts::MagneticFieldContext mfContext = Acts::MagneticFieldContext(fieldCondObj);
124 using Stepper = Acts::EigenStepper<>;
126 using Navigator = Acts::Experimental::DetectorNavigator;
127 using Propagator = Acts::Propagator<Stepper,Navigator>;
128 using ActorList = Acts::ActorList<Acts::detail::SteppingLogger, Acts::MaterialInteractor, Acts::EndOfWorldReached>;
129 using PropagatorOptions = Propagator::Options<ActorList>;
132 PropagatorOptions
options(geoContext, mfContext);
134 options.pathLimit = m_pathLimit;
135 options.stepping.maxStepSize = m_maxStepSize;
136 options.stepping.stepTolerance = m_stepTolerance;
138 options.maxTargetSkipping = m_maxTargetSkipping;
141 auto& materialInteractor =
options.actorList.get<Acts::MaterialInteractor>();
142 materialInteractor.energyLoss =
false;
143 materialInteractor.multipleScattering =
false;
144 materialInteractor.recordInteractions =
false;
148 Acts::Experimental::DetectorNavigator::Config navCfg;
150 navCfg.resolvePassive =
true;
152 auto bField = std::make_shared<ATLASMagneticFieldWrapper>();
153 auto bfieldCache = bField->makeCache(mfContext);
154 auto stepper =
Stepper(bField);
157 Acts::Experimental::DetectorNavigator navigator(navCfg, Acts::getDefaultLogger(
"DetectorNavigator",
ActsTrk::actsLevelVector(msgLevel())));
158 Acts::Propagator<Stepper, Acts::Experimental::DetectorNavigator> propagator(
159 std::move(stepper), std::move(navigator),
165 ATH_MSG_DEBUG(
"Consider truth particle "<<truthParticle->pt()<<
", "<<truthParticle->p4().P()<<
", "<<truthParticle->eta()<<
", "<<truthParticle->phi()
166 <<
", pdgId: "<<truthParticle->pdgId()<<
", status: "<<truthParticle->status()
167 <<
", unique id:"<<truthParticle->id());
170 std::vector<PropagatorRecorder> propagatedHits;
171 std::vector<std::pair<Identifier, Amg::Vector3D>> truthHits;
176 Acts::AnyCharge(truthParticle->charge()));
179 std::vector<std::pair<const xAOD::MuonSegment*, std::vector<const xAOD::MuonSimHit*>>> muonSegmentWithSimHits;
180 for (
const auto& truthSegLink : segAcc(*truthParticle)){
183 std::vector<const xAOD::MuonSimHit*> muonSimHits{unordedHits.begin(), unordedHits.end()};
185 muonSegmentWithSimHits.emplace_back(seg,muonSimHits);
187 const auto& particle = truthParticle->p4();
188 m_truthPt = particle.Pt();
189 m_truthP = particle.P();
199 double startPropP{particle.P()};
202 Amg::Vector3D magFieldPos{startPropPos.x()+
r, startPropPos.y()+
r, startPropPos.z()};
213 if(m_startFromFirstHit){
214 if (muonSegmentWithSimHits.empty()) {
218 std::ranges::sort(muonSegmentWithSimHits,
219 [](
const auto&
a,
const auto&
b) {
220 return a.first->position().
perp() <
b.first->position().perp();
224 std::vector<const xAOD::MuonSimHit*>& muonSimHits = muonSegmentWithSimHits.front().second;
226 for(
const auto& simHit: muonSimHits){
227 ATH_MSG_VERBOSE(
"Sim Hit of first segment at global position: "<<
Amg::toString(toGlobalTrf(*gctx, simHit->identify())*xAOD::toEigen(simHit->localPosition())));
232 std::ranges::sort(muonSimHits,
236 return globalPos1.norm()<globalPos2.norm();
240 for(
const auto& simHit: muonSimHits){
241 ATH_MSG_VERBOSE(
"Sim Hit of first segment at position: "<<
Amg::toString(toGlobalTrf(*gctx, simHit->identify())*xAOD::toEigen(simHit->localPosition())));
246 startPropPos = toGlobalTrf(*gctx, muonSimHits.front()->identify())*xAOD::toEigen(muonSimHits.front()->localPosition());
247 startPropDir = toGlobalTrf(*gctx, muonSimHits.front()->identify()).linear()*xAOD::toEigen(muonSimHits.front()->localDirection());
248 startPropP = muonSimHits.front()->kineticEnergy();
249 ATH_MSG_VERBOSE(
"Kinetic Energy from the simHit: "<<muonSimHits.front()->kineticEnergy() /
Gaudi::Units::GeV<<
" and mass: "<<muonSimHits.front()->mass()<<
" and energy deposit: "<<muonSimHits.front()->energyDeposit() /
Gaudi::Units::eV);
253 <<
Amg::toString(startPropDir)<<
" and momentum "<<startPropP);
256 Acts::BoundTrackParameters
start = Acts::BoundTrackParameters::createCurvilinear(
257 Acts::VectorHelpers::makeVector4(startPropPos, 0.), startPropDir,
258 truthParticle->charge() / startPropP,
267 const Acts::detail::SteppingLogger::result_type state =
result.value().get<Acts::detail::SteppingLogger::result_type>();
268 const Acts::MaterialInteractor::result_type material =
result.value().get<Acts::MaterialInteractor::result_type>();
269 ATH_MSG_DEBUG(
"Material interactions: " << material.materialInteractions.size());
272 std::vector<Acts::MaterialInteraction> interactions = material.materialInteractions;
273 for(
const Acts::MaterialInteraction& interaction : interactions){
274 ATH_MSG_DEBUG(
"Path Correction: " << interaction.pathCorrection);
279 Acts::ObjVisualization3D
helper{};
280 for (
const auto&
s : state.steps) {
281 if(
s.surface) Acts::GeometryView3D::drawSurface(
helper, *
s.surface, geoContext);
283 helper.write(
std::format(
"event_{:}_{:}_Hits.obj", ctx.eventID().event_number(), truthParticle->index()));
286 ATH_MSG_VERBOSE(
"Number of propagated steps : " << state.steps.size());
287 m_propSteps = state.steps.size();
288 m_propLength =
result.value().pathLength;
289 for(
const auto& state: state.steps){
300 ATH_MSG_VERBOSE(
"Identify propagated hit " << m_idHelperSvc->toString(
ID) <<
" with hit at local position " <<
Amg::toString(toGap*state.position)<<
" and global direction "<<
Amg::toString(state.momentum.unit()));
302 PropagatorRecorder newRecord{};
304 newRecord.actsPropPos = toGap*state.position;
305 newRecord.actsGlobalPos = state.position;
306 newRecord.actsPropDir = toGap.linear()*state.momentum.unit();
307 newRecord.actsPropabsMomentum = state.momentum.norm();
308 newRecord.actsStepSize = state.stepSize.value();
314 if(truthParticle->isMuon()){
319 std::unique_ptr<Trk::TrackParameters> atlasPars{m_extrapolator->extrapolate(ctx, atlasStart,
325 newRecord.atlasPropPos = toGap* atlasPars->position();
326 newRecord.atlasPropDir = toGap.linear()*atlasPars->momentum().unit();
327 newRecord.atlasPropabsMomentum = atlasPars->momentum().mag();
328 newRecord.atlasGlobalPos = atlasPars->position();
330 propagatedHits.emplace_back(newRecord);
333 std::size_t propHitsSize = propagatedHits.size();
336 unsigned int nMatchedTruth = 0, nMatchedProp = 0, nTruth{0};
337 for (
const auto&[
segment, simHits] : muonSegmentWithSimHits) {
343 toGlobalTrf(*gctx,simHit->identify())};
344 const Amg::Vector3D localPos = localTrf*xAOD::toEigen(simHit->localPosition());
345 const Amg::Vector3D globalPos = toGlobalTrf(*gctx, simHit->identify())*xAOD::toEigen(simHit->localPosition());
346 const Amg::Vector3D localDir = localTrf.linear()*xAOD::toEigen(simHit->localDirection());
347 m_detId.push_back(
ID);
348 m_techIdx.push_back(m_idHelperSvc->technologyIndex(
ID));
349 m_gasGapId.push_back(layerHash(
ID));
351 m_truthLoc.push_back(localPos);
352 m_truthDir.push_back(localDir);
353 m_truthGlob.push_back(globalPos);
354 m_startGlob.push_back(startPropPos);
357 auto it_begin = std::ranges::find_if(propagatedHits,
358 [
this,
ID, &localPos](
const auto& propagatedHit) {
359 return m_idHelperSvc->detElId(
ID) == m_idHelperSvc->detElId(propagatedHit.id) &&
360 layerHash(
ID) == layerHash(propagatedHit.id);
362 m_isPropagated.push_back(it_begin != propagatedHits.end());
364 if (it_begin == propagatedHits.end()) {
365 m_actsPropLoc.push_back(dummyPos);
366 m_actsPropDir.push_back(dummyPos);
367 m_atlasPropLoc.push_back(dummyPos);
368 m_atlasPropDir.push_back(dummyPos);
369 m_actsPropGlob.push_back(dummyPos);
370 m_atlasPropGlob.push_back(dummyPos);
371 m_actsPropMomentum.push_back(0.);
372 m_atlasPropMomentum.push_back(0.);
373 m_actsStepSize.push_back(0.);
376 auto it_end = std::find_if(it_begin, propagatedHits.end(),
377 [
this,
ID, &localPos](
const auto& propagatedHit) {
378 return m_idHelperSvc->detElId(ID) != m_idHelperSvc->detElId(propagatedHit.id) ||
379 layerHash(ID) != layerHash(propagatedHit.id);
382 auto it = std::min_element(it_begin, it_end,
383 [&localPos](
const PropagatorRecorder&
a,
384 const PropagatorRecorder&
b){
385 return (localPos -
a.actsPropPos).mag() < (localPos -
b.actsPropPos).mag();
389 ATH_MSG_DEBUG(
"Truth hit found in propagated hits: " << m_idHelperSvc->toString(
ID));
390 m_actsPropLoc.push_back(
it->actsPropPos);
391 m_actsPropDir.push_back(
it->actsPropDir);
392 m_actsPropGlob.push_back(
it->actsGlobalPos);
393 m_atlasPropLoc.push_back(
it->atlasPropPos);
394 m_atlasPropDir.push_back(
it->atlasPropDir);
395 m_atlasPropGlob.push_back(
it->atlasGlobalPos);
396 m_actsPropMomentum.push_back(
it->actsPropabsMomentum);
397 m_atlasPropMomentum.push_back(
it->atlasPropabsMomentum);
398 m_actsStepSize.push_back(
it->actsStepSize);
402 m_matchedTruthFraction = 1.f*nMatchedTruth / nTruth;
403 m_matchedPropFraction = 1.f*nMatchedProp / propHitsSize;
409 return StatusCode::SUCCESS;