ATLAS Offline Software
Loading...
Searching...
No Matches
MuonClusterOnTrackCreator.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 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 || fabs(fabs(lpos.z())-0.02)>1e-6){
70 ATH_MSG_WARNING("Extrapolated GlobalPosition not on detector surface! Distance " << lpos.z());
71 }
72 lp[Trk::locX] = lpos.x();
73 lp[Trk::locY] = lpos.y();
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
90 if ((m_doFixedErrorRpcEta && !measphi) ||
91 (m_doFixedErrorRpcPhi && measphi) ) {
92 const double fixedError = measphi ? m_fixedErrorRpcPhi
94 Amg::MatrixX mat(1, 1);
95 mat(0, 0) = fixedError * fixedError;
96 loce = mat;
97 }
98
100 Amg::Vector3D clusPos = re->stripPos(RIO.identify());
101
102 // let's correct rpc time subtracting delay due to the induced electric signal propagation along strip
103 double timeAlongStrip = 0;
104 if (!measphi) {
105 timeAlongStrip = re->distanceToEtaReadout(GP) / 1000. * SIG_VEL;
106 } else {
107 timeAlongStrip = re->distanceToPhiReadout(GP) / 1000. * SIG_VEL;
108 }
109 if (positionAlongZ) timeAlongStrip = 0; // no correction if extrapolated GlobalPosition not on detector surface!
110
111 // let's evaluate the average delay due to the induced electric signal propagation along strip
112 double assignedTimFromPrd = 0;
113 if (!measphi) {
114 assignedTimFromPrd = re->distanceToEtaReadout(clusPos) / 1000. * SIG_VEL;
115 } else {
116 assignedTimFromPrd = re->distanceToPhiReadout(clusPos) / 1000. * SIG_VEL;
117 }
118
119 // let's evaluate [real TOF - nominal TOF]
120 double real_TOF_onRPCgap = GP.mag() / 1000. * C_VEL;
121 double nominal_TOF_onRPCgap = clusPos.mag() / 1000. * C_VEL;
122
123 // let's evaluate the total time correction
124 double correct_time_tot = real_TOF_onRPCgap
125 - nominal_TOF_onRPCgap
126 + timeAlongStrip
127 - assignedTimFromPrd;
128
129 MClT = new RpcClusterOnTrack(MClus, std::move(locpar), std::move(loce),
130 positionAlongStrip, MClus->time() - correct_time_tot);
131
132 ATH_MSG_DEBUG(" correct_time_along_strip " << timeAlongStrip << " assignedTimFromPrd "
133 << assignedTimFromPrd << " real_TOF_onRPCgap " << real_TOF_onRPCgap
134 << " nominal_TOF_onRPCgap " << nominal_TOF_onRPCgap << " MClus->time() "
135 << MClus->time() << " correct_time_tot " << correct_time_tot);
136 break;
137
138 } case TGC: {
139
140 //***************************
141 // TGC: cast to TgcPrepData
142 //***************************
143
144 const TgcPrepData* MClus = static_cast<const TgcPrepData*>(&RIO);
145 const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
146
147 // calculation of 2D error matrix for TGC phi strips
148 if (idHelper.measuresPhi(RIO.identify())) {
149 const int stripNo = idHelper.channel(RIO.identify());
150 const int gasGap = idHelper.gasGap(RIO.identify());
151
152 const MuonGM::TgcReadoutElement* ele = MClus->detectorElement();
153
154 double stripLength = ele->stripLength();
155 double stripWidth = std::abs(ele->stripPitch(gasGap, stripNo, lp[Trk::locZ]));
156 const Amg::Vector3D lStripDir = ele->transform(RIO.identify()).inverse().linear()*
157 ele->stripDir(RIO.identify());
158
159 Amg::MatrixX mat(2, 2);
160
161 double phistereo = lStripDir.phi() - 90.*Gaudi::Units::deg;
162 double Sn = std::sin(phistereo);
163 double Sn2 = Sn * Sn;
164 double Cs2 = 1. - Sn2;
165
166 double V0 = stripWidth * stripWidth / 12;
168 double V1 = stripLength * stripLength / 12;
169 mat(0, 0) = (Cs2 * V0 + Sn2 * V1);
170 mat.fillSymmetric(1, 0, (Sn * std::sqrt(Cs2) * (V0 - V1)));
171 mat(1, 1) = (Sn2 * V0 + Cs2 * V1);
172 loce = mat;
173 } else {
175 Amg::MatrixX mat(1, 1);
177 loce = mat;
178 }
179 }
180
181 MClT = new TgcClusterOnTrack(MClus, std::move(locpar), std::move(loce),
182 positionAlongStrip);
183 break;
184
185 } case STGC: {
186
187 //***************************
188 // sTGC: cast to sTgcPrepData
189 //***************************
190
191 const sTgcPrepData* MClus = static_cast<const sTgcPrepData*>(&RIO);
192 Amg::Vector2D localPos(lp[Trk::locX], lp[Trk::locY]);
193
194 // Dont make RIO On tracks for sTGC wires in inner Q1
195 if (m_idHelperSvc->stgcIdHelper().channelType(MClus->identify()) == sTgcIdHelper::Wire &&
196 MClus->detectorElement()->isEtaZero(MClus->identify(), lp)) {
197 ATH_MSG_DEBUG("sTgcReadoutElement with isEtaZero() ?! "
198 <<m_idHelperSvc->toString(MClus->identify()));
199 return nullptr;
200 }
201 // Wires are already considered in the above check. Dont remove them here
202 if (!rio_surface.insideBounds(localPos) &&
203 m_idHelperSvc->stgcIdHelper().channelType(MClus->identify()) != sTgcIdHelper::Wire) {
204 ATH_MSG_DEBUG("sTgc measurement "<<m_idHelperSvc->toString(MClus->identify())
205 <<" out of bounds. "<<Amg::toString(localPos));
206 return nullptr;
207 }
208 MClT = new sTgcClusterOnTrack(MClus, std::move(locpar),
209 std::move(loce), positionAlongStrip);
210 break;
211
212 } case MM:{
213 //***************************
214 // MM: cast to MMPrepData
215 //***************************
216 const MMPrepData* mmPRD = static_cast<const MMPrepData*>(&RIO);
217 MClT = new MMClusterOnTrack(mmPRD, std::move(locpar), std::move(loce),
218 positionAlongStrip, {}, {});
219 break;
220 } default:
221 ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<<" Measurement not supported:"
222 <<m_idHelperSvc->toString(RIO.identify()));
223 }
224
225 return MClT;
226 }
227
228
229 //================================================================================
233
234 //================================================================================
235 MuonClusterOnTrack* MuonClusterOnTrackCreator::correct(const Trk::PrepRawData& RIO, const Trk::TrackParameters& TP, const EventContext& /*ctx*/ ) const {
236 return correct(RIO, TP.position(), TP.momentum().unit());
237 }
238
239 //================================================================================
241 ATH_MSG_VERBOSE("Apply calibration correction to "<<RIO);
242
243 switch (m_idHelperSvc->technologyIndex(RIO.identify())) {
245 case MM:
246 return calibratedClusterMMG(RIO, GP, GD);
247 case STGC: {
248 if (!m_idHelperSvc->measuresPhi(RIO.identify())){
249 return calibratedClusterSTG(RIO, GP, GD);
250 }
251 return createRIO_OnTrack(RIO, GP);
252 } default:
253 return createRIO_OnTrack(RIO, GP);
254 }
255 }
256
257
258 //================================================================================
260 const EventContext& ctx{Gaudi::Hive::currentContext()};
261 // Make sure RIO has a detector element
262 const MuonGM::MMReadoutElement* mmEL = static_cast<const MuonGM::MMReadoutElement*>(RIO.detectorElement());
263 if (!mmEL) {
264 ATH_MSG_WARNING("RIO does not have associated detectorElement! Skipping cluster calibration");
265 return nullptr;
266 }
267
268 Amg::MatrixX loce = RIO.localCovariance();
270
271 // * Local cluster coordinates to feed to the calibration tools
272 Amg::Vector2D lp{Amg::Vector2D::Zero()};
273
274 // get localY from the seeded position
275 const Trk::PlaneSurface& rio_surface = mmEL->surface(RIO.identify());
276 if (!rio_surface.globalToLocal(GP, GP, lp)) {
277 Amg::Vector3D lpos = rio_surface.transform().inverse() * GP;
278 ATH_MSG_WARNING("Extrapolated GlobalPosition not on detector surface! Distance " << lpos.z());
279 lp[Trk::locX] = lpos.x();
280 lp[Trk::locY] = lpos.y();
281 }
282 // set localX from the cluster parameters
283 lp[Trk::locX] = locpar[Trk::locX];
284
285 // * B-Field correction
286 // calibrate the input strips
287 const MMPrepData* mmPRD = static_cast<const MMPrepData*>(&RIO);
288
289 std::vector<NSWCalib::CalibratedStrip> calibratedStrips;
290 StatusCode sc = m_calibToolNSW->calibrateClus(ctx, mmPRD, GP, calibratedStrips);
291 if (sc != StatusCode::SUCCESS) {
292 ATH_MSG_WARNING("Could not calibrate the MM Cluster in the RIO on track creator");
293 return nullptr;
294 }
295
296 // calibrate the cluster position along the precision coordinate (updates lp.x())
297 IMMClusterBuilderTool::RIO_Author rotAuthor = m_clusterBuilderToolMM->getCalibratedClusterPosition(ctx,
298 calibratedStrips,
299 NswClustering::toLocal(*mmPRD, GD),
300 lp, loce);
301
302 if (rotAuthor == IMMClusterBuilderTool::RIO_Author::unKnownAuthor) {
303 ATH_MSG_WARNING("Could not calibrate the MM Cluster in the RIO on track creator");
304 return nullptr;
305 }
306
307 // * Correct the local cluster coordinates for as-built conditions and B-lines (returns a new 3D vector)
308 Amg::Vector3D localposition3D{Amg::Vector3D::Zero()};
309 if (!mmEL->spacePointPosition(RIO.identify(), lp, localposition3D)){
310 ATH_MSG_WARNING("Application of final as-built parameters failed for channel "<<m_idHelperSvc->toString(RIO.identify())<<" local pos = ("<<lp.x()<<"/"<<lp.y()<<").");
311 }
312
313 // Get the direction of the track in the local coordinate system and use it to project
314 // the actual hit position onto the nominal surface (locZ = 0), where the intersection
315 // of the track is considered. This "effective" position provides a more accurate residual.
317 rio_surface.globalToLocalDirection(GD, ld);
318 double a_impact = ld.angleXZ() < 0 ? -M_PI_2 - ld.angleXZ() : M_PI_2 - ld.angleXZ();
319 double x_projected = localposition3D.x() - std::tan(a_impact) * localposition3D.z();
320
321 // * Set the value of the local parameter (locX) after applying conditions
322 // The position along strip will be set from the seed (there is no better
323 // estimate than that; not used in the track fits anyway)
324 locpar[Trk::locX] = x_projected;
325
326 ATH_MSG_VERBOSE("generating MMClusterOnTrack in MMClusterBuilder");
327 MMClusterOnTrack* cluster = new MMClusterOnTrack(mmPRD, std::move(locpar), std::move(loce), lp[Trk::locY], {}, {});
328 cluster->setAuthor(rotAuthor);
329
330 return cluster;
331 }
332
333
334 //================================================================================
336
337 // Make sure RIO has a detector element
338 const MuonGM::sTgcReadoutElement* stgEL = static_cast<const MuonGM::sTgcReadoutElement*>(RIO.detectorElement());
339 if (!stgEL) {
340 ATH_MSG_WARNING("RIO does not have associated detectorElement! Skipping cluster calibration");
341 return nullptr;
342 }
343
344 Amg::MatrixX loce = RIO.localCovariance();
345 // > 1 in case we want to keep pads in the future ?
347
348
349 // * Local cluster coordinates to feed to the calibration tools
350 Amg::Vector2D lp{ Amg::Vector2D::Zero() };
351
352 // get local y from the seeded position
353 const Trk::PlaneSurface& rio_surface = stgEL->surface(RIO.identify());
354 if (!rio_surface.globalToLocal(GP, GP, lp)) {
355 Amg::Vector3D lpos = rio_surface.transform().inverse() * GP;
356 ATH_MSG_WARNING("Extrapolated GlobalPosition not on detector surface! Distance " << lpos.z());
357 lp[Trk::locX] = lpos.x();
358 lp[Trk::locY] = lpos.y();
359 }
360 // set local x from the cluster parameters
361 lp[Trk::locX] = locpar[Trk::locX];
362
363 // * Correct the local coordinates for as-built conditions and b-lines
364 Amg::Vector3D localposition3D { Amg::Vector3D::Zero() };
365 stgEL->spacePointPosition(RIO.identify(), lp[Trk::locX], lp[Trk::locY], localposition3D);
366
367 // Get the direction of the track in the local coordinate system and use it to project
368 // the actual hit position onto the nominal surface (locZ = 0), where the intersection
369 // of the track is considered. This "effective" position provides a more accurate residual.
371 rio_surface.globalToLocalDirection(GD, ld);
372 double a_impact = ld.angleXZ() < 0 ? -M_PI_2 - ld.angleXZ() : M_PI_2 - ld.angleXZ();
373 double x_projected = localposition3D.x() - std::tan(a_impact) * localposition3D.z();
374
375 // * Set the value of the local parameter (locX) after applying conditions
376 // The position along strip will be set from the seed (there is no better
377 // estimate than that; not used in the track fits anyway)
378 locpar[Trk::locX] = x_projected;
379
380 const sTgcPrepData* stgPRD = static_cast<const sTgcPrepData*>(&RIO);
381 ATH_MSG_VERBOSE("generating sTgcClusterOnTrack in MuonClusterBuilder");
382 MuonClusterOnTrack* cluster = new sTgcClusterOnTrack(stgPRD, std::move(locpar), std::move(loce), lp[Trk::locY]);
383
384 return cluster;
385 }
386} // 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
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.
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.
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