2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
5#include "ActsGeometry/ActsDetectorElement.h"
6#include <PixelReadoutGeometry/PixelModuleDesign.h>
7#include "InDetReadoutGeometry/SiDetectorElement.h"
8#include "InDetMeasurementUtilities/Helpers.h"
9#include "Acts/Surfaces/PlaneSurface.hpp"
11#include "TrackStateFlagHelper.h"
15namespace ActsTrk::detail {
17template <typename traj_t>
18const InDetDD::SiDetectorElement&
19PixelClusterCalibratorCommon<traj_t>::getDetectorElement(const Acts::Surface &surface) const
21 const ActsDetectorElement* detElem = dynamic_cast<const ActsDetectorElement*>(surface.surfacePlacement());
22 const InDetDD::SiDetectorElement *
23 siDetElement = detElem ? dynamic_cast<const InDetDD::SiDetectorElement *>(detElem->upstreamDetectorElement())
26 throw std::runtime_error("SiDetectorElement is NULL");
31template <typename traj_t>
32std::pair<float, float>
33PixelClusterCalibratorCommon<traj_t>::tanAnglesOfIncidence(const EventContext &ctx,
34 const Acts::GeometryContext& gctx,
35 const Acts::Surface &surface,
36 const InDetDD::SiDetectorElement& element,
37 const Acts::Vector3& direction) const
39 // to ensure that referenceFrame can be called with dummy direction and position
40 assert(dynamic_cast<const Acts::PlaneSurface *>(&surface) != nullptr);
41 static const Acts::Vector3 dummy=Acts::Vector3::Zero();
42 Acts::Vector3 projection = surface.referenceFrame(gctx, dummy,dummy).transpose() * direction;
44 float projPhi = direction.dot(element.phiAxis());
45 float projEta = direction.dot(element.etaAxis());
46 float projNorm = direction.dot(element.normal());
47 assert( std::abs(projection[0] - projPhi) < std::abs(projPhi) * std::numeric_limits<float>::epsilon() *2.);
48 assert( std::abs(projection[1] - projEta) < std::abs(projEta) * std::numeric_limits<float>::epsilon() *2.);
49 assert( std::abs(projection[2] - projNorm) < std::abs(projNorm) * std::numeric_limits<float>::epsilon() *2.);
52 double inv_proj_norm = 1./projection[2];
53 double tan_phi = projection[0]*inv_proj_norm;
54 double tan_theta = projection[1]*inv_proj_norm;
56 // Subtract the Lorentz angle effect
57 double angleShift = m_baseOptions.m_lorentzAngleTool->getTanLorentzAngle(element.identifyHash(), ctx);
58 tan_phi -= element.design().readoutSide() * angleShift;
60 return std::make_pair(static_cast<float>(tan_phi), static_cast<float>(tan_theta));
63template <typename derived_t, typename traj_t>
65PixelClusterCalibratorBase<derived_t, traj_t>::calibrate(
66 const Acts::GeometryContext& gctx,
67 const Acts::CalibrationContext& cctx,
68 const xAOD::PixelCluster& cluster,
69 typename PixelClusterCalibratorBase<derived_t, traj_t>::TrackStateProxy& trackState) const
71 const EventContext& ctx = *cctx.get<const EventContext*>();
72 const InDetDD::SiDetectorElement &detElement = this->getDetectorElement(trackState.referenceSurface());
73 Acts::Vector3 direction = Acts::makeDirectionFromPhiTheta(trackState.parameters()[Acts::eBoundPhi],
74 trackState.parameters()[Acts::eBoundTheta]);
75 auto [pos,cov,flags] = derived().calibrate(ctx, gctx, cctx, cluster, detElement, this->tanAnglesOfIncidence(ctx,
77 trackState.referenceSurface(),
80 assert( !trackState.hasCalibrated());
81 trackState.allocateCalibrated(2);
82 trackState.template calibrated<2>() = pos.template cast<double>();
83 trackState.template calibratedCovariance<2>() = cov.template cast<double>();
84 if (testTrackStateFlag(Acts::TrackStateFlag::IsSplitHit, flags)) {
85 trackState.typeFlags().setIsSplitHit();
89template <typename derived_t, typename traj_t>
90std::tuple<typename PixelClusterCalibratorCommon<traj_t>::Pos,
91 typename PixelClusterCalibratorCommon<traj_t>::Cov,
93PixelClusterCalibratorBase<derived_t, traj_t>::calibrate(const Acts::GeometryContext& gctx,
94 const Acts::CalibrationContext& cctx,
95 const Acts::Surface& surface,
96 const xAOD::PixelCluster& cluster,
97 const Acts::BoundTrackParameters& bound_parameters) const
99 const EventContext& ctx = *cctx.get<const EventContext*>();
100 const InDetDD::SiDetectorElement &detElement = this->getDetectorElement(surface);
101 Acts::Vector3 direction = Acts::makeDirectionFromPhiTheta(bound_parameters.parameters()[Acts::eBoundPhi],
102 bound_parameters.parameters()[Acts::eBoundTheta]);
103 return this->derived().calibrate(ctx, gctx, cctx, cluster, detElement, this->tanAnglesOfIncidence(ctx,
110template <typename derived_t, typename traj_t>
112PixelClusterCalibratorBase<derived_t, traj_t>
113 ::connectOnTrackCalibrator(PixelClusterCalibratorBase<derived_t, traj_t>::OnTrackCalibrator& calibrator) const
115 using CalibFuncPtr_t =
116 void(PixelClusterCalibratorBase<derived_t, traj_t>:: *)(const Acts::GeometryContext&,
117 const Acts::CalibrationContext&,
118 const xAOD::PixelCluster&,
119 TrackStateProxy&) const;
121 calibrator. template connect<static_cast<CalibFuncPtr_t>(&PixelClusterCalibratorBase<derived_t, traj_t>::calibrate)>(this);
125template <typename derived_t, typename traj_t>
127PixelClusterCalibratorBase<derived_t,traj_t>
128 ::connectCalibrator(typename PixelClusterCalibratorBase<derived_t,traj_t>::Calibrator &calibrator) const {
129 using CalibFuncPtr_t =
130 std::tuple<typename PixelClusterCalibratorCommon<traj_t>::Pos,
131 typename PixelClusterCalibratorCommon<traj_t>::Cov,
133 (PixelClusterCalibratorBase<derived_t, traj_t>:: *)(const Acts::GeometryContext&,
134 const Acts::CalibrationContext&,
135 const Acts::Surface&,
136 const xAOD::PixelCluster&,
137 const Acts::BoundTrackParameters&) const;
139 calibrator.template connect<static_cast<CalibFuncPtr_t>(&PixelClusterCalibratorBase<derived_t, traj_t>::calibrate)>(this);
142template <typename traj_t>
143StatusCode PixelClusterCalibrationToolBase<traj_t>::initialize()
145 ATH_CHECK(m_lorentzAngleTool.retrieve());
146 ATH_CHECK(AthAlgTool::detStore()->retrieve(m_pixelID, "PixelID"));
148 return StatusCode::SUCCESS;
151template <typename traj_t>
152bool PixelClusterCalibrationToolBase<traj_t>::calibrateAfterMeasurementSelection() const
153{ return m_postCalibration.value(); }
155} // namespace ActsTrk