ATLAS Offline Software
Loading...
Searching...
No Matches
MuonClusterOnTrackCreator.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6// AlgTool used for MuonClusterOnTrack object production
8
10
11#include <cmath>
12#include <sstream>
13
23#include "TrkSurfaces/Surface.h"
24#include "GaudiKernel/PhysicalConstants.h"
25
26namespace {
27 constexpr double SIG_VEL = 4.80000; // ns/m
28 constexpr double C_VEL = 1./ Gaudi::Units::c_light; // ns/m
29}
30namespace Muon {
31 //================================================================================
33 ATH_CHECK(m_idHelperSvc.retrieve());
34
35 ATH_CHECK(m_clusterBuilderToolMM.retrieve(DisableTool{m_calibToolNSW.empty()}));
36 ATH_CHECK(m_calibToolNSW.retrieve(DisableTool{m_calibToolNSW.empty()}));
37 return StatusCode::SUCCESS;
38 }
39
40 //================================================================================
42 const Amg::Vector3D& GP) const {
43 MuonClusterOnTrack* MClT = nullptr;
44
45 // check whether PrepRawData has detector element, if not there print warning
47
48 ATH_MSG_VERBOSE("Create ROT from "<<m_idHelperSvc->toString(RIO.identify())<<".");
49
50 // in RIO_OnTrack the local param and cov should have the same dimension
52
53 if (RIO.localCovariance().cols() > 1 || (m_idHelperSvc->isTgc(RIO.identify()) && m_idHelperSvc->measuresPhi(RIO.identify()))) {
54 ATH_MSG_VERBOSE("Making 2-dim local parameters: " << m_idHelperSvc->toString(RIO.identify()));
55 } else {
56 Trk::DefinedParameter radiusPar(RIO.localPosition().x(), Trk::locX);
57 locpar = Trk::LocalParameters(radiusPar);
58 ATH_MSG_VERBOSE("Making 1-dim local parameters: " << m_idHelperSvc->toString(RIO.identify()));
59 }
60
61 Amg::Vector2D lp{Amg::Vector2D::Zero()};
62 double positionAlongStrip{0};
63 double positionAlongZ{0};
64
65 const Trk::Surface& rio_surface = EL->surface(RIO.identify());
66 if (!rio_surface.globalToLocal(GP, GP, lp)) {
67 Amg::Vector3D lpos = rio_surface.transform().inverse() * GP;
68 //sTGC surfaces end up with a 20um shift in z when converted from ACTS track parameters, so optionally don't warn for such cases
69 if(!m_restrictWarnings ||
70 std::abs(std::abs(lpos.z())-0.02)>1e-6) {
71 ATH_MSG_WARNING("Extrapolated GlobalPosition not on detector surface! Distance " << lpos.z());
72 }
73 lp = lpos.block<2,1>(0,0);
74 positionAlongZ = lpos.z();
75 }
76
77 positionAlongStrip = lp[Trk::locY];
78
79 Amg::MatrixX loce = RIO.localCovariance();
80 ATH_MSG_DEBUG("All: new err matrix is " << loce);
81 switch (m_idHelperSvc->technologyIndex(RIO.identify())) {
83 case RPC: {
84 //***************************
85 // RPC: cast to RpcPrepData
86 //***************************
87 const RpcPrepData* MClus = static_cast<const RpcPrepData*>(&RIO);
88 const bool measphi = m_idHelperSvc->measuresPhi(RIO.identify());
89 if (MClus->localCovariance().cols() == 2) {
90 loce = MClus->localCovariance();
91 } else if ((m_doFixedErrorRpcEta && !measphi) ||
92 (m_doFixedErrorRpcPhi && measphi)) {
93 const double fixedError = measphi ? m_fixedErrorRpcPhi
95 Amg::MatrixX mat(1, 1);
96 mat(0, 0) = fixedError * fixedError;
97 loce = mat;
98 }
99
101 const Amg::Vector3D& clusPos = MClus->globalPosition();
102
103 // let's correct rpc time subtracting delay due to the induced electric signal propagation along strip
104 double timeAlongStrip = 0;
105 if (!measphi) {
106 timeAlongStrip = re->distanceToEtaReadout(GP) / 1000. * SIG_VEL;
107 } else {
108 timeAlongStrip = re->distanceToPhiReadout(GP) / 1000. * SIG_VEL;
109 }
110 if (positionAlongZ) {
111 timeAlongStrip = 0; // no correction if extrapolated GlobalPosition not on detector surface!
112 }
113 // let's evaluate the average delay due to the induced electric signal propagation along strip
114 double assignedTimFromPrd = 0;
115 if (!measphi) {
116 assignedTimFromPrd = re->distanceToEtaReadout(clusPos) / 1000. * SIG_VEL;
117 } else {
118 assignedTimFromPrd = re->distanceToPhiReadout(clusPos) / 1000. * SIG_VEL;
119 }
120
121 // let's evaluate [real TOF - nominal TOF]
122 double real_TOF_onRPCgap = GP.mag() / 1000. * C_VEL;
123 double nominal_TOF_onRPCgap = clusPos.mag() / 1000. * C_VEL;
124
125 // let's evaluate the total time correction
126 double correct_time_tot = real_TOF_onRPCgap
127 - nominal_TOF_onRPCgap
128 + timeAlongStrip
129 - assignedTimFromPrd;
130
131 MClT = new RpcClusterOnTrack(MClus, std::move(locpar), std::move(loce),
132 positionAlongStrip, MClus->time() - correct_time_tot);
133
134 ATH_MSG_DEBUG(" correct_time_along_strip " << timeAlongStrip << " assignedTimFromPrd "
135 << assignedTimFromPrd << " real_TOF_onRPCgap " << real_TOF_onRPCgap
136 << " nominal_TOF_onRPCgap " << nominal_TOF_onRPCgap << " MClus->time() "
137 << MClus->time() << " correct_time_tot " << correct_time_tot);
138 break;
139
140 } case TGC: {
141
142 //***************************
143 // TGC: cast to TgcPrepData
144 //***************************
145
146 const TgcPrepData* MClus = static_cast<const TgcPrepData*>(&RIO);
147 const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
148
149 // calculation of 2D error matrix for TGC phi strips
150 if (idHelper.measuresPhi(RIO.identify())) {
151 const int stripNo = idHelper.channel(RIO.identify());
152 const int gasGap = idHelper.gasGap(RIO.identify());
153
154 const MuonGM::TgcReadoutElement* ele = MClus->detectorElement();
155
156 double stripLength = ele->stripLength();
157 double stripWidth = std::abs(ele->stripPitch(gasGap, stripNo, lp[Trk::locZ]));
158 const Amg::Vector3D lStripDir = ele->transform(RIO.identify()).inverse().linear()*
159 ele->stripDir(RIO.identify());
160
161 Amg::MatrixX mat(2, 2);
162
163 double phistereo = lStripDir.phi() - 90.*Gaudi::Units::deg;
164 double Sn = std::sin(phistereo);
165 double Sn2 = Sn * Sn;
166 double Cs2 = 1. - Sn2;
167
168 double V0 = stripWidth * stripWidth / 12;
170 double V1 = stripLength * stripLength / 12;
171 mat(0, 0) = (Cs2 * V0 + Sn2 * V1);
172 mat.fillSymmetric(1, 0, (Sn * std::sqrt(Cs2) * (V0 - V1)));
173 mat(1, 1) = (Sn2 * V0 + Cs2 * V1);
174 loce = mat;
175 } else {
177 Amg::MatrixX mat(1, 1);
179 loce = mat;
180 }
181 }
182
183 MClT = new TgcClusterOnTrack(MClus, std::move(locpar), std::move(loce),
184 positionAlongStrip);
185 break;
186
187 } case STGC: {
188
189 //***************************
190 // sTGC: cast to sTgcPrepData
191 //***************************
192
193 const sTgcPrepData* MClus = static_cast<const sTgcPrepData*>(&RIO);
194 Amg::Vector2D localPos(lp[Trk::locX], lp[Trk::locY]);
195
196 // Dont make RIO On tracks for sTGC wires in inner Q1
197 if (m_idHelperSvc->stgcIdHelper().channelType(MClus->identify()) == sTgcIdHelper::Wire &&
198 MClus->detectorElement()->isEtaZero(MClus->identify(), lp)) {
199 ATH_MSG_DEBUG("sTgcReadoutElement with isEtaZero() ?! "
200 <<m_idHelperSvc->toString(MClus->identify()));
201 return nullptr;
202 }
203 // Wires are already considered in the above check. Dont remove them here
204 if (!rio_surface.insideBounds(localPos) &&
205 m_idHelperSvc->stgcIdHelper().channelType(MClus->identify()) != sTgcIdHelper::Wire) {
206 ATH_MSG_DEBUG("sTgc measurement "<<m_idHelperSvc->toString(MClus->identify())
207 <<" out of bounds. "<<Amg::toString(localPos));
208 return nullptr;
209 }
210 MClT = new sTgcClusterOnTrack(MClus, std::move(locpar),
211 std::move(loce), positionAlongStrip);
212 break;
213
214 } case MM:{
215 //***************************
216 // MM: cast to MMPrepData
217 //***************************
218 const MMPrepData* mmPRD = static_cast<const MMPrepData*>(&RIO);
219 MClT = new MMClusterOnTrack(mmPRD, std::move(locpar), std::move(loce),
220 positionAlongStrip, {}, {});
221 break;
222 } default:
223 ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<<" Measurement not supported:"
224 <<m_idHelperSvc->toString(RIO.identify()));
225 }
226
227 return MClT;
228 }
229
230
231 //================================================================================
235
236 //================================================================================
237 MuonClusterOnTrack* MuonClusterOnTrackCreator::correct(const Trk::PrepRawData& RIO, const Trk::TrackParameters& TP, const EventContext& /*ctx*/ ) const {
238 return correct(RIO, TP.position(), TP.momentum().unit());
239 }
240
241 //================================================================================
243 ATH_MSG_VERBOSE("Apply calibration correction to "<<RIO);
244
245 switch (m_idHelperSvc->technologyIndex(RIO.identify())) {
247 case MM:
248 return calibratedClusterMMG(RIO, GP, GD);
249 case STGC: {
250 if (!m_idHelperSvc->measuresPhi(RIO.identify())){
251 return calibratedClusterSTG(RIO, GP, GD);
252 }
253 return createRIO_OnTrack(RIO, GP);
254 } default:
255 return createRIO_OnTrack(RIO, GP);
256 }
257 }
258
259
260 //================================================================================
262 const EventContext& ctx{Gaudi::Hive::currentContext()};
263 // Make sure RIO has a detector element
264 const MuonGM::MMReadoutElement* mmEL = static_cast<const MuonGM::MMReadoutElement*>(RIO.detectorElement());
265 if (!mmEL) {
266 ATH_MSG_WARNING("RIO does not have associated detectorElement! Skipping cluster calibration");
267 return nullptr;
268 }
269
270 Amg::MatrixX loce = RIO.localCovariance();
272
273 // * Local cluster coordinates to feed to the calibration tools
274 Amg::Vector2D lp{Amg::Vector2D::Zero()};
275
276 // get localY from the seeded position
277 const Trk::PlaneSurface& rio_surface = mmEL->surface(RIO.identify());
278 if (!rio_surface.globalToLocal(GP, GP, lp)) {
279 Amg::Vector3D lpos = rio_surface.transform().inverse() * GP;
280 ATH_MSG_WARNING("Extrapolated GlobalPosition not on detector surface! Distance " << lpos.z());
281 lp[Trk::locX] = lpos.x();
282 lp[Trk::locY] = lpos.y();
283 }
284 // set localX from the cluster parameters
285 lp[Trk::locX] = locpar[Trk::locX];
286
287 // * B-Field correction
288 // calibrate the input strips
289 const MMPrepData* mmPRD = static_cast<const MMPrepData*>(&RIO);
290
291 std::vector<NSWCalib::CalibratedStrip> calibratedStrips;
292 StatusCode sc = m_calibToolNSW->calibrateClus(ctx, mmPRD, GP, calibratedStrips);
293 if (sc != StatusCode::SUCCESS) {
294 ATH_MSG_WARNING("Could not calibrate the MM Cluster in the RIO on track creator");
295 return nullptr;
296 }
297
298 // calibrate the cluster position along the precision coordinate (updates lp.x())
299 IMMClusterBuilderTool::RIO_Author rotAuthor = m_clusterBuilderToolMM->getCalibratedClusterPosition(ctx,
300 calibratedStrips,
301 NswClustering::toLocal(*mmPRD, GD),
302 lp, loce);
303
304 if (rotAuthor == IMMClusterBuilderTool::RIO_Author::unKnownAuthor) {
305 ATH_MSG_WARNING("Could not calibrate the MM Cluster in the RIO on track creator");
306 return nullptr;
307 }
308
309 // * Correct the local cluster coordinates for as-built conditions and B-lines (returns a new 3D vector)
310 Amg::Vector3D localposition3D{Amg::Vector3D::Zero()};
311 if (!mmEL->spacePointPosition(RIO.identify(), lp, localposition3D)){
312 ATH_MSG_WARNING("Application of final as-built parameters failed for channel "<<m_idHelperSvc->toString(RIO.identify())<<" local pos = ("<<lp.x()<<"/"<<lp.y()<<").");
313 }
314
315 // Get the direction of the track in the local coordinate system and use it to project
316 // the actual hit position onto the nominal surface (locZ = 0), where the intersection
317 // of the track is considered. This "effective" position provides a more accurate residual.
319 rio_surface.globalToLocalDirection(GD, ld);
320 double a_impact = ld.angleXZ() < 0 ? -M_PI_2 - ld.angleXZ() : M_PI_2 - ld.angleXZ();
321 double x_projected = localposition3D.x() - std::tan(a_impact) * localposition3D.z();
322
323 // * Set the value of the local parameter (locX) after applying conditions
324 // The position along strip will be set from the seed (there is no better
325 // estimate than that; not used in the track fits anyway)
326 locpar[Trk::locX] = x_projected;
327
328 ATH_MSG_VERBOSE("generating MMClusterOnTrack in MMClusterBuilder");
329 MMClusterOnTrack* cluster = new MMClusterOnTrack(mmPRD, std::move(locpar), std::move(loce), lp[Trk::locY], {}, {});
330 cluster->setAuthor(rotAuthor);
331
332 return cluster;
333 }
334
335
336 //================================================================================
338
339 // Make sure RIO has a detector element
340 const MuonGM::sTgcReadoutElement* stgEL = static_cast<const MuonGM::sTgcReadoutElement*>(RIO.detectorElement());
341 if (!stgEL) {
342 ATH_MSG_WARNING("RIO does not have associated detectorElement! Skipping cluster calibration");
343 return nullptr;
344 }
345
346 Amg::MatrixX loce = RIO.localCovariance();
347 // > 1 in case we want to keep pads in the future ?
349
350
351 // * Local cluster coordinates to feed to the calibration tools
352 Amg::Vector2D lp{ Amg::Vector2D::Zero() };
353
354 // get local y from the seeded position
355 const Trk::PlaneSurface& rio_surface = stgEL->surface(RIO.identify());
356 if (!rio_surface.globalToLocal(GP, GP, lp)) {
357 Amg::Vector3D lpos = rio_surface.transform().inverse() * GP;
358 ATH_MSG_WARNING("Extrapolated GlobalPosition not on detector surface! Distance " << lpos.z());
359 lp[Trk::locX] = lpos.x();
360 lp[Trk::locY] = lpos.y();
361 }
362 // set local x from the cluster parameters
363 lp[Trk::locX] = locpar[Trk::locX];
364
365 // * Correct the local coordinates for as-built conditions and b-lines
366 Amg::Vector3D localposition3D { Amg::Vector3D::Zero() };
367 stgEL->spacePointPosition(RIO.identify(), lp[Trk::locX], lp[Trk::locY], localposition3D);
368
369 // Get the direction of the track in the local coordinate system and use it to project
370 // the actual hit position onto the nominal surface (locZ = 0), where the intersection
371 // of the track is considered. This "effective" position provides a more accurate residual.
373 rio_surface.globalToLocalDirection(GD, ld);
374 double a_impact = ld.angleXZ() < 0 ? -M_PI_2 - ld.angleXZ() : M_PI_2 - ld.angleXZ();
375 double x_projected = localposition3D.x() - std::tan(a_impact) * localposition3D.z();
376
377 // * Set the value of the local parameter (locX) after applying conditions
378 // The position along strip will be set from the seed (there is no better
379 // estimate than that; not used in the track fits anyway)
380 locpar[Trk::locX] = x_projected;
381
382 const sTgcPrepData* stgPRD = static_cast<const sTgcPrepData*>(&RIO);
383 ATH_MSG_VERBOSE("generating sTgcClusterOnTrack in MuonClusterBuilder");
384 MuonClusterOnTrack* cluster = new sTgcClusterOnTrack(stgPRD, std::move(locpar), std::move(loce), lp[Trk::locY]);
385
386 return cluster;
387 }
388} // namespace Muon
const boost::regex re(r_e)
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
static Double_t sc
@ STGC
Definition RegSelEnums.h:39
@ MM
Definition RegSelEnums.h:38
@ RPC
Definition RegSelEnums.h:32
An MMReadoutElement corresponds to a single STGC module; therefore typicaly a barrel muon station con...
virtual bool spacePointPosition(const Identifier &phiId, const Identifier &etaId, Amg::Vector2D &pos) const override final
space point position for a given pair of phi and eta identifiers The LocalPosition is expressed in th...
virtual const Trk::PlaneSurface & surface() const override
access to chamber surface (phi orientation), uses the first gas gap
virtual const Amg::Transform3D & transform() const override
Return local to global transform.
An RpcReadoutElement corresponds to a single RPC module; therefore typicaly a barrel muon station con...
A TgcReadoutElement corresponds to a single TGC chamber; therefore typically a TGC station contains s...
Amg::Vector3D stripDir(int gasGap, int strip) const
Returns the direction of a strip.
double stripLength() const
Returns the length of each strip which is equal to the height of the chamber.
double stripPitch(int gasGap, int strip) const
Returns the pitch of the given strip in gasGap i.
An sTgcReadoutElement corresponds to a single STGC module; therefore typicaly a barrel muon station c...
virtual bool spacePointPosition(const Identifier &phiId, const Identifier &etaId, Amg::Vector2D &pos) const override final
space point position for a given pair of phi and eta identifiers The LocalPosition is expressed in th...
bool isEtaZero(const Identifier &id, const Amg::Vector2D &localPosition) const
is eta=0 of QL1 or QS1?
MMClusterOnTrack::Author RIO_Author
Refinement of the cluster position after the cluster calibration loop is ran with a complete external...
Class to represent calibrated clusters formed from TGC strips.
Class to represent MM measurements.
Definition MMPrepData.h:22
virtual StatusCode initialize() override
Gaudi::Property< double > m_fixedErrorTgcEta
MuonClusterOnTrack * calibratedClusterMMG(const Trk::PrepRawData &RIO, const Amg::Vector3D &GP, const Amg::Vector3D &GD) const
virtual MuonClusterOnTrack * createRIO_OnTrack(const Trk::PrepRawData &RIO, const Amg::Vector3D &GP) const override
Create new Muon::MuonClusterOnTrack from a Trk::PrepRawData and a predicted Trk::TrackParameter.
virtual MuonClusterOnTrack * correct(const Trk::PrepRawData &RIO, const Trk::TrackParameters &TP, const EventContext &) const override
Create new Muon::MuonClusterOnTrack from a Trk::PrepRawData and the predicted Trk::TrackParameter at ...
Gaudi::Property< double > m_fixedErrorRpcEta
Gaudi::Property< double > m_fixedErrorRpcPhi
ToolHandle< Muon::INSWCalibTool > m_calibToolNSW
MuonClusterOnTrack * calibratedClusterSTG(const Trk::PrepRawData &RIO, const Amg::Vector3D &GP, const Amg::Vector3D &GD) const
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
ToolHandle< Muon::IMMClusterBuilderTool > m_clusterBuilderToolMM
Gaudi::Property< double > m_fixedErrorTgcPhi
Base class for Muon cluster RIO_OnTracks.
Class to represent calibrated clusters formed from RPC strips.
Class to represent RPC measurements.
Definition RpcPrepData.h:35
virtual const MuonGM::RpcReadoutElement * detectorElement() const override final
Returns the detector element corresponding to this PRD.
virtual const Amg::Vector3D & globalPosition() const override
Returns the global position.
float time() const
Returns the time.
Class to represent calibrated clusters formed from TGC strips.
Class to represent TGC measurements.
Definition TgcPrepData.h:32
virtual const MuonGM::TgcReadoutElement * detectorElement() const override final
Returns the detector element corresponding to this PRD The pointer will be zero if the det el is not ...
Class to represent calibrated clusters formed from TGC strips.
Class to represent sTgc measurements.
virtual const MuonGM::sTgcReadoutElement * detectorElement() const override final
Returns the detector element corresponding to this PRD.
int channel(const Identifier &id) const override
int gasGap(const Identifier &id) const override
get the hashes
bool measuresPhi(const Identifier &id) const override
represents the three-dimensional global direction with respect to a planar surface frame.
const Amg::Vector3D & momentum() const
Access method for the momentum.
const Amg::Vector3D & position() const
Access method for the position.
Class for a planaer rectangular or trapezoidal surface in the ATLAS detector.
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const override final
Specified for PlaneSurface: GlobalToLocal method without dynamic memory allocation - boolean checks i...
void globalToLocalDirection(const Amg::Vector3D &glodir, Trk::LocalDirection &locdir) const
This method transforms the global direction to a local direction wrt the plane.
virtual const TrkDetElementBase * detectorElement() const =0
return the detector element corresponding to this PRD The pointer will be zero if the det el is not d...
const Amg::Vector2D & localPosition() const
return the local position reference
Identifier identify() const
return the identifier
const Amg::MatrixX & localCovariance() const
return const ref to the error matrix
Abstract Base Class for tracking surfaces.
Definition Surface.h:79
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const =0
Specified by each surface type: GlobalToLocal method without dynamic memory allocation - boolean chec...
virtual bool insideBounds(const Amg::Vector2D &locpos, double tol1=0., double tol2=0.) const =0
virtual methods to be overwritten by the inherited surfaces
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
This is the base class for all tracking detector elements with read-out relevant information.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
This module defines the arguments passed from the BATCH driver to the BATCH worker.
TechnologyIndex
enum to classify the different layers in the muon spectrometer
Amg::Vector3D toLocal(const Amg::Transform3D &toLocalTrans, const Amg::Vector3D &dir)
Rotates a direction vector into a local frame: x-axis : Parallell to the radial direction of the dete...
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
Definition TgcBase.h:6
@ locY
local cartesian
Definition ParamDefs.h:38
@ locX
Definition ParamDefs.h:37
@ locZ
local cylindrical
Definition ParamDefs.h:42
std::pair< double, ParamDefs > DefinedParameter
Typedef to of a std::pair<double, ParamDefs> to identify a passed-through double as a specific type o...
ParametersBase< TrackParametersDim, Charged > TrackParameters