ATLAS Offline Software
Loading...
Searching...
No Matches
MuonTGMeasurementTool.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
27#include "TrkGeometry/Layer.h"
32
33// Constructor with parameters:
34Muon::MuonTGMeasurementTool::MuonTGMeasurementTool(const std::string& type, const std::string& name, const IInterface* parent) :
35 AthAlgTool(type, name, parent), m_muonDetMgr(nullptr) {
36 declareInterface<Muon::IMuonTGMeasTool>(this);
37}
38
39// Initialize method:
41 // Get the messaging service, print where you are
42 ATH_MSG_INFO("MuonTGMeasurementTool::initialize()");
43
44 ATH_CHECK(m_idHelperSvc.retrieve());
46 if (m_useDSManager) { ATH_CHECK(detStore()->retrieve(m_muonDetMgr)); }
47
48 // define projection matrices
49 m_tgcProjEta = std::make_unique<AmgMatrix(5, 5)>();
50 m_tgcProjEta->setIdentity();
51 (*m_tgcProjEta)(0, 0) = 0.;
52 (*m_tgcProjEta)(1, 1) = 0.;
53 (*m_tgcProjEta)(0, 1) = 1.;
54 (*m_tgcProjEta)(1, 0) = -1.;
55 m_tgcProjPhi = std::make_unique<AmgMatrix(5, 5)>();
56 m_tgcProjPhi->setIdentity();
57
58 m_rpcProjEta = std::make_unique<AmgMatrix(5, 5)>();
59 m_rpcProjEta->setIdentity();
60 (*m_rpcProjEta)(0, 0) = 0.;
61 (*m_rpcProjEta)(1, 1) = 0.;
62 (*m_rpcProjEta)(0, 1) = 1.;
63 (*m_rpcProjEta)(1, 0) = 1.;
64 m_rpcProjPhi = std::make_unique<AmgMatrix(5, 5)>();
65 m_rpcProjPhi->setIdentity();
66
67 if (!m_trackingGeometryReadKey.empty()) {
69 } else {
71 }
72 return StatusCode::SUCCESS;
73}
75 Identifier id) const {
76 const MuonGM::MuonDetectorManager* MuonDetMgr = m_muonDetMgr;
77 if (!m_useDSManager) {
79 MuonDetMgr = DetectorManagerHandle.cptr();
80 if (MuonDetMgr == nullptr) {
81 ATH_MSG_ERROR("Null pointer to the read MuonDetectorManager conditions object");
82 // return StatusCode::FAILURE;
83 }
84 }
85
86 // Get the messaging service, print where you are
87 ATH_MSG_DEBUG("MuonTGMeasurementTool::layerToDetEl");
88 const Trk::TrackParameters* projPar = nullptr;
89 // const Amg::Vector2D* locPos = 0;
90 // check input
91 if (!lay || !parm || !id.get_identifier32().get_compact()) return projPar;
92
93 // get tracking geometry
94
95 // check compatibility of layer info and required id ? this was already done when associating !
96 if (!lay->layerType()) return projPar;
97 Identifier layId(lay->layerType());
98
99 unsigned int hitType = 0;
100 if (m_idHelperSvc->isMdt(id)) hitType = 1;
101 if (m_idHelperSvc->isRpc(id)) hitType = 2;
102 if (m_idHelperSvc->isCsc(id)) hitType = 3;
103 if (m_idHelperSvc->isTgc(id)) hitType = 4;
104
105 unsigned int layType = 0;
106 if (m_idHelperSvc->isMdt(layId)) layType = 1;
107 if (m_idHelperSvc->isRpc(layId)) layType = 2;
108 if (m_idHelperSvc->isCsc(layId)) layType = 3;
109 if (m_idHelperSvc->isTgc(layId)) layType = 4;
110
111 if (layType != hitType) return projPar;
112
113 if (hitType == 0) {
114 ATH_MSG_ERROR("unknown hit technology");
115 return projPar;
116 } else {
117 ATH_MSG_DEBUG("hit technology:" << hitType);
118 }
119
120 ATH_MSG_DEBUG("extrapolated covariance:" << parm->covariance());
121
122 if (hitType == 1) {
123 const MuonGM::MdtReadoutElement* mdtROE = MuonDetMgr->getMdtReadoutElement(id);
124 if (!mdtROE) {
125 ATH_MSG_WARNING(name() << "MDT readout element not found");
126 return projPar;
127 }
128 // local position of tube
129 int tube = m_idHelperSvc->mdtIdHelper().tube(id);
130 Amg::Vector2D locWire(0., lay->getRef() + (tube - 1) * 30.035);
131 if (fabs(lay->getRef()) > 10e6) {
132 double sign = (lay->getRef() > 0) ? 1. : -1.;
133 int dec = int(lay->getRef() / 1.e5);
134 double ref0 = dec / 1.e5;
135 double ref1 = lay->getRef() - dec * 1e5 - 0.5 * (sign + 1) * 1e5;
136 locWire[0] = ref0;
137 locWire[1] = ref1;
138 int tube = m_idHelperSvc->mdtIdHelper().tube(id);
139 int tubeMax = m_idHelperSvc->mdtIdHelper().tubeMax(id);
140 if (tube > 6 && tubeMax - tube > 5) locWire[0] = 0.;
141 }
142 if (sqrt(locWire[0] * locWire[0] + locWire[1] * locWire[1]) > 2000.) {
143 ATH_MSG_WARNING(name() << " wire shift out bounds for MDT tube :" << m_idHelperSvc->mdtIdHelper().stationName(id) << ","
144 << m_idHelperSvc->mdtIdHelper().stationEta(id) << "," << m_idHelperSvc->mdtIdHelper().stationPhi(id)
145 << ": abandon projection");
146 return projPar;
147 }
148 // direction at the layer
149 Amg::Vector3D dir = parm->momentum().unit();
150 Amg::Vector3D locDir = (lay->surfaceRepresentation().transform().inverse()) * dir;
151 Amg::Vector3D wireDir(1., 0., 0.);
152 //
153 double ND = dir.dot(lay->surfaceRepresentation().normal());
154 double DL = locDir.dot(wireDir);
155 double A = sqrt(1. - DL * DL);
156 AmgMatrix(5, 5) mdtProj;
157 mdtProj.setIdentity();
158 //
159 const Trk::StraightLineSurface* tubeSurf = dynamic_cast<const Trk::StraightLineSurface*>(&(mdtROE->surface(id)));
160 double ori = (lay->surfaceRepresentation().transform().inverse() * tubeSurf->transform()).rotation()(1, 1) > 0. ? -1. : 1.;
161 if (A > 10e-6) {
162 mdtProj(0, 1) = ND / A;
163 mdtProj(1, 0) = ori;
164 mdtProj(1, 1) = DL / A * sqrt(A * A - ND * ND) / A;
165 mdtProj(0, 0) = 0.;
166 } else {
167 mdtProj(0, 1) = 1.;
168 mdtProj(1, 0) = ori;
169 mdtProj(1, 1) = 0.;
170 mdtProj(0, 0) = 0.;
171 }
172 //
173 Amg::VectorX locPar = parm->parameters();
174 locPar[0] -= locWire[0];
175 locPar[1] -= locWire[1];
176 Amg::VectorX pPar = mdtProj * locPar;
177 ATH_MSG_DEBUG("projected parameters(layer->MDT):" << pPar);
178
179 if (parm->covariance()) {
180 std::optional<AmgMatrix(5, 5)> projEM = parm->covariance()->similarity(mdtProj);
181 ATH_MSG_DEBUG("projected covariance(layer->MDT):" << (*projEM));
182 projPar = new Trk::AtaStraightLine(pPar[0], pPar[1], pPar[2], pPar[3], pPar[4], *tubeSurf, projEM);
183
184 } else {
185 projPar = new Trk::AtaStraightLine(pPar[0], pPar[1], pPar[2], pPar[3], pPar[4], *tubeSurf);
186 }
187 }
188
189 if (hitType == 2) {
190 //
191 const MuonGM::RpcReadoutElement* rpcROE = MuonDetMgr->getRpcReadoutElement(id);
192 if (!rpcROE) return projPar;
193 const Trk::PlaneSurface* stripSurf = dynamic_cast<const Trk::PlaneSurface*>(&(rpcROE->surface(id)));
194 if (!stripSurf) return projPar;
195 // decode ref position
196 Amg::VectorX locPar = parm->parameters();
197 // projection matrix
198 AmgMatrix(5, 5)* pMx = nullptr;
199 if (m_idHelperSvc->rpcIdHelper().measuresPhi(id))
200 pMx = m_rpcProjPhi.get();
201 else
202 pMx = m_rpcProjEta.get();
203 // projected parameters
204 double eta = 1.;
205 double sign = (m_idHelperSvc->rpcIdHelper().measuresPhi(id) && m_idHelperSvc->rpcIdHelper().doubletPhi(id) == 2) ? -1. : 1.;
206 double zswap = (lay->getRef() > 10000.) ? -1. : 1.;
207 double ref = (zswap < 0.) ? lay->getRef() - 20000. : lay->getRef();
208 locPar[0] -= sign * ref;
209 Amg::VectorX pPar = (*pMx) * locPar;
210 if (m_idHelperSvc->rpcIdHelper().measuresPhi(id))
211 pPar[0] *= eta;
212 else
213 pPar[1] *= -eta;
214 if (m_idHelperSvc->rpcIdHelper().measuresPhi(id))
215 pPar[1] *= zswap;
216 else
217 pPar[0] *= zswap;
218
219 std::optional<AmgMatrix(5, 5)> projEM;
220 projEM.emplace();
221 if (parm->covariance()) {
222 projEM = parm->covariance()->similarity(*pMx);
223 projPar = new Trk::AtaPlane(pPar[0], pPar[1], pPar[2], pPar[3], pPar[4], *stripSurf, projEM);
224
225 } else {
226 projPar = new Trk::AtaPlane(pPar[0], pPar[1], pPar[2], pPar[3], pPar[4], *stripSurf);
227 projEM = std::nullopt;
228 }
229
230 if (m_alignedMode && (parm->position() - projPar->position()).mag() > 0.001) {
231 ATH_MSG_DEBUG("geometrical RPC projection (layerToDetEl) for hit : "
232 << m_idHelperSvc->rpcIdHelper().measuresPhi(id) << "," << m_idHelperSvc->rpcIdHelper().stationName(id) << ","
233 << m_idHelperSvc->rpcIdHelper().stationEta(id) << "," << m_idHelperSvc->rpcIdHelper().stationPhi(id) << ","
234 << m_idHelperSvc->rpcIdHelper().doubletPhi(id) << "," << m_idHelperSvc->rpcIdHelper().doubletR(id) << ","
235 << m_idHelperSvc->rpcIdHelper().doubletZ(id));
236 Amg::Vector2D locPos;
237 const Amg::Vector3D& globPos = parm->position();
238 bool onSurface = stripSurf->globalToLocal(globPos, globPos, locPos);
239 if (onSurface) {
240 pPar[0] = locPos[0];
241 pPar[1] = locPos[1];
242 delete projPar;
243 projPar = nullptr;
244 projPar = projEM ? new Trk::AtaPlane(pPar[0], pPar[1], pPar[2], pPar[3], pPar[4], *stripSurf, projEM)
245 : new Trk::AtaPlane(pPar[0], pPar[1], pPar[2], pPar[3], pPar[4], *stripSurf);
246 } else {
247 delete projPar;
248 return nullptr;
249 }
250 }
251 }
252
253 if (hitType == 3) {
254 // local position of detEl
255 const MuonGM::CscReadoutElement* cscROE = MuonDetMgr->getCscReadoutElement(id);
256 if (!cscROE) {
257 ATH_MSG_WARNING(name() << "CSC readout element not found");
258 return projPar;
259 }
260
261 const Trk::PlaneSurface* stripSurf = dynamic_cast<const Trk::PlaneSurface*>(&(cscROE->surface(id)));
262 if (!stripSurf) return projPar;
263 // dealing with displaced planes, possibly sligthly displaced
264 double diff = m_idHelperSvc->cscIdHelper().measuresPhi(id) ? 1.55 : -1.55;
265 // distance between planes (assuming parallel planes)
266 Amg::Vector3D layNormal = lay->surfaceRepresentation().normal();
267 double DN = parm->momentum().dot(layNormal);
268 double t = diff / DN;
269 // displacement ( as projection of strip surface center on the layer )
270 const Amg::Vector2D csc_shift(0., lay->getRef());
271 // correct local position due to plane distance : use method independent on misalignment
272 Amg::Vector3D corrLocPos = parm->position() - t * parm->momentum() + t * DN * layNormal;
273 Amg::Vector2D locCorrLay;
274 bool onSurface = lay->surfaceRepresentation().globalToLocal(corrLocPos, corrLocPos, locCorrLay);
275
276 if (!onSurface) {
277 ATH_MSG_WARNING(name() << ": misplaced CSC " << id);
278 return projPar;
279 }
280
281 Amg::VectorX parProj(5);
282 parProj[0] = locCorrLay[Trk::locX] - csc_shift[Trk::locX];
283 parProj[1] = locCorrLay[Trk::locY] - csc_shift[Trk::locY];
284 parProj[2] = parm->parameters()[Trk::phi];
285 parProj[3] = parm->parameters()[Trk::theta];
286 parProj[4] = parm->parameters()[Trk::qOverP];
287 //
288 AmgMatrix(5, 5)* pMx = nullptr;
289 if (m_idHelperSvc->cscIdHelper().measuresPhi(id))
290 pMx = m_tgcProjPhi.get();
291 else
292 pMx = m_tgcProjEta.get();
293 Amg::VectorX locPar = (*pMx) * parProj;
294 ATH_MSG_DEBUG("projected parameters (layer->CSC):" << m_idHelperSvc->cscIdHelper().measuresPhi(id) << "," << locPar);
295
296 if (parm->covariance()) {
297 std::optional<AmgMatrix(5, 5)> projEM = parm->covariance()->similarity(*pMx);
298
299 ATH_MSG_DEBUG("projected covariance (layer->CSC):" << *projEM);
300
301 projPar = new Trk::AtaPlane(locPar[0], locPar[1], locPar[2], locPar[3], locPar[4], *stripSurf, projEM);
302
303 } else
304 projPar = new Trk::AtaPlane(locPar[0], locPar[1], locPar[2], locPar[3], locPar[4], *stripSurf);
305
306 ATH_MSG_DEBUG("test CSC projection:layerToDetEl:" << parm->position() << "," << projPar->position());
307 }
308
309 if (hitType == 4) {
310 // local position at layer
311 const MuonGM::TgcReadoutElement* tgcROE = MuonDetMgr->getTgcReadoutElement(id);
312 if (!tgcROE) {
313 ATH_MSG_WARNING(name() << "TGC readout element not found");
314 return projPar;
315 }
316 const Trk::PlaneSurface* stripSurf = dynamic_cast<const Trk::PlaneSurface*>(&(tgcROE->surface(id)));
317 if (!stripSurf) return projPar;
318 //
319 AmgMatrix(5, 5)* pMx = nullptr;
320 if (m_idHelperSvc->tgcIdHelper().isStrip(id))
321 pMx = m_tgcProjPhi.get();
322 else
323 pMx = m_tgcProjEta.get();
324 Amg::VectorX locPar = (*pMx) * parm->parameters();
325 ATH_MSG_DEBUG("projected parameters (layer->TGC):" << m_idHelperSvc->tgcIdHelper().isStrip(id) << "," << locPar << ","
326 << stripSurf);
327
328 std::optional<AmgMatrix(5, 5)> projEM = std::nullopt;
329 bool bcov = false;
330
331 if (parm->covariance()) {
332 projEM = parm->covariance()->similarity(*pMx);
333 bcov = true;
334 ATH_MSG_DEBUG("projected covariance (layer->TGC):" << (*projEM));
335 projPar = new Trk::AtaPlane(locPar[0], locPar[1], locPar[2], locPar[3], locPar[4], *stripSurf, projEM);
336
337 } else {
338 projPar = new Trk::AtaPlane(locPar[0], locPar[1], locPar[2], locPar[3], locPar[4], *stripSurf);
339 }
340
341 // verify
342 if (m_alignedMode && (parm->position() - projPar->position()).mag() > 0.001) {
343 ATH_MSG_DEBUG("geometrical TGC projection ( layer2detEl ):"
344 << m_idHelperSvc->tgcIdHelper().stationName(id) << "," << m_idHelperSvc->tgcIdHelper().stationEta(id) << ","
345 << m_idHelperSvc->tgcIdHelper().stationPhi(id) << "," << m_idHelperSvc->tgcIdHelper().isStrip(id));
346 Amg::Vector2D locPos;
347 const Amg::Vector3D& globPos = parm->position();
348 bool onSurface = stripSurf->globalToLocal(globPos, globPos, locPos);
349 if (onSurface) {
350 locPar[0] = locPos[0];
351 locPar[1] = locPos[1];
352 delete projPar;
353 projPar = nullptr;
354 projPar = bcov ? new Trk::AtaPlane(locPar[0], locPar[1], locPar[2], locPar[3], locPar[4], *stripSurf, projEM)
355 : new Trk::AtaPlane(locPar[0], locPar[1], locPar[2], locPar[3], locPar[4], *stripSurf);
356 } else {
357 delete projPar;
358 return nullptr;
359 }
360 }
361 }
362
363 return projPar;
364}
365
367 Identifier id) const {
368 // Get the messaging service, print where you are
369 ATH_MSG_DEBUG("MuonTGMeasurementTool::detElToLayer");
370 const Trk::TrackParameters* projPar = nullptr;
371
372 // check input
373 if (!lay || !parm || !(id.get_identifier32().get_compact() > 0)) return projPar;
374
375 // check compatibility of layer info and required id ? this was already done when associating !
376 if (!lay->layerType()) return projPar;
377 Identifier layId(lay->layerType());
378
379 ATH_MSG_DEBUG("MuonTGMeasurementTool::input ok");
380
381 unsigned int hitType = 0;
382 if (m_idHelperSvc->isMdt(id)) hitType = 1;
383 if (m_idHelperSvc->isRpc(id)) hitType = 2;
384 if (m_idHelperSvc->isCsc(id)) hitType = 3;
385 if (m_idHelperSvc->isTgc(id)) hitType = 4;
386
387 unsigned int layType = 0;
388 if (m_idHelperSvc->isMdt(layId)) layType = 1;
389 if (m_idHelperSvc->isRpc(layId)) layType = 2;
390 if (m_idHelperSvc->isCsc(layId)) layType = 3;
391 if (m_idHelperSvc->isTgc(layId)) layType = 4;
392
393 if (layType != hitType) return projPar;
394
395 if (hitType == 0) {
396 ATH_MSG_DEBUG("unknown hit technology");
397 return projPar;
398 }
399
400 if (hitType == 1) {
401 // local position of the tube
402 int tube = m_idHelperSvc->mdtIdHelper().tube(id);
403 Amg::Vector2D locWire(0., lay->getRef() + (tube - 1) * 30.035);
404 if (fabs(lay->getRef()) > 10e6) {
405 double sign = (lay->getRef() > 0) ? 1. : -1.;
406 int dec = int(lay->getRef() / 1.e5);
407 double ref0 = dec / 1.e5;
408 double ref1 = lay->getRef() - dec * 1e5 - 0.5 * (sign + 1) * 1e5;
409 locWire[0] = ref0;
410 locWire[1] = ref1;
411 int tube = m_idHelperSvc->mdtIdHelper().tube(id);
412 int tubeMax = m_idHelperSvc->mdtIdHelper().tubeMax(id);
413 if (tube > 6 && tubeMax - tube > 5) locWire[0] = 0.;
414 }
415 if (sqrt(locWire[0] * locWire[0] + locWire[1] * locWire[1]) > 2000.) {
416 ATH_MSG_WARNING(name() << " wire shift out bounds for MDT tube :" << m_idHelperSvc->mdtIdHelper().stationName(id) << ","
417 << m_idHelperSvc->mdtIdHelper().stationEta(id) << "," << m_idHelperSvc->mdtIdHelper().stationPhi(id)
418 << ": abandon projection");
419 return projPar;
420 }
421 // local position (tube)
422 // const Amg::Vector2D locPos = parm->localPosition();
423 // direction at the layer
424 Amg::Vector3D dir = parm->momentum().unit();
425 Amg::Vector3D locDir = (lay->surfaceRepresentation().transform().inverse()) * dir;
427 Amg::Vector3D wireDir(1., 0., 0.);
428 const Trk::PlaneSurface* laySurf = dynamic_cast<const Trk::PlaneSurface*>(&(lay->surfaceRepresentation()));
429 if (!laySurf) return projPar;
430 //
431 double ND = dir.dot(normal);
432 double DL = locDir.dot(wireDir);
433 double A = sqrt(1. - DL * DL);
434 AmgMatrix(5, 5) mdtProj;
435 mdtProj.setIdentity();
436 //
437 double ori = (laySurf->transform().inverse() * parm->associatedSurface().transform()).rotation()(1, 1) > 0. ? -1. : 1.;
438 if (A > 10e-6) {
439 mdtProj(0, 1) = ND / A;
440 mdtProj(1, 0) = ori;
441 mdtProj(1, 1) = DL / A * sqrt(A * A - ND * ND) / A;
442 mdtProj(0, 0) = 0.;
443 } else {
444 mdtProj(0, 1) = 1.;
445 mdtProj(1, 0) = ori;
446 mdtProj(1, 1) = 0.;
447 mdtProj(0, 0) = 0.;
448 }
449 Amg::VectorX locPar = parm->parameters();
450 AmgMatrix(5, 5) mdtProjInv = mdtProj.inverse();
451 Amg::VectorX pPar = mdtProjInv * locPar;
452 pPar[0] += locWire[0];
453 pPar[1] += locWire[1];
454 ATH_MSG_DEBUG("back projected parameters(MDT->layer):" << pPar);
455
456 std::optional<AmgMatrix(5, 5)> projEM = parm->covariance()->similarity(mdtProjInv);
457
458 ATH_MSG_DEBUG("back projected covariance(MDT->layer):" << (*projEM));
459 projPar = new Trk::AtaPlane(pPar[0], pPar[1], pPar[2], pPar[3], pPar[4], *laySurf, projEM);
460 // delete projEM;
461 }
462
463 if (hitType == 2) {
464 // local position at detEl
465 // const Amg::Vector2D locPos = parm->localPosition();
466 const Trk::PlaneSurface* laySurf = dynamic_cast<const Trk::PlaneSurface*>(&(lay->surfaceRepresentation()));
467 if (!laySurf) return projPar;
468 //
469 Amg::VectorX locPar = parm->parameters();
470 AmgMatrix(5, 5)* pMx = nullptr;
471 if (m_idHelperSvc->rpcIdHelper().measuresPhi(id))
472 pMx = m_rpcProjPhi.get();
473 else
474 pMx = m_rpcProjEta.get();
475
476 double eta = 1.;
477 double sign = (m_idHelperSvc->rpcIdHelper().measuresPhi(id) && m_idHelperSvc->rpcIdHelper().doubletPhi(id) == 2) ? -1. : 1.;
478
479 double ref = (lay->getRef() > 10000.) ? lay->getRef() - 20000. : lay->getRef();
480 double zswap = (lay->getRef() > 10000.) ? -1. : 1.;
481
482 if (m_idHelperSvc->rpcIdHelper().measuresPhi(id))
483 locPar[0] *= eta;
484 else
485 locPar[1] *= -eta;
486 if (m_idHelperSvc->rpcIdHelper().measuresPhi(id))
487 locPar[1] *= zswap;
488 else
489 locPar[0] *= zswap;
490
491 Amg::VectorX pPar = (*pMx) * locPar;
492 pPar[0] += sign * ref;
493
494 //
495 ATH_MSG_DEBUG("back projected parameters(RPC->layer):" << m_idHelperSvc->rpcIdHelper().measuresPhi(id) << "," << pPar);
496
497 std::optional<AmgMatrix(5, 5)> projEM = parm->covariance()->similarityT(*pMx);
498
499 ATH_MSG_DEBUG("back projected covariance(RPC->layer):" << (*projEM));
500 projPar = new Trk::AtaPlane(pPar[0], pPar[1], pPar[2], pPar[3], pPar[4], *laySurf, projEM);
501 // delete projEM;
502
503 if ((parm->position() - projPar->position()).mag() > 0.001) {
504 ATH_MSG_DEBUG("geometrical RPC projection (detElToLayer) for hit : "
505 << m_idHelperSvc->rpcIdHelper().measuresPhi(id) << "," << m_idHelperSvc->rpcIdHelper().stationName(id) << ","
506 << m_idHelperSvc->rpcIdHelper().stationEta(id) << "," << m_idHelperSvc->rpcIdHelper().stationPhi(id) << ","
507 << m_idHelperSvc->rpcIdHelper().doubletPhi(id) << "," << m_idHelperSvc->rpcIdHelper().doubletR(id) << ","
508 << m_idHelperSvc->rpcIdHelper().doubletZ(id));
509 Amg::Vector2D locPos;
510 const Amg::Vector3D& globPos = parm->position();
511 bool onSurface = laySurf->globalToLocal(globPos, globPos, locPos);
512 if (onSurface) {
513 pPar[0] = locPos[0];
514 pPar[1] = locPos[1];
515 delete projPar;
516 projPar = new Trk::AtaPlane(pPar[0], pPar[1], pPar[2], pPar[3], pPar[4], *laySurf, projEM);
517 // delete projEM;
518 } else {
519 delete projPar;
520 return nullptr;
521 }
522 }
523 }
524
525 if (hitType == 3) {
526 // local position of detEl
527 // const Amg::Vector2D locPos = parm->localPosition();
528 const Trk::PlaneSurface* laySurf = dynamic_cast<const Trk::PlaneSurface*>(&(lay->surfaceRepresentation()));
529 if (!laySurf) return projPar;
530 // dealing with parallel displaced planes
531 double diff = m_idHelperSvc->cscIdHelper().measuresPhi(id) ? 1.55 : -1.55;
532 //
533 Amg::Vector3D layNormal = lay->surfaceRepresentation().normal();
534 double DN = parm->momentum().dot(layNormal);
535 double t = diff / DN;
536 // displacement of planes
537 const Amg::Vector2D csc_shift(0., lay->getRef());
538 // projection : take into account possible misalignment ;
539 AmgMatrix(5, 5)* pMx = nullptr;
540 if (m_idHelperSvc->cscIdHelper().measuresPhi(id))
541 pMx = m_tgcProjPhi.get();
542 else
543 pMx = m_tgcProjEta.get();
544 AmgMatrix(5, 5) pMxInv = pMx->inverse();
545 Amg::VectorX parProj = pMxInv * parm->parameters();
546 Amg::Vector3D corrLocPos = lay->surfaceRepresentation().center() - t * parm->momentum() + t * DN * layNormal;
547 Amg::Vector2D locCorrLay;
548 bool onSurface = lay->surfaceRepresentation().globalToLocal(corrLocPos, corrLocPos, locCorrLay);
549 if (onSurface && locCorrLay.size() > 0) {
550 parProj[0] += locCorrLay[Trk::locX] + csc_shift[Trk::locX];
551 parProj[1] += locCorrLay[Trk::locY] + csc_shift[Trk::locY];
552 ATH_MSG_DEBUG("back projected parameters(CSC->layer):" << m_idHelperSvc->cscIdHelper().measuresPhi(id) << "," << parProj);
553 }
554 std::optional<AmgMatrix(5, 5)> projEM = parm->covariance()->similarity(pMxInv);
555
556 ATH_MSG_DEBUG("back projected covariance(CSC->layer):" << (*projEM));
557 projPar = new Trk::AtaPlane(parProj[0], parProj[1], parProj[2], parProj[3], parProj[4], *laySurf, projEM);
558
559 ATH_MSG_DEBUG("test CSC projection:detElToLayer:" << parm->position() << "," << projPar->position());
560 }
561
562 if (hitType == 4) {
563 const Trk::PlaneSurface* laySurf = dynamic_cast<const Trk::PlaneSurface*>(&(lay->surfaceRepresentation()));
564 if (!laySurf) { return projPar; }
565
566 AmgMatrix(5, 5)* pMx = nullptr;
567 if (m_idHelperSvc->tgcIdHelper().isStrip(id))
568 pMx = m_tgcProjPhi.get();
569 else
570 pMx = m_tgcProjEta.get();
571 AmgMatrix(5, 5) pMxInv = pMx->inverse();
572 Amg::VectorX locPar = pMxInv * parm->parameters();
573 ATH_MSG_DEBUG("back projected parameters(TGC->layer):" << m_idHelperSvc->tgcIdHelper().isStrip(id) << "," << locPar);
574
575 std::optional<AmgMatrix(5, 5)> projEM = parm->covariance()->similarity(pMxInv);
576
577 ATH_MSG_DEBUG("back projected covariance(TGC->layer):" << (*projEM));
578 projPar = new Trk::AtaPlane(locPar[0], locPar[1], locPar[2], locPar[3], locPar[4], *laySurf, projEM);
579
580 // verify
581 if (m_alignedMode && (parm->position() - projPar->position()).mag() > 0.001) {
582 ATH_MSG_DEBUG("geometrical TGC projection ( detEl2Layer ):"
583 << m_idHelperSvc->tgcIdHelper().stationName(id) << "," << m_idHelperSvc->tgcIdHelper().stationEta(id) << ","
584 << m_idHelperSvc->tgcIdHelper().stationPhi(id) << "," << m_idHelperSvc->tgcIdHelper().isStrip(id));
585 Amg::Vector2D locPos;
586 const Amg::Vector3D& globPos = parm->position();
587 bool onSurface = laySurf->globalToLocal(globPos, globPos, locPos);
588 if (onSurface) {
589 locPar[0] = locPos[0];
590 locPar[1] = locPos[1];
591 delete projPar;
592 projPar = nullptr;
593 projPar = new Trk::AtaPlane(locPar[0], locPar[1], locPar[2], locPar[3], locPar[4], *laySurf, projEM);
594 } else {
595 delete projPar;
596 return nullptr;
597 }
598 }
599 }
600 return projPar;
601}
602
604 const Trk::RIO_OnTrack* rio) const {
605 const MuonGM::MuonDetectorManager* MuonDetMgr = m_muonDetMgr;
606 if (!m_useDSManager) {
608 MuonDetMgr = DetectorManagerHandle.cptr();
609 if (MuonDetMgr == nullptr) {
610 ATH_MSG_ERROR("Null pointer to the read MuonDetectorManager conditions object");
611 // return StatusCode::FAILURE;
612 }
613 }
614 // Get the messaging service, print where you are
615 ATH_MSG_DEBUG("MuonTGMeasurementTool::measToLayer");
616 const Trk::RIO_OnTrack* projRIO = nullptr;
617
618 // check input
619 if (!lay || !parm || !rio) return projRIO;
620
621 // check compatibility of layer info and required id ? this was already done when associating !
622 Identifier id = rio->identify();
623
624 ATH_MSG_DEBUG("MuonTGMeasurementTool::input ok");
625
626 unsigned int hitType = 0;
627 if (m_idHelperSvc->isMdt(id)) hitType = 1;
628 if (m_idHelperSvc->isRpc(id)) hitType = 2;
629 if (m_idHelperSvc->isCsc(id)) hitType = 3;
630 if (m_idHelperSvc->isTgc(id)) hitType = 4;
631
632 if (hitType == 1) {
633 // local position of the tube
634 int tube = m_idHelperSvc->mdtIdHelper().tube(id);
635 Amg::Vector2D locWire(0., lay->getRef() + (tube - 1) * 30.035);
636 if (fabs(lay->getRef()) > 10e6) {
637 double sign = (lay->getRef() > 0) ? 1. : -1.;
638 int dec = int(lay->getRef() / 1.e5);
639 double ref0 = dec / 1.e5;
640 double ref1 = lay->getRef() - dec * 1e5 - 0.5 * (sign + 1) * 1e5;
641 locWire[0] = ref0;
642 locWire[1] = ref1;
643 int tube = m_idHelperSvc->mdtIdHelper().tube(id);
644 int tubeMax = m_idHelperSvc->mdtIdHelper().tubeMax(id);
645 if (tube > 6 && tubeMax - tube > 5) locWire[0] = 0.;
646 }
647 // direction at the layer
648 Amg::Vector3D dir = parm->momentum().unit();
649 Amg::Vector3D locDir = (lay->surfaceRepresentation().transform().inverse()) * dir;
651 Amg::Vector3D wireDir(1., 0., 0.);
652 //
653 double ND = dir.dot(normal);
654 double DL = locDir.dot(wireDir);
655 double A = sqrt(1. - DL * DL);
656 double A_ND = A / ND;
657 //
658 double locLay = A_ND * rio->localParameters()[Trk::locR] + locWire[1];
659 // create (fake!) rio ( rio image on TG layer )
660 const MuonGM::MdtReadoutElement* mdtROE = MuonDetMgr->getMdtReadoutElement(id);
661 auto cov = Amg::MatrixX();
662 cov = A_ND * A_ND * rio->localCovariance();
664 const Muon::MdtPrepData* mdtPrd =
665 new Muon::MdtPrepData(id,
666 Amg::Vector2D(locLay, 0.),
667 cov,
668 mdtROE,
669 0,
670 0,
671 status);
674 Muon::MuonDriftCircleErrorStrategy strat(stratbits);
675 const Muon::MdtDriftCircleOnTrack* mdtRio =
677 Amg::MatrixX(mdtPrd->localCovariance()), 0., Trk::DECIDED, 0.0, strat);
678 return mdtRio;
679 }
680
681 else if (hitType == 2) {
682 //
683 double eta = (m_idHelperSvc->rpcIdHelper().stationEta(id) < 0) ? -1. : 1.;
684 double sign = (m_idHelperSvc->rpcIdHelper().measuresPhi(id) && m_idHelperSvc->rpcIdHelper().doubletPhi(id) == 2) ? -1. : 1.;
685
686 double locPos = rio->localParameters()[Trk::locX];
687
688 if (m_idHelperSvc->rpcIdHelper().measuresPhi(id)) locPos *= eta;
689
690 double ref = (lay->getRef() > 10000.) ? lay->getRef() - 20000. : lay->getRef();
691 double zswap = (lay->getRef() > 10000.) ? -1. : 1.;
692
693 if (m_idHelperSvc->rpcIdHelper().measuresPhi(id))
694 locPos += sign * ref;
695 else
696 locPos *= zswap;
697 //
698 const MuonGM::RpcReadoutElement* rpcROE = MuonDetMgr->getRpcReadoutElement(id);
699 const IdentifierHash idHash(0);
700 std::vector<Identifier> rdoList;
701 rdoList.push_back(id);
702 const Muon::RpcPrepData* rpcPrd = new Muon::RpcPrepData(id, idHash, Amg::Vector2D(locPos, 0.), rdoList,
703 Amg::MatrixX(rio->localCovariance()), rpcROE, float(0.), 0, 0);
704 const Muon::RpcClusterOnTrack* rpcRio = nullptr;
705 if (m_idHelperSvc->rpcIdHelper().measuresPhi(id))
708 else
711 return rpcRio;
712 }
713
714 else if (hitType == 3) {
715 // dealing with parallel displaced planes
716 double diff = m_idHelperSvc->cscIdHelper().measuresPhi(id) ? 1.55 : -1.55;
717 //
718 Amg::Vector3D layNormal = lay->surfaceRepresentation().normal();
719 double DN = parm->momentum().dot(layNormal);
720 double t = diff / DN;
721 // displacement of planes
722 const Amg::Vector2D csc_shift(0., lay->getRef());
723 Amg::Vector3D corrLocPos = lay->surfaceRepresentation().center() - t * parm->momentum() + t * DN * layNormal;
724 Amg::Vector2D locCorrLay;
725 bool onSurface = lay->surfaceRepresentation().globalToLocal(corrLocPos, corrLocPos, locCorrLay);
726 //
727 // if( !locCorrLay.size()==2) { ??
728 if (!onSurface) { return projRIO; }
729 double locPos;
730 if (m_idHelperSvc->cscIdHelper().measuresPhi(id)) {
731 locPos = rio->localParameters()[Trk::locX] + locCorrLay[Trk::locX] + csc_shift[Trk::locX];
732 } else {
733 locPos = rio->localParameters()[Trk::locX] + locCorrLay[Trk::locY] + csc_shift[Trk::locY];
734 }
735 //
736 const MuonGM::CscReadoutElement* cscROE = MuonDetMgr->getCscReadoutElement(id);
737 IdentifierHash idHash(0);
738 std::vector<Identifier> rdoList;
739 rdoList.push_back(id);
741 const Muon::CscPrepData* cscPrd =
742 new Muon::CscPrepData(id,
743 idHash,
744 Amg::Vector2D(locPos, 0.),
745 rdoList,
747 cscROE,
748 0,
749 0.,
750 status);
751 const Muon::CscClusterOnTrack* cscRio = nullptr;
752 if (m_idHelperSvc->cscIdHelper().measuresPhi(id))
754 Amg::MatrixX(cscPrd->localCovariance()), parm->localPosition()[Trk::locY], cscPrd->status());
755 else
757 Amg::MatrixX(cscPrd->localCovariance()), parm->localPosition()[Trk::locX], cscPrd->status());
758 return cscRio;
759 }
760
761 else if (hitType == 4) {
762 //
763 double locPos = rio->localParameters()[Trk::locX];
764 //
765 const MuonGM::TgcReadoutElement* tgcROE = MuonDetMgr->getTgcReadoutElement(id);
766 IdentifierHash idHash(0);
767 std::vector<Identifier> rdoList;
768 rdoList.push_back(id);
769 const Muon::TgcPrepData* tgcPrd =
770 new Muon::TgcPrepData(id,
771 idHash,
772 Amg::Vector2D(locPos, 0.),
773 rdoList,
775 tgcROE);
776 const Muon::TgcClusterOnTrack* tgcRio = nullptr;
777 if (m_idHelperSvc->tgcIdHelper().isStrip(id)) {
778 Amg::Vector2D loc(locPos, parm->localPosition()[Trk::locY]);
781 } else {
784 }
785 return tgcRio;
786 }
787
788 ATH_MSG_DEBUG("unknown hit technology");
789 return projRIO;
790}
791
793 double& pitch) const {
794 const MuonGM::MuonDetectorManager* MuonDetMgr = m_muonDetMgr;
795 if (!m_useDSManager) {
797 MuonDetMgr = DetectorManagerHandle.cptr();
798 if (MuonDetMgr == nullptr) { ATH_MSG_ERROR("Null pointer to the read MuonDetectorManager conditions object"); }
799 }
800 // Get the messaging service, print where you are
801 ATH_MSG_DEBUG("MuonTGMeasurementTool::nearestDetEl");
802 Identifier nid(0);
803 // check input
804 if (!lay || !parm || !lay->layerType()) return nid;
805
806 // check compatibility of layer info and required id ? this was already done when associating !
807 Identifier layId(lay->layerType());
808
809 unsigned int hitType = 0;
810 if (m_idHelperSvc->isMdt(layId)) hitType = 1;
811 if (m_idHelperSvc->isRpc(layId)) hitType = 2;
812 if (m_idHelperSvc->isCsc(layId)) hitType = 3;
813 if (m_idHelperSvc->isTgc(layId)) hitType = 4;
814
815 if (hitType == 0) {
816 ATH_MSG_DEBUG("unknown hit technology");
817 return nid;
818 }
819
820 if (hitType == 1) {
821 const MuonGM::MdtReadoutElement* mdtROE = MuonDetMgr->getMdtReadoutElement(layId);
822 if (!mdtROE) return nid;
823 int tMax = mdtROE->getNtubesperlayer();
824 // local position at layer
825 Amg::Vector2D locLay;
826 const Amg::Vector3D& globPos = parm->position();
827 bool onSurface = lay->surfaceRepresentation().globalToLocal(globPos, globPos, locLay);
828 if (!onSurface || measPhi) { return nid; }
829 // nearest tube index
830 double refL = lay->getRef();
831 if (fabs(refL) > 10e6) {
832 double sign = (lay->getRef() > 0) ? 1. : -1.;
833 int dec = int(lay->getRef() / 1.e5);
834 refL = lay->getRef() - dec * 1e5 - 0.5 * (sign + 1) * 1e5;
835 }
836 double dloc = locLay[Trk::locY] - refL + 15.0175;
837 int itube = int(dloc / 30.035) + 1;
838 if (itube < 1 || itube > tMax || dloc < 0.) { return nid; }
839 // tube id
840 Identifier nearId = m_idHelperSvc->mdtIdHelper().channelID(
841 m_idHelperSvc->mdtIdHelper().stationName(layId), m_idHelperSvc->mdtIdHelper().stationEta(layId),
842 m_idHelperSvc->mdtIdHelper().stationPhi(layId), m_idHelperSvc->mdtIdHelper().multilayer(layId),
843 m_idHelperSvc->mdtIdHelper().tubeLayer(layId), itube);
844 // check if position within active volume
845 if (fabs(locLay[Trk::locX]) > 0.5 * mdtROE->getActiveTubeLength(m_idHelperSvc->mdtIdHelper().tubeLayer(layId), itube)) {
846 return nid;
847 }
848 //
849 if (m_idHelperSvc->mdtIdHelper().valid(nearId))
850 return nearId;
851 else
852 return nid;
853 }
854
855 if (hitType == 2) {
856 // identify phi doublet first
857 Identifier phiId(0);
858 // both phi and eta needs to be within bounds !!!
859 int doubletPhi = 1;
860 bool foundDoubletPhi = false;
861 const MuonGM::RpcReadoutElement* rpcROE = nullptr;
862 while (!foundDoubletPhi && doubletPhi < 3) {
863 Identifier refPhi1 = m_idHelperSvc->rpcIdHelper().channelID(
864 m_idHelperSvc->rpcIdHelper().stationName(layId), m_idHelperSvc->rpcIdHelper().stationEta(layId),
865 m_idHelperSvc->rpcIdHelper().stationPhi(layId), m_idHelperSvc->rpcIdHelper().doubletR(layId),
866 m_idHelperSvc->rpcIdHelper().doubletZ(layId), doubletPhi, m_idHelperSvc->rpcIdHelper().gasGap(layId), 1, 1);
867 rpcROE = MuonDetMgr->getRpcReadoutElement(refPhi1);
868 if (!rpcROE) return nid;
869 if (!m_idHelperSvc->rpcIdHelper().valid(refPhi1)) return nid;
870 int nStripPhi = rpcROE->Nstrips(1);
871
872 Identifier refPhiN = m_idHelperSvc->rpcIdHelper().channelID(
873 m_idHelperSvc->rpcIdHelper().stationName(layId), m_idHelperSvc->rpcIdHelper().stationEta(layId),
874 m_idHelperSvc->rpcIdHelper().stationPhi(layId), m_idHelperSvc->rpcIdHelper().doubletR(layId),
875 m_idHelperSvc->rpcIdHelper().doubletZ(layId), doubletPhi, m_idHelperSvc->rpcIdHelper().gasGap(layId), 1, nStripPhi);
876 //
877 Amg::Vector2D loc1;
878 const Amg::Vector3D globPos1 = rpcROE->stripPos(refPhi1);
879 bool onSurface1 = rpcROE->surface(refPhi1).globalToLocal(globPos1, globPos1, loc1);
880 Amg::Vector2D locN;
881 const Amg::Vector3D globPosN = rpcROE->stripPos(refPhiN);
882 bool onSurfaceN = rpcROE->surface(refPhiN).globalToLocal(globPosN, globPosN, locN);
883 Amg::Vector2D loc;
884 const Amg::Vector3D& glob = parm->position();
885 bool onSurface = rpcROE->surface(refPhiN).globalToLocal(glob, glob, loc);
886
887 int strip = 0;
888 if (onSurface1 && onSurfaceN && onSurface) {
889 pitch = (locN[Trk::locX] - loc1[Trk::locX]) / fmax(1, nStripPhi - 1);
890 double dstrip = (loc[Trk::locX] - loc1[Trk::locX]) / pitch + 0.5;
891 strip = dstrip >= 0. ? int(dstrip) + 1 : 0;
892
893 if (strip > 0 && strip <= nStripPhi) {
894 // correct doublet
895 phiId = m_idHelperSvc->rpcIdHelper().channelID(
896 m_idHelperSvc->rpcIdHelper().stationName(layId), m_idHelperSvc->rpcIdHelper().stationEta(layId),
897 m_idHelperSvc->rpcIdHelper().stationPhi(layId), m_idHelperSvc->rpcIdHelper().doubletR(layId),
898 m_idHelperSvc->rpcIdHelper().doubletZ(layId), doubletPhi, m_idHelperSvc->rpcIdHelper().gasGap(layId), 1, strip);
899 foundDoubletPhi = true;
900
901 } else {
902 doubletPhi += 1;
903 }
904 } else
905 doubletPhi += 1;
906 }
907 // no valid phi strip - skip search
908 if (!foundDoubletPhi) return nid;
909
910 // eta strip
911 Identifier etaId(0);
912 int doubletZ = 1;
913 while (doubletZ < 4) {
914 Identifier refEta1 = m_idHelperSvc->rpcIdHelper().channelID(
915 m_idHelperSvc->rpcIdHelper().stationName(layId), m_idHelperSvc->rpcIdHelper().stationEta(layId),
916 m_idHelperSvc->rpcIdHelper().stationPhi(layId), m_idHelperSvc->rpcIdHelper().doubletR(layId), doubletZ, doubletPhi,
917 m_idHelperSvc->rpcIdHelper().gasGap(layId), 0, 1);
918 rpcROE = MuonDetMgr->getRpcReadoutElement(refEta1);
919 if (!rpcROE) return nid;
920 if (!m_idHelperSvc->rpcIdHelper().valid(refEta1)) return nid;
921 int nStrips = rpcROE->Nstrips(0);
922
923 Identifier refEtaN = m_idHelperSvc->rpcIdHelper().channelID(
924 m_idHelperSvc->rpcIdHelper().stationName(layId), m_idHelperSvc->rpcIdHelper().stationEta(layId),
925 m_idHelperSvc->rpcIdHelper().stationPhi(layId), m_idHelperSvc->rpcIdHelper().doubletR(layId), doubletZ, doubletPhi,
926 m_idHelperSvc->rpcIdHelper().gasGap(layId), 0, nStrips);
927 //
928
929 Amg::Vector2D loc1;
930 const Amg::Vector3D globPos1 = rpcROE->stripPos(refEta1);
931 bool onSurface1 = rpcROE->surface(refEta1).globalToLocal(globPos1, globPos1, loc1);
932 Amg::Vector2D locN;
933 const Amg::Vector3D globPosN = rpcROE->stripPos(refEtaN);
934 bool onSurfaceN = rpcROE->surface(refEtaN).globalToLocal(globPosN, globPosN, locN);
935 Amg::Vector2D loc;
936 const Amg::Vector3D& glob = parm->position();
937 bool onSurface = rpcROE->surface(refEtaN).globalToLocal(glob, glob, loc);
938
939 int strip = 0;
940 if (onSurface && onSurface1 && onSurfaceN) {
941 pitch = (locN[Trk::locX] - loc1[Trk::locX]) / fmax(1, nStrips - 1);
942 // strip = int( (refPar->localPosition()[Trk::locX]-loc1[Trk::locX])/pitch+0.5 )+1;
943 double dstrip = (loc[Trk::locX] - loc1[Trk::locX]) / pitch + 0.5;
944 strip = dstrip >= 0. ? int(dstrip) + 1 : 0;
945
946 if (strip > 0 && strip <= nStrips) {
947 etaId = m_idHelperSvc->rpcIdHelper().channelID(
948 m_idHelperSvc->rpcIdHelper().stationName(layId), m_idHelperSvc->rpcIdHelper().stationEta(layId),
949 m_idHelperSvc->rpcIdHelper().stationPhi(layId), m_idHelperSvc->rpcIdHelper().doubletR(layId), doubletZ, doubletPhi,
950 m_idHelperSvc->rpcIdHelper().gasGap(layId), 0, strip);
951 if (measPhi)
952 return phiId;
953 else
954 return etaId;
955 }
956 }
957 doubletZ += 1;
958 }
959
960 return nid;
961 }
962
963 if (hitType == 3) {
964 // ref id
965 Identifier refId = m_idHelperSvc->cscIdHelper().channelID(
966 m_idHelperSvc->cscIdHelper().stationName(layId), m_idHelperSvc->cscIdHelper().stationEta(layId),
967 m_idHelperSvc->cscIdHelper().stationPhi(layId), m_idHelperSvc->cscIdHelper().chamberLayer(layId),
968 m_idHelperSvc->cscIdHelper().wireLayer(layId), measPhi, 1);
969 if (!m_idHelperSvc->cscIdHelper().valid(refId)) return nid;
970 // residual in ref frame
971 const Trk::TrackParameters* refPar = layerToDetEl(lay, parm, refId);
972 if (!refPar) return nid;
973 //
974 const MuonGM::CscReadoutElement* cscROE = MuonDetMgr->getCscReadoutElement(refId);
975 if (!cscROE) {
976 delete refPar;
977 return nid;
978 }
979 pitch = cscROE->StripPitch(measPhi);
980 int nStrips = m_idHelperSvc->cscIdHelper().stripMax(refId);
981 if (nStrips < 1) {
982 delete refPar;
983 return nid;
984 }
985
986 Identifier refIdN = m_idHelperSvc->cscIdHelper().channelID(
987 m_idHelperSvc->cscIdHelper().stationName(refId), m_idHelperSvc->cscIdHelper().stationEta(refId),
988 m_idHelperSvc->cscIdHelper().stationPhi(refId), m_idHelperSvc->cscIdHelper().chamberLayer(refId),
989 m_idHelperSvc->cscIdHelper().wireLayer(refId), measPhi, nStrips);
990 //
991 Amg::Vector3D loc1 = cscROE->surface(refId).transform().inverse() * cscROE->stripPos(refId);
992 Amg::Vector3D locN = cscROE->surface(refIdN).transform().inverse() * cscROE->stripPos(refIdN);
993 int strip = 0;
994
995 pitch = (locN[0] - loc1[0]) / fmax(1, nStrips - 1);
996 strip = int((refPar->localPosition()[Trk::locX] - loc1[0]) / pitch + 0.5) + 1;
997
998 delete refPar;
999 refPar = nullptr;
1000 if (strip > 0 && strip <= nStrips) {
1001 // strip id
1002 Identifier nearId = m_idHelperSvc->cscIdHelper().channelID(
1003 m_idHelperSvc->cscIdHelper().stationName(layId), m_idHelperSvc->cscIdHelper().stationEta(layId),
1004 m_idHelperSvc->cscIdHelper().stationPhi(layId), m_idHelperSvc->cscIdHelper().chamberLayer(layId),
1005 m_idHelperSvc->cscIdHelper().wireLayer(layId), measPhi, strip);
1006 if (fabs(residual(parm, nearId)) > 0.5 * pitch)
1007 ATH_MSG_DEBUG("nearest CSC channel residual too large: " << residual(parm, nearId));
1008 return nearId;
1009 }
1010 }
1011
1012 if (hitType == 4) { // ref id
1013 if (measPhi && m_idHelperSvc->tgcIdHelper().gasGap(layId) == 2 && m_idHelperSvc->tgcIdHelper().gasGapMax(layId) == 3)
1014 return nid; // no phi strips here
1015 // ref id
1016 Identifier refId = layId;
1017 if (measPhi)
1018 refId = m_idHelperSvc->tgcIdHelper().channelID(
1019 m_idHelperSvc->tgcIdHelper().stationName(layId), m_idHelperSvc->tgcIdHelper().stationEta(layId),
1020 m_idHelperSvc->tgcIdHelper().stationPhi(layId), m_idHelperSvc->tgcIdHelper().gasGap(layId), measPhi, 1);
1021 if (!m_idHelperSvc->tgcIdHelper().valid(refId)) return nid;
1022 // residual in ref frame
1023 const Trk::TrackParameters* refPar = layerToDetEl(lay, parm, refId);
1024 if (!refPar) return nid;
1025 //
1026 const MuonGM::TgcReadoutElement* tgcROE = MuonDetMgr->getTgcReadoutElement(layId);
1027 if (!tgcROE) {
1028 delete refPar;
1029 return nid;
1030 }
1031 int nStrips = m_idHelperSvc->tgcIdHelper().channelMax(refId);
1032
1033 if (nStrips < 1) {
1034 delete refPar;
1035 return nid;
1036 }
1037
1038 Identifier refIdN = m_idHelperSvc->tgcIdHelper().channelID(
1039 m_idHelperSvc->tgcIdHelper().stationName(layId), m_idHelperSvc->tgcIdHelper().stationEta(layId),
1040 m_idHelperSvc->tgcIdHelper().stationPhi(layId), m_idHelperSvc->tgcIdHelper().gasGap(layId), measPhi, nStrips);
1041 //
1042 Amg::Vector2D loc1;
1043 const Amg::Vector3D glob1 = tgcROE->channelPos(refId);
1044 bool onSurface1 = tgcROE->surface(refId).globalToLocal(glob1, glob1, loc1);
1045 Amg::Vector2D locN;
1046 const Amg::Vector3D globN = tgcROE->channelPos(refIdN);
1047 bool onSurfaceN = tgcROE->surface(refIdN).globalToLocal(globN, globN, locN);
1048
1049 int strip = 0;
1050 if (onSurface1 && onSurfaceN) {
1051 pitch = (locN[Trk::locX] - loc1[Trk::locX]) / fmax(1, nStrips - 1);
1052 strip = int((refPar->localPosition()[Trk::locX] - loc1[Trk::locX]) / pitch + 0.5) + 1;
1053 } else {
1054 ATH_MSG_DEBUG("local position of boundary elements not retrieved, return 0 ");
1055 delete refPar;
1056 return nid;
1057 }
1058
1059 if (strip > 0 && strip <= nStrips) {
1060 // check second coordinate for active volume
1061 if (!measPhi && fabs(refPar->localPosition()[Trk::locY]) >
1062 tgcROE->gangCentralWidth(m_idHelperSvc->tgcIdHelper().gasGap(layId), strip)) {
1063 delete refPar;
1064 return nid;
1065 }
1066 Identifier nearId = m_idHelperSvc->tgcIdHelper().channelID(
1067 m_idHelperSvc->tgcIdHelper().stationName(layId), m_idHelperSvc->tgcIdHelper().stationEta(layId),
1068 m_idHelperSvc->tgcIdHelper().stationPhi(layId), m_idHelperSvc->tgcIdHelper().gasGap(layId), measPhi, strip);
1069 Amg::Vector3D stripposition = tgcROE->surface(nearId).transform().inverse() * tgcROE->channelPos(nearId);
1070 Amg::Vector3D localhit = tgcROE->surface(nearId).transform().inverse() * parm->position();
1071
1072 int plane = m_idHelperSvc->tgcIdHelper().gasGap(nearId);
1073 if (m_idHelperSvc->tgcIdHelper().isStrip(nearId))
1074 pitch = tgcROE->stripPitch(plane, m_idHelperSvc->tgcIdHelper().channel(nearId), localhit[1]);
1075 int last = 0;
1076 while (fabs(stripposition[0] - localhit[0]) > 0.5 * pitch) {
1077 if (stripposition[0] < localhit[0]) {
1078 if (last != -1) {
1079 strip += 1;
1080 last = 1;
1081 } else
1082 break;
1083 } else {
1084 if (last != 1) {
1085 strip -= 1;
1086 last = -1;
1087 } else
1088 break;
1089 }
1090 if (strip < 1 || strip > nStrips) break;
1091 nearId = m_idHelperSvc->tgcIdHelper().channelID(
1092 m_idHelperSvc->tgcIdHelper().stationName(layId), m_idHelperSvc->tgcIdHelper().stationEta(layId),
1093 m_idHelperSvc->tgcIdHelper().stationPhi(layId), m_idHelperSvc->tgcIdHelper().gasGap(layId), measPhi, strip);
1094 stripposition = tgcROE->surface(nearId).transform().inverse() * tgcROE->channelPos(nearId);
1095 localhit = tgcROE->surface(nearId).transform().inverse() * parm->position();
1096 if (m_idHelperSvc->tgcIdHelper().isStrip(nearId))
1097 pitch = tgcROE->stripPitch(plane, m_idHelperSvc->tgcIdHelper().channel(nearId), localhit[1]);
1098 }
1099 delete refPar;
1100 if (strip < 1 || strip > nStrips) return nid;
1101 if (m_idHelperSvc->tgcIdHelper().valid(nearId))
1102 return nearId;
1103 else
1104 return nid;
1105 }
1106 delete refPar;
1107 }
1108 return nid;
1109}
1110
1112 // Get the messaging service, print where you are
1113 ATH_MSG_DEBUG("MuonTGMeasurementTool::associatedLayer");
1114 const Trk::Layer* lay = nullptr;
1115 // check input
1116 if (!id.get_identifier32().get_compact()) return lay;
1117
1118 // rely on having misalignment uncertainty covered by span safety marge ( don't loose station from static volume
1119 // when misaligned
1120 const Trk::TrackingVolume* staticVol = getGeometry()->lowestStaticTrackingVolume(gp);
1121 const Trk::DetachedTrackingVolume* station = nullptr;
1122 if (staticVol && !staticVol->confinedDetachedVolumes().empty()) {
1124 for (const auto *i : detTV) {
1125 if (i->layerRepresentation() && i->layerRepresentation()->layerType() > 0) {
1126 Identifier stId(i->layerRepresentation()->layerType());
1127 if (m_idHelperSvc->mdtIdHelper().stationName(stId) == m_idHelperSvc->mdtIdHelper().stationName(id) &&
1128 m_idHelperSvc->mdtIdHelper().stationEta(stId) == m_idHelperSvc->mdtIdHelper().stationEta(id) &&
1129 m_idHelperSvc->mdtIdHelper().stationPhi(stId) == m_idHelperSvc->mdtIdHelper().stationPhi(id)) {
1130 station = i;
1131 break;
1132 }
1133 }
1134 }
1135 }
1136
1137 if (station) lay = associatedLayer(id, station->trackingVolume());
1138
1139 return lay;
1140}
1141
1143 const Trk::Layer* lay = nullptr;
1144 // check input
1145 if (!vol) return lay;
1146
1147 if (vol->confinedVolumes()) {
1148 std::span<Trk::TrackingVolume const * const > subVols = vol->confinedVolumes()->arrayObjects();
1149 std::span<Trk::TrackingVolume const * const >::iterator iter = subVols.begin();
1150 while (!lay && iter != subVols.end()) {
1151 lay = associatedLayer(id, *iter);
1152 if (lay) break;
1153 ++iter;
1154 }
1155 if (lay) return lay;
1156 }
1157
1158 if (vol->confinedLayers()) {
1159 std::span<Trk::Layer const * const > ordLay = vol->confinedLayers()->arrayObjects();
1160 std::span<Trk::Layer const * const >::iterator iter = ordLay.begin();
1161 while (!lay && iter != ordLay.end()) {
1162 lay = match(id, *iter);
1163 if (lay) break;
1164 ++iter;
1165 }
1166 if (lay) return lay;
1167 }
1168
1169 if (!vol->confinedArbitraryLayers().empty()) {
1171 Trk::ArraySpan<const Trk::Layer* const>::iterator iter = unOrdLay.begin();
1172 while (!lay && iter != unOrdLay.end()) {
1173 lay = match(id, *iter);
1174 if (lay) break;
1175 ++iter;
1176 }
1177 if (lay) return lay;
1178 }
1179
1180 return lay;
1181}
1182
1184 const Trk::Layer* mLay = nullptr;
1185 if (!id.get_identifier32().get_compact() || !lay || !lay->layerType()) return mLay;
1186
1187 Identifier layId(lay->layerType());
1188
1189 if (m_idHelperSvc->isMdt(id) && m_idHelperSvc->isMdt(layId)) {
1190 if (m_idHelperSvc->mdtIdHelper().multilayer(layId) == m_idHelperSvc->mdtIdHelper().multilayer(id) &&
1191 m_idHelperSvc->mdtIdHelper().tubeLayer(layId) == m_idHelperSvc->mdtIdHelper().tubeLayer(id))
1192 return lay;
1193 }
1194
1195 if (m_idHelperSvc->isRpc(id) && m_idHelperSvc->isRpc(layId)) {
1196 if (m_idHelperSvc->rpcIdHelper().doubletR(layId) == m_idHelperSvc->rpcIdHelper().doubletR(id) &&
1197 m_idHelperSvc->rpcIdHelper().doubletZ(layId) == m_idHelperSvc->rpcIdHelper().doubletZ(id) &&
1198 m_idHelperSvc->rpcIdHelper().gasGap(layId) == m_idHelperSvc->rpcIdHelper().gasGap(id))
1199 return lay;
1200 }
1201
1202 if (m_idHelperSvc->isTgc(id) && m_idHelperSvc->isTgc(layId)) {
1203 if (m_idHelperSvc->tgcIdHelper().gasGap(layId) == m_idHelperSvc->tgcIdHelper().gasGap(id)) return lay;
1204 }
1205
1206 if (m_idHelperSvc->isCsc(id) && m_idHelperSvc->isCsc(layId)) {
1207 if (m_idHelperSvc->cscIdHelper().chamberLayer(layId) == m_idHelperSvc->cscIdHelper().chamberLayer(id) &&
1208 m_idHelperSvc->cscIdHelper().wireLayer(layId) == m_idHelperSvc->cscIdHelper().wireLayer(id))
1209 return lay;
1210 }
1211
1212 return mLay;
1213}
1214
1216 double res = 10000.;
1217 if (!layPar || !rio) return res;
1218
1219 Amg::Vector3D gp = layPar->position();
1220 const Trk::Layer* layer = associatedLayer(rio->identify(), gp);
1221 if (!layer) return res;
1222
1223 return residual(layer, layPar, rio);
1224}
1225
1227 double res = 10000.;
1228 if (!layPar || !id.get_identifier32().get_compact()) return res;
1229
1230 Amg::Vector3D gp = layPar->position();
1231 const Trk::Layer* layer = associatedLayer(id, gp);
1232 if (!layer) return res;
1233
1234 return residual(layer, layPar, id);
1235}
1236
1238 const Trk::RIO_OnTrack* rio) const {
1239 double res = 10000.;
1240 if (!layer || !layPar || !rio) return res;
1241
1242 const Trk::TrackParameters* detElPar = layerToDetEl(layer, layPar, rio->identify());
1243 if (!detElPar) return res;
1244 if (m_idHelperSvc->isMdt(rio->identify())) {
1245 res = fabs(detElPar->localPosition()[Trk::locR] - rio->localParameters()[Trk::locR]);
1246 } else {
1247 res = fabs(detElPar->localPosition()[Trk::locX] - rio->localParameters()[Trk::locX]);
1248 }
1249 delete detElPar;
1250 return res;
1251}
1252
1254 const MuonGM::MuonDetectorManager* MuonDetMgr = m_muonDetMgr;
1255 if (!m_useDSManager) {
1257 MuonDetMgr = DetectorManagerHandle.cptr();
1258 if (MuonDetMgr == nullptr) {
1259 ATH_MSG_ERROR("Null pointer to the read MuonDetectorManager conditions object");
1260 // return StatusCode::FAILURE;
1261 }
1262 }
1263
1264 double res = 10000.;
1265 if (!layer || !layPar || !id.get_identifier32().get_compact()) return res;
1266
1267 const Trk::TrackParameters* detElPar = layerToDetEl(layer, layPar, id);
1268 if (!detElPar) return res;
1269 if (m_idHelperSvc->isMdt(id)) {
1270 res = detElPar->localPosition()[Trk::locR];
1271 } else if (m_idHelperSvc->isRpc(id)) {
1272 const MuonGM::RpcReadoutElement* rpcROE = MuonDetMgr->getRpcReadoutElement(id);
1273 if (rpcROE)
1274 res = detElPar->localPosition()[Trk::locX] -
1275 (detElPar->associatedSurface().transform().inverse() * (rpcROE->stripPos(id)))[Trk::locX];
1276 } else if (m_idHelperSvc->isCsc(id)) {
1277 const MuonGM::CscReadoutElement* cscROE = MuonDetMgr->getCscReadoutElement(id);
1278 if (cscROE)
1279 res = detElPar->localPosition()[Trk::locX] - (detElPar->associatedSurface().transform().inverse() * (cscROE->stripPos(id)))[0];
1280 } else if (m_idHelperSvc->isTgc(id)) {
1281 if (m_idHelperSvc->tgcIdHelper().isStrip(id) && m_idHelperSvc->tgcIdHelper().gasGap(id) == 2 &&
1282 m_idHelperSvc->tgcIdHelper().gasGapMax(id) == 3) {
1283 delete detElPar;
1284 return res; // no phi strips here
1285 }
1286 const MuonGM::TgcReadoutElement* tgcROE = MuonDetMgr->getTgcReadoutElement(id);
1287 if (tgcROE) {
1288 Amg::Vector2D locPos;
1289 const Amg::Vector3D globPos = tgcROE->channelPos(id);
1290 bool onSurface = detElPar->associatedSurface().globalToLocal(globPos, globPos, locPos);
1291 if (onSurface) res = detElPar->localPosition()[Trk::locX] - locPos[Trk::locX];
1292 }
1293 }
1294 delete detElPar;
1295 return res;
1296}
const boost::regex ref(r_ef)
Scalar eta() const
pseudorapidity method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define AmgMatrix(rows, cols)
std::pair< std::vector< unsigned int >, bool > res
double tubeMax
void diff(const Jet &rJet1, const Jet &rJet2, std::map< std::string, double > varDiff)
Difference between jets - Non-Class function required by trigger.
Definition Jet.cxx:631
int sign(int a)
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
const ServiceHandle< StoreGateSvc > & detStore() const
This is a "hash" representation of an Identifier.
double StripPitch(int chlayer, int measphi) const
Amg::Vector3D stripPos(const Identifier &id) const
takes into account internal alignment parameters, hence gives accurate answer
double getActiveTubeLength(const int tubeLayer, const int tube) const
int getNtubesperlayer() const
Returns the number of tubes in each tube layer.
virtual const Trk::Surface & surface() const override final
Return surface associated with this detector element.
virtual const Trk::PlaneSurface & surface() const override
access to chamber surface (phi orientation), uses the first gas gap
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
const RpcReadoutElement * getRpcReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
const MdtReadoutElement * getMdtReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
const TgcReadoutElement * getTgcReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
const CscReadoutElement * getCscReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
An RpcReadoutElement corresponds to a single RPC module; therefore typicaly a barrel muon station con...
int Nstrips(bool measphi) const
returns the number of strips for the phi or eta plane
A TgcReadoutElement corresponds to a single TGC chamber; therefore typically a TGC station contains s...
Amg::Vector3D channelPos(const Identifier &id) const
Returns the position of the active channel (wireGang or strip)
double stripPitch(int gasGap, int strip) const
Returns the pitch of the given strip in gasGap i.
double gangCentralWidth(int gasGap, int gang) const
Returns the length of the central wire in the gang.
Class to represent the calibrated clusters created from CSC strips.
Class representing clusters from the CSC.
Definition CscPrepData.h:39
CscClusterStatus status() const
Returns the Csc status (position measurement) flag.
This class represents the corrected MDT measurements, where the corrections include the effects of wi...
Class to represent measurements from the Monitored Drift Tubes.
Definition MdtPrepData.h:33
Gaudi::Property< bool > m_useDSManager
std::unique_ptr< AmgMatrix(5, 5)> m_rpcProjEta
const Trk::TrackParameters * layerToDetEl(const Trk::Layer *, const Trk::TrackParameters *, Identifier) const override
const Trk::RIO_OnTrack * measToLayer(const Trk::Layer *, const Trk::TrackParameters *, const Trk::RIO_OnTrack *) const override
MuonTGMeasurementTool(const std::string &type, const std::string &name, const IInterface *)
Constructor with AlgTool parameters.
SG::ReadCondHandleKey< Trk::TrackingGeometry > m_trackingGeometryReadKey
const Identifier nearestDetEl(const Trk::Layer *, const Trk::TrackParameters *, bool measPhi, double &pitch) const override
const MuonGM::MuonDetectorManager * m_muonDetMgr
virtual StatusCode initialize() override
Gaudi::Property< bool > m_alignedMode
std::unique_ptr< AmgMatrix(5, 5)> m_rpcProjPhi
const Trk::Layer * match(Identifier id, const Trk::Layer *lay) const override
const Trk::TrackingGeometry * getGeometry() const
double residual(const Trk::Layer *, const Trk::TrackParameters *, const Trk::RIO_OnTrack *) const override
ServiceHandle< Trk::ITrackingGeometrySvc > m_trackingGeometrySvc
const Trk::Layer * associatedLayer(Identifier id, Amg::Vector3D &gp) const override
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_DetectorManagerKey
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
std::unique_ptr< AmgMatrix(5, 5)> m_tgcProjPhi
const Trk::TrackParameters * detElToLayer(const Trk::Layer *, const Trk::TrackParameters *, Identifier) const override
std::unique_ptr< AmgMatrix(5, 5)> m_tgcProjEta
Class to represent calibrated clusters formed from RPC strips.
Class to represent RPC measurements.
Definition RpcPrepData.h:35
Class to represent calibrated clusters formed from TGC strips.
Class to represent TGC measurements.
Definition TgcPrepData.h:32
const_pointer_type cptr()
virtual std::span< T *const > arrayObjects()=0
Return all objects of the Array non-const we can still modify the T.
Base Class for a navigation object (active/passive) in the Tracking realm.
const TrackingVolume * trackingVolume() const
returns the TrackingVolume
Base Class for a Detector Layer in the Tracking realm.
Definition Layer.h:72
int layerType() const
get the Layer coding
virtual const Surface & surfaceRepresentation() const =0
Transforms the layer into a Surface representation for extrapolation.
double getRef() const
get the reference measure
const LocalParameters & localParameters() const
Interface method to get the LocalParameters.
const Amg::MatrixX & localCovariance() const
Interface method to get the localError.
const Amg::Vector3D & momentum() const
Access method for the momentum.
const Amg::Vector3D & position() const
Access method for the position.
virtual const Surface & associatedSurface() const override=0
Access to the Surface associated to the Parameters.
Amg::Vector2D localPosition() const
Access method for the local coordinates, local parameter definitions differ for each surface type.
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...
const Amg::MatrixX & localCovariance() const
return const ref to the error matrix
Class to handle RIO On Tracks ROT) for InDet and Muons, it inherits from the common MeasurementBase.
Definition RIO_OnTrack.h:70
Identifier identify() const
return the identifier -extends MeasurementBase
Class for a StraightLineSurface in the ATLAS detector to describe dirft tube and straw like detectors...
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 const Amg::Vector3D & normal() const
Returns the normal vector of the Surface (i.e.
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
const Amg::Vector3D & center() const
Returns the center position of the Surface.
Full Volume description used in Tracking, it inherits from Volume to get the geometrical structure,...
const LayerArray * confinedLayers() const
Return the subLayer array.
const TrackingVolumeArray * confinedVolumes() const
Return the subLayer array.
ArraySpan< DetachedTrackingVolume const *const > confinedDetachedVolumes() const
Return detached subVolumes - not the ownership.
ArraySpan< Layer const *const > confinedArbitraryLayers() const
Return the confined subLayer array.
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:357
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
Eigen::Matrix< double, Eigen::Dynamic, 1 > VectorX
Dynamic Vector - dynamic allocation.
MdtDriftCircleStatus
Enum to represent the 'status' of Mdt measurements e.g.
@ MdtStatusDriftTime
The tube produced a vaild measurement.
std::bitset< 23 > MuonDriftCircleErrorStrategyInput
CscClusterStatus
Enum to represent the cluster status - see the specific enum values for more details.
@ CscStatusSimple
Cluster with non-precision fit.
std::span< T > ArraySpan
ParametersT< TrackParametersDim, Charged, StraightLineSurface > AtaStraightLine
@ DECIDED
sign of drift radius has been determined
@ locY
local cartesian
Definition ParamDefs.h:38
@ locX
Definition ParamDefs.h:37
@ locR
Definition ParamDefs.h:44
@ theta
Definition ParamDefs.h:66
@ qOverP
perigee
Definition ParamDefs.h:67
@ phi
Definition ParamDefs.h:75
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
ParametersT< TrackParametersDim, Charged, PlaneSurface > AtaPlane
hold the test vectors and ease the comparison