ATLAS Offline Software
Loading...
Searching...
No Matches
MooCandidateMatchingTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <cmath>
8#include <cstdlib>
9#include <iomanip>
10#include <sstream>
11#include <string>
12
25
26namespace { // local funcs
27
28 // limit angle difference to -pi/2 < x <= pi/2
29 inline double theta_diff(double x) {
30 while (x <= -M_PI_2) x += M_PI;
31 while (x > +M_PI_2) x -= M_PI;
32 return x;
33 }
34
35 // limit angle difference to -pi < x <= pi
36 inline double phi_diff(double x) {
37 while (x <= -M_PI) x += 2.0 * M_PI;
38 while (x > +M_PI) x -= 2.0 * M_PI;
39 return x;
40 }
41
42 // print covariance and correlation on one line
43 std::string printCovCorr(Amg::MatrixX& cov, const std::string& title, unsigned int prec = 3) {
44 std::ostringstream oss;
45 oss << title << " " << Amg::toString(cov, prec) << std::endl;
46 return oss.str();
47 }
48
49} // namespace
50
51namespace Muon {
52
54
60
61 MooCandidateMatchingTool::MooCandidateMatchingTool(const std::string& t, const std::string& n, const IInterface* p) :
62 AthAlgTool(t, n, p) {
63 declareInterface<MooCandidateMatchingTool>(this);
64 declareInterface<IMuonTrackSegmentMatchingTool>(this);
65
66 declareProperty("RequireSameSide", m_requireSameSide = false,
67 "require entries to be on the same side of the Perigee or Calorimeter");
68 declareProperty("MinimumRadiusSideMatch", m_minimumSideMatchRadius = 4000., "All intersects outside the radius will be accepted");
69 declareProperty("CaloMatchZ", m_caloMatchZ = 6500., "limit in Z to determine Calo crossing");
70 declareProperty("MatchAngleXCut", m_matchAngXCut = 0.1,
71 "Local X (phi) angle difference cut for track-segment matching. Disabled if 0");
72 declareProperty("MatchAngleYCut", m_matchAngYCut = 0.01,
73 "Local Y (theta) angle difference cut for track-segment matching. Disabled if 0");
74 declareProperty("MatchAngleXPullCut", m_matchAngXPullCut = 10.0,
75 "Local X (phi) angle difference pull cut for track-segment matching. Disabled if 0");
76 declareProperty("MatchAngleYPullCut", m_matchAngYPullCut = 25.0,
77 "Local Y (theta) angle difference pull cut for track-segment matching. Disabled if 0");
78 declareProperty("MatchPosXCut", m_matchPosXCut = 100.0,
79 "Local X (2nd coord) position difference cut (mm) for track-segment matching. Disabled if 0");
80 declareProperty("MatchPosYCut", m_matchPosYCut = 30.0,
81 "Local Y (precision) position difference cut (mm) for track-segment matching. Disabled if 0");
82 declareProperty("MatchPosPullCut", m_matchPosPullCut = 10.0, "Local position pull cut for track-segment matching. Disabled if 0");
83 declareProperty("MatchChiSquaredCut", m_matchChiSquaredCut = 100.0, "Cut on the track-segment matching chi-squared");
84 declareProperty("MatchChiSquaredCutTight", m_matchChiSquaredCutTight = 25.0,
85 "Cut on the track-segment matching chi-squared in case a tight cut is requested");
86 declareProperty("AlignmentErrorPosX", m_alignErrorPosX = 0.0, "Alignment precision in local X direction");
87 declareProperty("AlignmentErrorPosY", m_alignErrorPosY = 0.0, "Alignment precision in local Y direction");
88 declareProperty("AlignmentErrorAngleX", m_alignErrorAngleX = 0.0, "Alignment precision in local X angle");
89 declareProperty("AlignmentErrorAngleY", m_alignErrorAngleY = 0.0, "Alignment precision in local Y angle");
90
91 for (unsigned int i = 0; i < TrackSegmentMatchResult::NumberOfReasons; i++) {
92 m_reasonsForMatchOk[i].store(0, std::memory_order_relaxed);
93 m_reasonsForMatchNotOk[i].store(0, std::memory_order_relaxed);
94 }
95 }
96
98
100 ATH_CHECK(m_atlasExtrapolator.retrieve());
101 ATH_CHECK(m_idHelperSvc.retrieve());
102 ATH_CHECK(m_edmHelperSvc.retrieve());
103 ATH_CHECK(m_printer.retrieve());
107 ATH_CHECK(m_candidateTool.retrieve());
108
109 return StatusCode::SUCCESS;
110 }
111
113 int segmentMatchesLoose = m_segmentMatches - m_segmentMatchesTight;
114 int goodSegmentMatchesLoose = m_goodSegmentMatches - m_goodSegmentMatchesTight;
115 double sameScale = m_sameSideOfPerigee != 0 ? m_segmentMatches / m_sameSideOfPerigee : 1.;
116 double scale = m_segmentMatches != 0 ? 1. / ((double)m_segmentMatches) : 1.;
117 double scaleTight = m_segmentMatchesTight != 0 ? 1. / ((double)m_segmentMatchesTight) : 1.;
118 double scaleLoose = segmentMatchesLoose != 0.0 ? 1. / ((double)segmentMatchesLoose) : 1.;
119 msg(MSG::INFO) << std::fixed << std::setprecision(3);
120 msg(MSG::INFO) << "Segment/segment matches: total " << std::setw(7) << m_segmentMatches << " tight " << std::setw(7)
121 << m_segmentMatchesTight << endmsg << " same side " << std::setw(7) << m_sameSideOfPerigee << " fraction "
122 << m_sameSideOfPerigee * scale << endmsg << " other side " << std::setw(7) << m_otherSideOfPerigee << " fraction "
123 << m_otherSideOfPerigee * scale << endmsg << " good total " << std::setw(7) << m_goodSegmentMatches << " fraction "
124 << m_goodSegmentMatches * scale * sameScale << endmsg << " good loose " << std::setw(7) << goodSegmentMatchesLoose
125 << " fraction " << goodSegmentMatchesLoose * scaleLoose * sameScale << endmsg << " good tight " << std::setw(7)
126 << m_goodSegmentMatchesTight << " fraction " << m_goodSegmentMatchesTight * scaleTight * sameScale << endmsg;
127
128 int segmentTrackMatchesLoose = m_segmentTrackMatches - m_segmentTrackMatchesTight;
129 int goodSegmentTrackMatchesLoose = m_goodSegmentTrackMatches - m_goodSegmentTrackMatchesTight;
130 double sameScaleTrack = m_sameSideOfPerigeeTrk != 0 ? m_segmentTrackMatches / m_sameSideOfPerigeeTrk : 1.;
131 double scaleTrack = m_segmentTrackMatches != 0 ? 1. / ((double)m_segmentTrackMatches) : 1.;
132 double scaleTrackTight = m_segmentTrackMatchesTight != 0 ? 1. / ((double)m_segmentTrackMatchesTight) : 1.;
133 double scaleTrackLoose = segmentTrackMatchesLoose != 0.0 ? 1. / ((double)segmentTrackMatchesLoose) : 1.;
134 msg(MSG::INFO) << "Track/segment matches: total " << std::setw(7) << m_segmentTrackMatches << " tight " << std::setw(7)
135 << m_segmentTrackMatchesTight << endmsg << " same side " << std::setw(7) << m_sameSideOfPerigeeTrk << " fraction "
136 << m_sameSideOfPerigeeTrk * scaleTrack << endmsg << " other side " << std::setw(7) << m_otherSideOfPerigeeTrk
137 << " fraction " << m_otherSideOfPerigeeTrk * scaleTrack << endmsg << " good total " << std::setw(7)
138 << m_goodSegmentTrackMatches << " fraction " << m_goodSegmentTrackMatches * scaleTrack * sameScaleTrack << endmsg
139 << " good loose " << std::setw(7) << goodSegmentTrackMatchesLoose << " fraction "
140 << goodSegmentTrackMatchesLoose * scaleTrackLoose * sameScaleTrack << endmsg << " good tight " << std::setw(7)
141 << m_goodSegmentTrackMatchesTight << " fraction "
142 << m_goodSegmentTrackMatchesTight * scaleTrackTight * sameScaleTrack << endmsg;
143 // get printing width
144 unsigned int nReasons = (int)TrackSegmentMatchResult::NumberOfReasons;
145 unsigned int width = 0;
146 for (unsigned int i = 0; i < nReasons; ++i) {
148 if (w > width) width = w;
149 }
150 // print it
151 msg(MSG::INFO) << " Reasons for match failures:" << endmsg;
152 for (unsigned int i = 0; i < nReasons; ++i) {
153 int cnt = m_reasonsForMatchNotOk[i];
155 if (cnt > 0)
156 msg(MSG::INFO) << " " << std::left << std::setw(width) << TrackSegmentMatchResult::reasonString(reason) << std::right
157 << ": " << cnt << endmsg;
158 }
159 msg(MSG::INFO) << " Reasons for match successes:" << endmsg;
160 for (unsigned int i = 0; i < nReasons; ++i) {
161 int cnt = m_reasonsForMatchOk[i];
163 if (cnt > 0)
164 msg(MSG::INFO) << " " << std::left << std::setw(width) << TrackSegmentMatchResult::reasonString(reason) << std::right
165 << ": " << cnt << endmsg;
166 }
167
168 return StatusCode::SUCCESS;
169 }
170
171 bool MooCandidateMatchingTool::match(const EventContext& ctx, const MuPatSegment& entry1, const MuPatSegment& entry2, bool useTightCuts) const {
173
174 // same segments should never be matched!
175 if (&entry1 == &entry2) {
176 ATH_MSG_DEBUG("Matching segment with itself: " << entry1.name << ". Should not happen!. Returning false.");
177 return false;
178 }
179
180 // check whether SL overlap => same station index, just one station
181 bool isSLOverlap = false;
182 if (entry1.stations().size() == 1 && entry2.stations().size() == 1 && entry1.stations().count(*entry2.stations().begin()))
183 isSLOverlap = true;
184 if (isSLOverlap) {
185 ATH_MSG_DEBUG("Small/large overlap");
186 // don't combine CSC and MDT segments
187 if (entry1.isMdt != entry2.isMdt) {
188 ATH_MSG_DEBUG(" mdt/csc mix ignored");
189 return false;
190 }
191
192 if (!areInNeighbouringChambers(entry1, entry2)) {
193 ATH_MSG_DEBUG(" not in neighbouring chambers");
194 return false;
195 }
196
197 if (!checkSegmentDistance(entry1, entry2)) {
198 ATH_MSG_DEBUG(" distance between segments too large");
199 return false;
200 }
201
202 // check whether there are hits in the same chamber layer
203 std::vector<MuonStationIndex::ChIndex> intersection;
204 std::set_intersection(entry1.chambers().begin(), entry1.chambers().end(), entry2.chambers().begin(), entry2.chambers().end(),
205 std::back_inserter(intersection));
206
207 if (!intersection.empty()) {
208 ATH_MSG_DEBUG(" Segments are in the same chamber ");
209 return false;
210 }
211
212 if (m_idHelperSvc->issTgc(*entry1.chamberIds().begin()) || m_idHelperSvc->isMM(*entry1.chamberIds().begin())) { return true; }
213 }
214
215 ATH_MSG_VERBOSE("Matching segments: " << entry1.name << " and " << entry2.name);
216
217 if (useTightCuts) ++m_segmentMatchesTight;
218
219 if (m_requireSameSide && !sameSide(entry1, entry2, m_requireSameSide)) {
221 return false;
222 } else {
224 }
225
226 // call segment matching tool
227 bool match = true;
228 if (useTightCuts) {
229 match = m_segmentMatchingToolTight->match(ctx, *entry1.segment, *entry2.segment);
230 } else {
231 match = m_segmentMatchingTool->match(ctx, *entry1.segment, *entry2.segment);
232 }
233 if (match) {
235 if (useTightCuts) ++m_goodSegmentMatchesTight;
236 }
237
238 return match;
239 }
240
241 bool MooCandidateMatchingTool::match(const EventContext& ctx, const Trk::Track& track, const MuonSegment& segment, bool useTightCuts) const {
242 ATH_MSG_DEBUG("Match track/segment: useTightCuts " << useTightCuts);
243 // convert segment and track
244 std::unique_ptr<Trk::Track> inTrack = std::make_unique<Trk::Track>(track);
245 std::unique_ptr<MuPatTrack> candidate = m_candidateTool->createCandidate(inTrack);
246 if (!candidate) {
247 ATH_MSG_VERBOSE("Failed to create track candidate");
248 return false;
249 }
250 std::unique_ptr<MuPatSegment> segInfo(m_candidateTool->createSegInfo(ctx, segment));
251 if (!segInfo) {
252 ATH_MSG_VERBOSE("Failed to create segment candidate");
253 return false;
254 }
255
256 // call match
257 const bool ok = match(ctx, *candidate, *segInfo, useTightCuts);
258 ATH_MSG_DEBUG("Match track/segment: result " << ok);
259 // return result
260 return ok;
261 }
262
263 bool MooCandidateMatchingTool::match(const EventContext& ctx, const MuPatTrack& entry1, const MuPatSegment& entry2, bool useTightCuts) const {
265 if (useTightCuts) ++m_segmentTrackMatchesTight;
266
267 ATH_MSG_VERBOSE("Matching track: " << entry1.segmentNames() << " with segment: " << entry2.name);
268
269 if (m_requireSameSide && !sameSide(entry1, entry2, m_requireSameSide)) {
270
272 return false;
273 } else {
275 }
276
277 // pre-matching using segment-segment matching
278 // 0=no segments match,1=any segment match,2=all segment match
279
280 // First pass filtering: call segment matching tool for all segment on candidate
281 bool haveMatch = true;
283 bool haveAllMatch = true;
284 bool haveAnyMatch = false;
285 const std::vector<MuPatSegment*>& segments = entry1.segments();
286 for (const MuPatSegment* segment : segments) {
287 if (!match(ctx, *segment, entry2, false)) {
288 haveAllMatch = false;
289 } else {
290 haveAnyMatch = true;
291 }
292 }
294 haveMatch = haveAnyMatch;
295 } else if (m_trackSegmentPreMatchingStrategy == 2) {
296 haveMatch = haveAllMatch;
297 }
298
299 if (!haveMatch) {
300 ATH_MSG_VERBOSE("track-segment match: -> Failed in comparing segments on track");
301
303 return false;
304 }
305 }
306
309 calculateTrackSegmentMatchResult(ctx, entry1, entry2, info);
310 TrackSegmentMatchCuts cuts = getMatchingCuts(entry1, entry2, useTightCuts);
311 haveMatch = applyTrackSegmentCuts(ctx, info, cuts);
312 // update counters
313 if (haveMatch) {
314 ++m_reasonsForMatchOk[info.reason];
315 } else {
316 ++m_reasonsForMatchNotOk[info.reason];
317 }
318 }
319
320 if (haveMatch) {
322 if (useTightCuts) ++m_goodSegmentTrackMatchesTight;
323 }
324
325 return haveMatch;
326 }
327
329 bool useTightCuts) const {
331 cuts.useTightCuts = useTightCuts;
332 cuts.posXCut = m_matchPosXCut;
333 cuts.posYCut = m_matchPosYCut;
334 cuts.posXPullCut = m_matchPosPullCut;
335 cuts.posYPullCut = m_matchPosPullCut;
336 cuts.angleXCut = m_matchAngXCut;
337 cuts.angleYCut = m_matchAngYCut;
338 cuts.angleXPullCut = m_matchAngXPullCut;
339 cuts.angleYPullCut = m_matchAngYPullCut;
340 if (useTightCuts) {
341 cuts.matchChiSquaredCut = m_matchChiSquaredCutTight;
342 } else {
343 cuts.matchChiSquaredCut = m_matchChiSquaredCut;
344 }
345
346 cuts.cutOnMatchChiSquared = true;
349 // CSC
350 cuts.cutOnPosX = true;
351 cuts.cutOnPosY = true;
352 cuts.cutOnPosXPull = true;
353 cuts.cutOnPosYPull = true;
354 cuts.cutOnAngleX = true;
355 cuts.cutOnAngleY = true;
356 cuts.cutOnAngleXPull = true;
357 cuts.cutOnAngleYPull = true;
358 } else { // ! containsChamber(CSS || CSL)
359 // MDT
360 cuts.cutOnPosX = false;
361 cuts.cutOnPosY = true;
362 cuts.cutOnPosXPull = false;
363 cuts.cutOnPosYPull = true;
364 cuts.cutOnAngleX = false;
365 cuts.cutOnAngleY = true;
366 cuts.cutOnAngleXPull = false;
367 cuts.cutOnAngleYPull = true;
368 }
369
370 if (cuts.posXCut == 0.0) cuts.cutOnPosX = false;
371 if (cuts.posYCut == 0.0) cuts.cutOnPosY = false;
372 if (cuts.angleXCut == 0.0) cuts.cutOnAngleX = false;
373 if (cuts.angleYCut == 0.0) cuts.cutOnAngleY = false;
374 if (cuts.posXPullCut == 0.0) cuts.cutOnPosXPull = false;
375 if (cuts.posYPullCut == 0.0) cuts.cutOnPosYPull = false;
376 if (cuts.angleXPullCut == 0.0) cuts.cutOnAngleXPull = false;
377 if (cuts.angleYPullCut == 0.0) cuts.cutOnAngleYPull = false;
378 if (cuts.matchChiSquaredCut == 0.0) cuts.cutOnMatchChiSquared = false;
379
380 return cuts;
381 }
382
384 if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << MSG::DEBUG << "track segment match:";
385
387 // for tracks that have no momentum, but need a curved match
388 // fall-back to segment matching with the closest segment
389 MuPatSegment* closestSegment = nullptr;
390 double closestSegmentDist = 1E9;
391 std::vector<MuPatSegment*>::const_iterator itS = info.MCTBTrack->segments().begin(), itS_end = info.MCTBTrack->segments().end();
392 for (; itS != itS_end; ++itS) {
393 // calculate distance along the direction of the segment on the track
394 double dist =
395 (info.MCTBSegment->entryPars().position() - (*itS)->entryPars().position()).dot((*itS)->entryPars().momentum().unit());
396 // store closest distance
397 if (std::abs(dist) < std::abs(closestSegmentDist)) {
398 closestSegmentDist = dist;
399 closestSegment = *itS;
400 }
401 }
402
403 if (!closestSegment) {
405 info.matchOK = true;
406 } else { // closestSegment
407 // call segment matching tool
408 if (cuts.useTightCuts) {
409 info.matchOK = m_segmentMatchingToolTight->match(ctx, *(closestSegment->segment), *(info.segment));
410 } else {
411 info.matchOK = m_segmentMatchingTool->match(ctx, *(closestSegment->segment), *(info.segment));
412 }
413 if (msgLvl(MSG::DEBUG)) {
414 if (info.matchOK) {
415 msg(MSG::DEBUG) << MSG::DEBUG << " -> Passed";
416 } else {
417 msg(MSG::DEBUG) << MSG::DEBUG << " -> Failed";
418 }
419 msg(MSG::DEBUG) << " segment match between segment-on-track "
420 << MuonStationIndex::chName(m_idHelperSvc->chamberIndex(info.trackChamberId)) << " and segment "
421 << MuonStationIndex::chName(m_idHelperSvc->chamberIndex(info.segmentChamberId)) << endmsg;
422 }
424 info.trackChamberId = closestSegment->chid;
425 } // else closestSegment
426
427 return info.matchOK;
428 } // if ( info.reason == TrackSegmentMatchResult::NoMomentumWithMagField )
429
430 if (msgLvl(MSG::VERBOSE)) {
431 msg(MSG::DEBUG) << MSG::VERBOSE << std::fixed;
432 if (info.havePosXError) {
433 double diff = info.localPosXDiff;
434 double totErr = std::sqrt(info.posXTotalErr2);
435 double pull = totErr != 0.0 ? diff / totErr : 0.0;
436 msg(MSG::DEBUG) << std::endl
437 << std::setprecision(3) << "deltaPosX =" << std::setw(8) << diff << " +- " << std::left << std::setw(8)
438 << totErr << std::right << std::setprecision(2) << " pull=" << std::setw(5) << pull << std::setprecision(3)
439 << " (align=" << m_alignErrorPosX << " meas=" << std::sqrt(info.posXMeasErr2)
440 << " pred=" << std::sqrt(info.posXPredErr2) << ")";
441 }
442 if (info.havePosYError) {
443 double diff = info.localPosYDiff;
444 double totErr = std::sqrt(info.posYTotalErr2);
445 double pull = totErr != 0.0 ? diff / totErr : 0.0;
446 msg(MSG::DEBUG) << std::endl
447 << std::setprecision(3) << "deltaPosY =" << std::setw(8) << diff << " +- " << std::left << std::setw(8)
448 << totErr << std::right << std::setprecision(2) << " pull=" << std::setw(5) << pull
449 << " (align=" << m_alignErrorPosY << " meas=" << std::sqrt(info.posYMeasErr2)
450 << " pred=" << std::sqrt(info.posYPredErr2) << ")";
451 }
452 if (info.haveAngleXError) {
453 double diff = info.localAngleXDiff;
454 double totErr = std::sqrt(info.angleXTotalErr2);
455 double pull = totErr != 0.0 ? diff / totErr : 0.0;
456 msg(MSG::DEBUG) << std::endl
457 << std::setprecision(5) << "deltaAngleX=" << std::setw(8) << diff << " +- " << std::left << std::setw(8)
458 << totErr << std::right << std::setprecision(2) << " pull=" << std::setw(5) << pull << std::setprecision(5)
459 << " (align=" << m_alignErrorAngleX << " meas=" << std::sqrt(info.angleXMeasErr2)
460 << " pred=" << std::sqrt(info.angleXPredErr2) << ")";
461 }
462 if (info.haveAngleYError) {
463 double diff = info.localAngleYDiff;
464 double totErr = std::sqrt(info.angleYTotalErr2);
465 double pull = totErr != 0.0 ? diff / totErr : 0.0;
466 msg(MSG::DEBUG) << std::endl
467 << std::setprecision(5) << "deltaAngleY=" << std::setw(8) << diff << " +- " << std::left << std::setw(8)
468 << totErr << std::right << std::setprecision(2) << " pull=" << std::setw(5) << pull << std::setprecision(5)
469 << " (align=" << m_alignErrorAngleY << " meas=" << std::sqrt(info.angleYMeasErr2)
470 << " pred=" << std::sqrt(info.angleYPredErr2) << ")";
471 }
472
473 msg(MSG::DEBUG) << std::endl << std::setprecision(5) << "Difference vector:" << info.diffVector;
474 msg(MSG::DEBUG) << printCovCorr(info.measuredCovariance, "Measured") << printCovCorr(info.predictionCovariance, "Predicted")
475 << printCovCorr(info.totalCovariance, "Total") << "Match chi-squared: " << info.matchChiSquared
476 << " sqrt=" << std::sqrt(info.matchChiSquared);
477
478 // finish on new line
479 if (info.havePosXError || info.havePosYError || info.haveAngleXError || info.haveAngleYError) { msg(MSG::DEBUG) << std::endl; }
480 }
481
482 //
483 // Start checking all cuts
484 //
485 info.resetCuts();
486 //
487 // apply cut on positions
488 //
489 double scaledPosXErr2 = cuts.posXPullCut * cuts.posXPullCut * info.posXTotalErr2;
490
491 // cut on absolute X position
492 if (cuts.cutOnPosX && info.havePosX) {
493 double posXCut2 = cuts.posXCut * cuts.posXCut + scaledPosXErr2;
494 if (info.localPosXDiff * info.localPosXDiff > posXCut2) {
495 if (msgLvl(MSG::DEBUG)) {
496 msg(MSG::DEBUG) << MSG::DEBUG << " -> Failed "
497 << MuonStationIndex::chName(m_idHelperSvc->chamberIndex(info.segmentChamberId))
498 << " X position cut: " << info.localPosXDiff << " > " << std::sqrt(posXCut2) << endmsg;
499 }
500 info.setCutFailed(TrackSegmentMatchResult::PosXCut);
501 } else {
502 info.setCutPassed(TrackSegmentMatchResult::PosXCut);
503 }
504 }
505
506 double scaledPosYErr2 = cuts.posYPullCut * cuts.posYPullCut * info.posYTotalErr2;
507
508 // cut on absolute Y position
509 if (cuts.cutOnPosY && info.havePosY) {
510 double posYCut2 = cuts.posYCut * cuts.posYCut + scaledPosYErr2;
511 if (info.localPosYDiff * info.localPosYDiff > posYCut2) {
512 if (msgLvl(MSG::DEBUG)) {
513 msg(MSG::DEBUG) << MSG::DEBUG << " -> Failed "
514 << MuonStationIndex::chName((m_idHelperSvc->chamberIndex(info.segmentChamberId)))
515 << " Y position cut: " << info.localPosYDiff << " > " << std::sqrt(posYCut2) << endmsg;
516 }
517 info.setCutFailed(TrackSegmentMatchResult::PosYCut);
518 } else {
519 info.setCutPassed(TrackSegmentMatchResult::PosYCut);
520 }
521 }
522
523 // cut on X position pull
524 if (cuts.cutOnPosXPull && info.havePosX && info.posXTotalErr2 > 0.0) {
525 if (info.localPosXDiff * info.localPosXDiff > scaledPosXErr2) {
526 if (msgLvl(MSG::DEBUG)) {
527 double pull = info.localPosXDiff / std::sqrt(info.posXTotalErr2);
528 msg(MSG::DEBUG) << MSG::DEBUG << " -> Failed "
529 << MuonStationIndex::chName((m_idHelperSvc->chamberIndex(info.segmentChamberId)))
530 << " X position pull cut: |" << pull << "| > " << cuts.posXPullCut << endmsg;
531 }
532 info.setCutFailed(TrackSegmentMatchResult::PosXPullCut);
533 } else {
534 info.setCutPassed(TrackSegmentMatchResult::PosXPullCut);
535 }
536 }
537
538 // cut on Y position pull
539 if (cuts.cutOnPosYPull && info.havePosY && info.posYTotalErr2 > 0.0) {
540 if (info.localPosYDiff * info.localPosYDiff > scaledPosYErr2) {
541 if (msgLvl(MSG::DEBUG)) {
542 double pull = info.localPosYDiff / std::sqrt(info.posYTotalErr2);
543 msg(MSG::DEBUG) << MSG::DEBUG << " -> Failed "
544 << MuonStationIndex::chName((m_idHelperSvc->chamberIndex(info.segmentChamberId)))
545 << " Y position pull cut: |" << pull << "| > " << cuts.posYPullCut << endmsg;
546 }
547 info.setCutFailed(TrackSegmentMatchResult::PosYPullCut);
548 } else {
549 info.setCutPassed(TrackSegmentMatchResult::PosYPullCut);
550 }
551 }
552
553 //
554 // apply cut on angles
555 //
556 double scaledAngleXErr2 = cuts.angleXPullCut * cuts.angleXPullCut * info.angleXTotalErr2;
557
558 // cut on absolute X angle
559 if (cuts.cutOnAngleX && info.haveAngleX) {
560 double angleXCut2 = cuts.angleXCut * cuts.angleXCut + scaledAngleXErr2;
561 if (info.localAngleXDiff * info.localAngleXDiff > angleXCut2) {
562 if (msgLvl(MSG::DEBUG)) {
563 msg(MSG::DEBUG) << MSG::DEBUG << " -> Failed "
564 << MuonStationIndex::chName(m_idHelperSvc->chamberIndex(info.segmentChamberId))
565 << " X angle cut: " << info.localAngleXDiff << " > " << std::sqrt(angleXCut2) << endmsg;
566 }
567 info.setCutFailed(TrackSegmentMatchResult::AngXCut);
568 } else {
569 info.setCutPassed(TrackSegmentMatchResult::AngXCut);
570 }
571 }
572
573 double scaledAngleYErr2 = cuts.angleYPullCut * cuts.angleYPullCut * info.angleYTotalErr2;
574
575 // cut on absolute Y angle
576 if (cuts.cutOnAngleY && info.haveAngleY) {
577 double angleYCut2 = cuts.angleYCut * cuts.angleYCut + scaledAngleYErr2;
578 if (info.localAngleYDiff * info.localAngleYDiff > angleYCut2) {
579 if (msgLvl(MSG::DEBUG)) {
580 msg(MSG::DEBUG) << MSG::DEBUG << " -> Failed "
581 << MuonStationIndex::chName((m_idHelperSvc->chamberIndex(info.segmentChamberId)))
582 << " Y angle cut: " << info.localAngleYDiff << " > " << std::sqrt(angleYCut2) << endmsg;
583 }
584 info.setCutFailed(TrackSegmentMatchResult::AngYCut);
585 } else {
586 info.setCutPassed(TrackSegmentMatchResult::AngYCut);
587 }
588 }
589
590 // cut on X angle pull
591 if (cuts.cutOnAngleXPull && info.haveAngleX && info.angleXTotalErr2 > 0.0) {
592 if (info.localAngleXDiff * info.localAngleXDiff > scaledAngleXErr2) {
593 if (msgLvl(MSG::DEBUG)) {
594 double pull = info.localAngleXDiff / std::sqrt(info.angleXTotalErr2);
595 msg(MSG::DEBUG) << MSG::DEBUG << " -> Failed "
596 << MuonStationIndex::chName((m_idHelperSvc->chamberIndex(info.segmentChamberId)))
597 << " X angle pull cut: |" << pull << "| > " << cuts.angleXPullCut << endmsg;
598 }
599 info.setCutFailed(TrackSegmentMatchResult::AngXPullCut);
600 } else {
601 info.setCutPassed(TrackSegmentMatchResult::AngXPullCut);
602 }
603 }
604
605 if (cuts.cutOnAngleYPull && info.haveAngleY && info.angleYTotalErr2 > 0.0) {
606 // cut on Y angle pull
607 if (info.localAngleYDiff * info.localAngleYDiff > scaledAngleYErr2) {
608 if (msgLvl(MSG::DEBUG)) {
609 double pull = info.localAngleYDiff / std::sqrt(info.angleYTotalErr2);
610 msg(MSG::DEBUG) << MSG::DEBUG << " -> Failed "
611 << MuonStationIndex::chName((m_idHelperSvc->chamberIndex(info.segmentChamberId)))
612 << " Y angle pull cut: |" << pull << "| > " << cuts.angleYPullCut << endmsg;
613 }
614 info.setCutFailed(TrackSegmentMatchResult::AngYPullCut);
615 } else {
616 info.setCutPassed(TrackSegmentMatchResult::AngYPullCut);
617 }
618 }
619
620 //
621 // Cut on total chiSquared
622 //
623 if (cuts.cutOnMatchChiSquared && info.haveMatchChiSquared) {
624 // cut on matching chi-squared
625 if (info.matchChiSquared > cuts.matchChiSquaredCut) {
626 if (msgLvl(MSG::DEBUG)) {
627 msg(MSG::DEBUG) << MSG::DEBUG << " -> Failed "
628 << MuonStationIndex::chName((m_idHelperSvc->chamberIndex(info.segmentChamberId)))
629 << " match chi-squared cut: " << info.matchChiSquared << " > " << cuts.matchChiSquaredCut << endmsg;
630 }
632 } else {
634 }
635 }
636
637 //
638 // Based on all cuts, decide to accept or reject
639 //
640
641 // match is OR of several matches
642 info.matchOK = false;
643 // if any cut was applied
644 if (info.appliedAnyCut()) {
645 if (info.passedAllCuts()) {
646 info.matchOK = true;
648 if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << MSG::DEBUG << " -> Passed all cuts";
649 } else if (info.passedCut(TrackSegmentMatchResult::MatchChiSquaredCut)) {
650 info.matchOK = true;
652 if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << MSG::DEBUG << " -> Passed match chi-quared cut";
653 } else if ((info.passedCut(TrackSegmentMatchResult::PosXCut) || info.passedCut(TrackSegmentMatchResult::PosXPullCut)) &&
654 (info.passedCut(TrackSegmentMatchResult::PosYCut) || info.passedCut(TrackSegmentMatchResult::PosYPullCut)) &&
655 (info.passedCut(TrackSegmentMatchResult::AngXCut) || info.passedCut(TrackSegmentMatchResult::AngXPullCut)) &&
656 (info.passedCut(TrackSegmentMatchResult::AngYCut) || info.passedCut(TrackSegmentMatchResult::AngYPullCut))) {
657 info.matchOK = true;
659 if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << MSG::DEBUG << " -> Passed cuts " << info.passedCutsString();
660 if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << MSG::DEBUG << " -> Failed cuts " << info.failedCutsString();
661 } else {
663 if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << MSG::DEBUG << " -> Failed cuts " << info.failedCutsString();
664 }
665 } else { // !info.appliedCuts
666 if (info.reason == TrackSegmentMatchResult::Unknown) {
668 if (msgLvl(MSG::DEBUG)) { msg(MSG::DEBUG) << MSG::DEBUG << ". No cuts applied"; } // if msgLvl(MSG::DEBUG)
669 } // if reason == Unknown
670 } // !appliedCuts
671
672 if (msgLvl(MSG::DEBUG)) {
673 if (info.matchOK) {
674 msg(MSG::DEBUG) << MSG::DEBUG << " -> Accepted because " << info.reasonString() << endmsg;
675 } else {
676 msg(MSG::DEBUG) << MSG::DEBUG << " -> Rejected because " << info.reasonString() << endmsg;
677 }
678 }
679
680 return info.matchOK;
681 } // applyTrackSegmentCuts()
682
683 void MooCandidateMatchingTool::calculateTrackSegmentMatchResult(const EventContext& ctx, const MuPatTrack& entry1, const MuPatSegment& entry2,
684 MooTrackSegmentMatchResult& info) const {
685 info.clear();
686 info.MCTBTrack = &entry1;
687 info.MCTBSegment = &entry2;
688 info.track = &entry1.track();
689 info.segment = entry2.segment;
690 info.segmentChamberId = entry2.chid;
691 if (!entry2.segment) {
692 ATH_MSG_WARNING(__FUNCTION__ << " entry2 does not have segment pointer.");
694 return;
695 }
696 int sector2 = m_idHelperSvc->sector(info.segmentChamberId);
697 bool hasStereoAngle = false;
698
699 // find closest track parameters
700 const Trk::TrackParameters* closestPars = nullptr;
701 double closestParsDist = 1E9;
702 const Trk::TrackParameters* closestMeasPars = nullptr;
703 double closestMeasParsDist = 1E9;
704 // const Trk::TrackStateOnSurface* closestTSOS = 0;
705 Identifier closestId;
706 double closestIdDist = 1E9;
707 bool trackHasPhi = true;
708
709 MagField::AtlasFieldCache fieldCache;
710 // Get field cache object
712 const AtlasFieldCacheCondObj* fieldCondObj{*readHandle};
713
714 if (fieldCondObj == nullptr) {
715 ATH_MSG_ERROR("Failed to retrieve AtlasFieldCacheCondObj with key " << m_fieldCacheCondObjInputKey.key());
716 return;
717 }
718 fieldCondObj->getInitializedCache(fieldCache);
719
720 // loop over TSOS
721 const Trk::TrackStates* tsoses = entry1.track().trackStateOnSurfaces();
723 Trk::TrackStates::const_iterator tit_end = tsoses->end();
724 for (; tit != tit_end; ++tit) {
725 const Trk::MeasurementBase* meas = (*tit)->measurementOnTrack();
726
727 // do not want to start from a pseudo-measurement
728 const Trk::PseudoMeasurementOnTrack* pseudo = dynamic_cast<const Trk::PseudoMeasurementOnTrack*>(meas);
729 if (pseudo) {
730 trackHasPhi = false;
731 continue;
732 }
733
734 // do not want to start from non-MS measurements
735 Identifier id;
736 if (meas) {
737 id = m_edmHelperSvc->getIdentifier(*meas);
738 if (id.is_valid()) {
739 if (!m_idHelperSvc->isMuon(id)) continue;
740 if (m_idHelperSvc->isMdt(id) && m_idHelperSvc->sector(id) != sector2) hasStereoAngle = true;
741 }
742 }
743
744 const Trk::TrackParameters* pars = (*tit)->trackParameters();
745 if (!pars) { continue; }
746
747 // calculate distance along the direction of the track
748 double dist = (entry2.entryPars().position() - pars->position()).dot(entry1.entryPars().momentum().unit());
749 // store closest distance
750 if (std::abs(dist) < std::abs(closestParsDist)) {
751 // closestTSOS = *tit;
752 closestParsDist = dist;
753 closestPars = pars;
754 if (pars->covariance()) {
755 closestMeasParsDist = dist;
756 closestMeasPars = pars;
757 }
758 }
759 // store closest MDT or CSC ID (for printout and performance analysis)
760 if (std::abs(dist) < std::abs(closestIdDist)) {
761 if (meas && id.is_valid() && m_idHelperSvc->isMuon(id) && (m_idHelperSvc->isMdt(id) || m_idHelperSvc->isCsc(id))) {
762 closestId = id;
763 closestIdDist = dist;
764 }
765 }
766 }
767
768 // update trackHasPhi in the cases where we do have enough phi constraints
769 if (entry1.phiHits().size() > 1) {
770 // calculate difference between hits
771 const Amg::Vector3D& gposFirstPhi = entry1.phiHits().front()->globalPosition();
772 const Amg::Vector3D& gposLastPhi = entry1.phiHits().back()->globalPosition();
773 Amg::Vector3D globalDistance = gposLastPhi - gposFirstPhi;
774
775 // calculate 'projective' distance
776 double distance = entry1.hasEndcap() ? fabs(globalDistance.z()) : globalDistance.perp();
777
778 if (distance > 500) trackHasPhi = true;
779 }
780
781 if (!closestPars) {
782 ATH_MSG_DEBUG("track-segment match: No closest track parameters found.");
784 return;
785 }
786
787 // set the identification of the first entry (the track - taking the closest point)
788 if (closestPars && closestId.is_valid()) { info.trackChamberId = m_idHelperSvc->chamberId(closestId); }
789
790 if (msgLvl(MSG::VERBOSE)) {
791 msg(MSG::DEBUG) << MSG::VERBOSE << "match Closest chamber: " << m_idHelperSvc->toStringChamber(info.trackChamberId)
792 << " Segment: " << m_idHelperSvc->toStringChamber(info.segmentChamberId);
793 const Trk::TrackParameters* tmpPars = nullptr;
794 if (closestMeasPars) tmpPars = closestMeasPars->covariance() ? closestMeasPars : nullptr;
795 if (tmpPars) {
796 msg(MSG::DEBUG) << std::endl
797 << "Closest measured track parameters: " << m_printer->print(*tmpPars) << std::endl
798 << Amg::toString(*tmpPars->covariance(), 10) << " distance=" << closestMeasParsDist;
799 }
800 if (!tmpPars || tmpPars != closestPars) {
801 msg(MSG::DEBUG) << std::endl
802 << "Closest track parameters : " << m_printer->print(*closestPars)
803 << " distance=" << closestParsDist;
804 }
805 msg(MSG::DEBUG) << endmsg;
806 }
807
808 bool straightLineMatch = !fieldCache.toroidOn();
809 if (hasStereoAngle && !trackHasPhi && (straightLineMatch || entry1.hasMomentum())) {
810 // can not do any extrapolation (not reliable)
812 return;
813 }
814
815 // if extrapolating within EM-EO, can use straight-line extrapolator even without momentum
816 if (!straightLineMatch && !entry1.hasMomentum() && info.trackChamberId.is_valid()) {
817 MuonStationIndex::StIndex trackStationIndex = m_idHelperSvc->stationIndex(info.trackChamberId);
818 MuonStationIndex::StIndex segmentStationIndex = entry2.stIndex;
819 if (((trackStationIndex == MuonStationIndex::StIndex::EM && segmentStationIndex == MuonStationIndex::StIndex::EO) ||
820 (trackStationIndex == MuonStationIndex::StIndex::EO && segmentStationIndex == MuonStationIndex::StIndex::EM)) &&
821 closestPars->position().z() * entry2.entryPars().position().z() > 0.0) {
822 straightLineMatch = true;
823 ATH_MSG_DEBUG("track in " << m_idHelperSvc->toStringStation(info.trackChamberId) << " and segment in "
824 << m_idHelperSvc->toStringStation(info.segmentChamberId)
825 << " => doing straight line extrapolation match");
826 }
827 }
828
829 //
830 // for tracks that have a momentum or have straight line match
831 //
832 if (straightLineMatch || entry1.hasMomentum()) {
833 // extrapolate to segment surface
834 std::unique_ptr<const Trk::TrackParameters> exPars;
835 const Trk::TrackParameters* exMeasPars = nullptr;
836 if (closestMeasPars) {
837 const Trk::TrackParameters* tmpPars = closestMeasPars->covariance() ? closestMeasPars : nullptr;
838
839 if (tmpPars) {
840 // Check sector+
841 if (!m_idHelperSvc->isMuon(info.trackChamberId)) {
843 return;
844 }
845 int trackSector = m_idHelperSvc->sector(info.trackChamberId);
846 int segmentSector = m_idHelperSvc->sector(info.segmentChamberId);
847 int sectorDiff = std::abs(trackSector - segmentSector);
848 if (sectorDiff > 1 && sectorDiff != 15) {
849 ATH_MSG_VERBOSE("track sector =" << trackSector << " segment sector =" << segmentSector
850 << " => not in neighbouring sectors ");
851
853 return;
854 }
855 // Check sector-
856
857 if (straightLineMatch && !entry1.hasMomentum()) {
858 exPars = m_atlasExtrapolator->extrapolateDirectly(ctx, *tmpPars, entry2.segment->associatedSurface(),
860 } else {
861 ATH_MSG_VERBOSE(" Extrapolating to other segment " << m_printer->print(*tmpPars) << std::endl
862 << Amg::toString(*tmpPars->covariance(), 10));
863 exPars = m_atlasExtrapolator->extrapolate(ctx, *tmpPars, entry2.segment->associatedSurface(), Trk::anyDirection,
864 false, Trk::muon);
865 }
866 }
867 if (!exPars) {
868 ATH_MSG_DEBUG("track-segment match: Failed to extrapolate measured track parameters\n"
869 << m_printer->print(*closestPars) << "\nfrom " << m_idHelperSvc->toStringChamber(info.trackChamberId)
870 << " to segment surface " << m_idHelperSvc->toStringChamber(info.segmentChamberId));
871 info.matchOK = false;
873 return;
874 }
875
876 exMeasPars = exPars->covariance() ? exPars.get() : nullptr;
877 if (!exMeasPars) {
878 ATH_MSG_DEBUG("track-segment match: Did not get measured track parameters from extrapolation\n"
879 << "\nfrom " << m_idHelperSvc->toStringChamber(info.trackChamberId) << " to segment surface "
880 << m_idHelperSvc->toStringChamber(info.segmentChamberId));
882 return;
883 }
884 ATH_MSG_VERBOSE(" ExMeasParameters " << exMeasPars << " " << m_printer->print(*exMeasPars) << std::endl
885 << Amg::toString(*exMeasPars->covariance(), 10));
886
887 } else {
888 // no closest measured parameters, take closest parameters
889
890 if (straightLineMatch && !entry1.hasMomentum()) {
891 exPars = m_atlasExtrapolator->extrapolateDirectly(ctx, *closestPars, entry2.segment->associatedSurface(),
893 } else {
894 exPars = m_atlasExtrapolator->extrapolate(ctx, *closestPars, entry2.segment->associatedSurface(), Trk::anyDirection,
895 false, Trk::muon);
896 }
897 if (!exPars) {
898 ATH_MSG_DEBUG("track-segment match: Failed to extrapolate track parameters without errors\n"
899 << m_printer->print(*closestPars) << "\nfrom " << m_idHelperSvc->toStringChamber(info.trackChamberId)
900 << " to segment surface " << m_idHelperSvc->toStringChamber(info.segmentChamberId));
901 info.matchOK = false;
903 return;
904 }
905 }
906
907 // get the available measured information by looking at the errors
908 // check measurement errors
909 const Amg::MatrixX& measErrors = entry2.segment->localCovariance();
910
911 double posXMeasErr2 = measErrors(Trk::locX, Trk::locX);
912 if (posXMeasErr2 <= 999.0) {
913 info.havePosX = true;
914 info.havePosXError = true;
915 info.posXMeasErr2 = posXMeasErr2;
916 info.posXTotalErr2 += posXMeasErr2;
917 }
918
919 double posYMeasErr2 = measErrors(Trk::locY, Trk::locY);
920 if (info.posYMeasErr2 <= 999.0) {
921 info.havePosY = true;
922 info.havePosYError = true;
923 info.posYMeasErr2 = posYMeasErr2;
924 info.posYTotalErr2 += posYMeasErr2;
925 }
926 double phiMeasErr2 = measErrors(Trk::phi, Trk::phi);
927 double thetaMeasErr2 = measErrors(Trk::theta, Trk::theta);
928 if (phiMeasErr2 <= 999.0) {
929 info.haveAngleX = true;
930 info.haveAngleXError = true;
931 info.angleXMeasErr2 = phiMeasErr2;
932 info.angleXTotalErr2 += phiMeasErr2;
933 }
934 if (thetaMeasErr2 <= 999.0) {
935 info.haveAngleY = true;
936 info.haveAngleYError = true;
937 info.angleYMeasErr2 = thetaMeasErr2;
938 info.angleYTotalErr2 += thetaMeasErr2;
939 }
940
941 // require extrapolation errors to enable use of errors
942 if (!exMeasPars) {
943 info.haveAngleXError = false;
944 info.haveAngleYError = false;
945 info.havePosXError = false;
946 info.havePosYError = false;
947 }
948
949 // calculate position difference
950 info.localPosXDiff = exPars->parameters()[Trk::locX] - entry2.segment->localParameters()[Trk::locX];
951 info.localPosYDiff = exPars->parameters()[Trk::locY] - entry2.segment->localParameters()[Trk::locY];
952
953 // calculate angle difference
954 Trk::LocalDirection locDirEx;
955 entry2.segment->associatedSurface().globalToLocalDirection(exPars->momentum(), locDirEx);
956
957 const Trk::LocalDirection& locDirSeg = entry2.segment->localDirection();
958
959 // angular residuals
960 info.localAngleXDiff = phi_diff(locDirEx.angleXZ() - locDirSeg.angleXZ());
961 info.localAngleYDiff = theta_diff(locDirEx.angleYZ() - locDirSeg.angleYZ());
962
963 AmgSymMatrix(5) localPredCovar;
964 localPredCovar.setIdentity();
965 // only calculate if needed
966 if (info.haveAngleXError || info.haveAngleYError || info.havePosXError || info.havePosYError) {
967 // Predicted angle errors are on global phi and theta. Need to convert to errors on local angles
968 Trk::JacobianPhiThetaLocalAngles globalToLocalPredAnglesJacobian(
969 exMeasPars->parameters()[Trk::phi], exMeasPars->parameters()[Trk::theta],
970 exMeasPars->associatedSurface().transform().rotation().inverse());
971
972 // make the Jacobian to convert all in one go from global to local
973 // so that the correlations are calculated correctly
974 AmgSymMatrix(5) globalToLocalPredJacobian;
975 globalToLocalPredJacobian.setIdentity();
976 globalToLocalPredJacobian(Trk::locX, Trk::locX) = 1.0;
977 globalToLocalPredJacobian(Trk::locY, Trk::locY) = 1.0;
978 globalToLocalPredJacobian(Trk::phi, Trk::phi) = globalToLocalPredAnglesJacobian(0, 0);
979 globalToLocalPredJacobian(Trk::theta, Trk::theta) = globalToLocalPredAnglesJacobian(1, 1);
980 globalToLocalPredJacobian(Trk::theta, Trk::phi) =
981 globalToLocalPredAnglesJacobian(0, 1); // also fills (Trk::phi,Trk::theta)
982 globalToLocalPredJacobian(Trk::phi, Trk::theta) = globalToLocalPredJacobian(Trk::theta, Trk::phi);
983 globalToLocalPredJacobian(Trk::qOverP, Trk::qOverP) = 1.0;
984 const AmgSymMatrix(5)& globalPredCovar = *exMeasPars->covariance();
985 localPredCovar = globalPredCovar.similarity(globalToLocalPredJacobian);
986 }
987
988 if (info.haveAngleXError && info.haveAngleYError && info.havePosXError && info.havePosYError) {
989 // Full 4D info available: CSC segments and MDT small-large overlap
990 info.measuredCovariance = measErrors.block<4, 4>(0, 0); // sub(1,4); hope this is ok ....
991 info.predictionCovariance = localPredCovar.block<4, 4>(0, 0); // sub(1,4); hope this is ok ....
992 info.totalCovariance = info.measuredCovariance + info.predictionCovariance;
993
994 // add alignment errors
995 info.totalCovariance(Trk::locX, Trk::locX) += m_alignErrorPosX * m_alignErrorPosX;
996 info.totalCovariance(Trk::locY, Trk::locY) += m_alignErrorPosY * m_alignErrorPosY;
997 info.totalCovariance(Trk::phi, Trk::phi) += m_alignErrorAngleX * m_alignErrorAngleX;
999
1000 // fill difference vector
1001 Amg::VectorX diffVec(4);
1002 diffVec[Trk::locX] = exPars->parameters()[Trk::locX] - entry2.segment->localParameters()[Trk::locX];
1003 diffVec[Trk::locY] = exPars->parameters()[Trk::locY] - entry2.segment->localParameters()[Trk::locY];
1004 diffVec[Trk::phi] = exPars->parameters()[Trk::phi] - entry2.segment->localParameters()[Trk::phi];
1005 diffVec[Trk::theta] = exPars->parameters()[Trk::theta] - entry2.segment->localParameters()[Trk::theta];
1006 info.diffVector = diffVec;
1007
1008 // finally calculate the match chi-squared
1009 Amg::MatrixX weightMatrix = info.totalCovariance.inverse();
1010 info.matchChiSquared = info.diffVector.transpose() * weightMatrix * info.diffVector;
1011 info.haveMatchChiSquared = true;
1012
1013 // update separate angles (redunant with covar)
1014 info.posXPredErr2 = localPredCovar(Trk::locX, Trk::locX);
1015 info.posYPredErr2 = localPredCovar(Trk::locY, Trk::locY);
1016 info.angleXPredErr2 = localPredCovar(Trk::phi, Trk::phi);
1017 info.angleYPredErr2 = localPredCovar(Trk::theta, Trk::theta);
1018 // update total errors
1019 info.posXTotalErr2 += info.posXPredErr2;
1020 info.posYTotalErr2 += info.posYPredErr2;
1021 info.angleXTotalErr2 += info.angleXPredErr2;
1022 info.angleYTotalErr2 += info.angleYPredErr2;
1023 info.posXTotalErr2 += m_alignErrorPosX * m_alignErrorPosX;
1024 info.posYTotalErr2 += m_alignErrorPosY * m_alignErrorPosY;
1025 info.angleXTotalErr2 += m_alignErrorAngleX * m_alignErrorAngleX;
1026 info.angleYTotalErr2 += m_alignErrorAngleY * m_alignErrorAngleY;
1027
1028 } else if (info.haveAngleYError && info.havePosYError) {
1029 // 2D Y info available:
1030 // normal (non-overlap) MDT segments have no X nor phi(angleXZ) measurement, and give error on local angleYZ
1031
1032 // Y,angleYZ 2x2 sub-set of predicted covariance
1033 AmgSymMatrix(2) predCovar{AmgSymMatrix(2)::Zero()};
1034 predCovar(0, 0) = localPredCovar(Trk::locY, Trk::locY); // Y
1035 predCovar(1, 1) = localPredCovar(Trk::theta, Trk::theta); // angleYZ
1036 predCovar(1, 0) = localPredCovar(Trk::theta, Trk::locY); // also sets (0,1)
1037 predCovar(0, 1) = predCovar(1, 0);
1038 info.predictionCovariance = predCovar;
1039
1040 // Y,angleYZ 2x2 sub-set of measured covariance
1041 AmgSymMatrix(2) measCovar{AmgSymMatrix(2)::Zero()};
1042 measCovar.setIdentity();
1043 measCovar(0, 0) = measErrors(Trk::locY, Trk::locY);
1044 measCovar(1, 1) = measErrors(Trk::theta, Trk::theta);
1045 measCovar(1, 0) = measErrors(Trk::theta, Trk::locY);
1046 measCovar(0, 1) = measCovar(1, 0);
1047
1048 info.measuredCovariance = measCovar;
1049 info.totalCovariance = info.predictionCovariance + info.measuredCovariance;
1050 // add alignment errors
1051 info.totalCovariance(0, 0) += m_alignErrorPosY * m_alignErrorPosY;
1052 info.totalCovariance(1, 1) += m_alignErrorAngleY * m_alignErrorAngleY;
1053 if (std::abs(info.totalCovariance.determinant()) <
1054 std::numeric_limits<float>::epsilon()){
1056 return;
1057 }
1058 // now fill the difference vector
1059 Amg::VectorX diffVec(2);
1060 diffVec[0] = info.localPosYDiff;
1061 diffVec[1] = info.localAngleYDiff;
1062 info.diffVector = diffVec;
1063
1064 // finally calculate the match chi-squared
1065 Amg::MatrixX weightMatrix = info.totalCovariance.inverse();
1066 info.matchChiSquared = info.diffVector.transpose() * weightMatrix * info.diffVector;
1067 info.haveMatchChiSquared = true;
1068
1069 // fill all available information (redundant with covar)
1070 info.posXPredErr2 = localPredCovar(Trk::locX, Trk::locX);
1071 info.posYPredErr2 = localPredCovar(Trk::locY, Trk::locY);
1072 info.angleXPredErr2 = localPredCovar(Trk::phi, Trk::phi);
1073 info.angleYPredErr2 = localPredCovar(Trk::theta, Trk::theta);
1074 // only use Y/angleY
1075 info.posYTotalErr2 += info.posYPredErr2;
1076 info.angleYTotalErr2 += info.angleYPredErr2;
1077 info.posYTotalErr2 += m_alignErrorPosY * m_alignErrorPosY;
1078 info.angleYTotalErr2 += m_alignErrorAngleY * m_alignErrorAngleY;
1079
1080 } else {
1082 }
1083
1084 } else {
1086 //
1087 // Alternative method:
1088 // EM/EO -> EI
1089 // extrapolate (straight line) from EM/EO track and line to IP -> matching region
1090
1091 } // else !straighLineMatch && !entry1.hasMomemtum()
1092
1093 }
1094
1095 bool MooCandidateMatchingTool::sameSide(const MuPatSegment& entry1, const MuPatSegment& entry2, bool sameSideOfPerigee) const {
1096 ATH_MSG_VERBOSE("sameSide: MuPatSegment, MuPatSegment");
1097 return sameSide(entry1.entryPars().momentum().unit(),
1098 entry1.entryPars().position(),
1099 entry2.entryPars().position(), sameSideOfPerigee);
1100 }
1101
1102 bool MooCandidateMatchingTool::sameSide(const MuPatTrack& entry1, const MuPatSegment& entry2, bool sameSideOfPerigee) const {
1103 ATH_MSG_VERBOSE("sameSide: MuPatTrack, MuPatSegment");
1104 return sameSide(entry1.entryPars().momentum().unit(), entry1.entryPars().position(), entry2.entryPars().position(),
1105 sameSideOfPerigee);
1106 }
1107
1108 bool MooCandidateMatchingTool::sameSide(const MuPatTrack& entry1, const MuPatTrack& entry2, bool sameSideOfPerigee) const {
1109 ATH_MSG_VERBOSE("sameSide: MuPatTrack, MuPatTrack");
1110 return sameSide(entry1.entryPars().momentum().unit(), entry1.entryPars().position(), entry2.entryPars().position(),
1111 sameSideOfPerigee);
1112 }
1114 bool requireSameSideOfPerigee) const {
1115 // check if segments are on same side of the Perigee in the xy plane
1116 Amg::Vector3D dirxy{dir.x(),dir.y(), 0.};
1117 dirxy = dirxy.unit();
1118 double distFromPerigee1 = pos1.dot(dirxy);
1119 double distFromPerigee2 = pos2.dot(dirxy);
1120 bool sameSideOfPerigee = (distFromPerigee1 * distFromPerigee2 > 0.);
1121 bool same = sameSideOfPerigee;
1122
1123 // if one segment in each endcap, then consider on different side
1124 bool inOppositeEndcap = false;
1125 constexpr double etaEndcap = 1.1;
1126 double eta1 = pos1.eta();
1127 double eta2 = pos2.eta();
1128 if ((eta1 > +etaEndcap && eta2 < -etaEndcap) || (eta1 < -etaEndcap && eta2 > +etaEndcap)) {
1129 inOppositeEndcap = true;
1130 same = false;
1131 }
1132
1133 if (msgLvl(MSG::VERBOSE)) {
1134 msg(MSG::DEBUG) << MSG::VERBOSE << "sameSide: Require same side of Perigee: " << requireSameSideOfPerigee;
1135 double sign1 = pos1.y() < 0 ? -1. : 1.;
1136 double sign2 = pos2.y() < 0 ? -1. : 1.;
1137 msg(MSG::DEBUG) << " Direction " << dir << std::fixed << std::setprecision(0) << std::endl
1138 << " pos1: dist " << std::setw(6) << distFromPerigee1 << " r " << std::setw(6) << pos1.perp() * sign1
1139 << " (x,y,z)=(" << std::setw(5) << pos1.x() << "," << std::setw(5) << pos1.y() << "," << std::setw(5)
1140 << pos1.z() << ")" << std::endl
1141 << " pos2: dist " << std::setw(6) << distFromPerigee2 << " r " << std::setw(6) << pos2.perp() * sign2
1142 << " (x,y,z)=(" << std::setw(5) << pos2.x() << "," << std::setw(5) << pos2.y() << "," << std::setw(5)
1143 << pos2.z() << ")" << std::setprecision(6); // back to default
1144
1145 if (sameSideOfPerigee) {
1146 msg(MSG::DEBUG) << std::endl << " Same side of perigee.";
1147 } else {
1148 msg(MSG::DEBUG) << std::endl << " Other side of perigee.";
1149 }
1150 if (inOppositeEndcap) { msg(MSG::DEBUG) << " In opposite end-cap."; }
1151 }
1152
1153 // if segments are on the same side of the Perigee, they are also on the same side of Calo, so can return
1154 if (same) {
1155 if (msgLvl(MSG::VERBOSE)) msg(MSG::DEBUG) << " => Accepted" << endmsg;
1156 return true;
1157 }
1158
1159 // if requiring sameSideOfPerigee (stronger condition), then we are done here.
1160 if (requireSameSideOfPerigee) {
1161 if (msgLvl(MSG::VERBOSE)) msg(MSG::DEBUG) << " => Rejected" << endmsg;
1162 return false;
1163 }
1164 return true;
1165 }
1166
1167 bool MooCandidateMatchingTool::match(const EventContext& ctx, const MuPatCandidateBase& entry1, const MuPatSegment& entry2, bool useTightCuts) const {
1168 const MuPatSegment* seg = dynamic_cast<const MuPatSegment*>(&entry1);
1169 if (seg) return match(ctx, *seg, entry2, useTightCuts);
1170
1171 const MuPatTrack* track = dynamic_cast<const MuPatTrack*>(&entry1);
1172 if (track) return match(ctx, *track, entry2, useTightCuts);
1173
1174 return false;
1175 }
1176
1177 void MooCandidateMatchingTool::getIdentifierSet(const std::vector<const Trk::MeasurementBase*>& measurements,
1178 std::set<Identifier>& ids) {
1179 // loop over measurements and extract all identifiers
1180 std::vector<const Trk::MeasurementBase*>::const_iterator it = measurements.begin();
1181 std::vector<const Trk::MeasurementBase*>::const_iterator it_end = measurements.end();
1182 for (; it != it_end; ++it) {
1183 const Trk::RIO_OnTrack* rot = dynamic_cast<const Trk::RIO_OnTrack*>(*it);
1184 if (rot) {
1185 ids.insert(rot->identify());
1186 } else {
1187 const CompetingMuonClustersOnTrack* crot = dynamic_cast<const CompetingMuonClustersOnTrack*>(*it);
1188 if (crot) {
1189 const std::vector<const MuonClusterOnTrack*>& rots = crot->containedROTs();
1190 std::vector<const MuonClusterOnTrack*>::const_iterator rit = rots.begin();
1191 std::vector<const MuonClusterOnTrack*>::const_iterator rit_end = rots.end();
1192 for (; rit != rit_end; ++rit) ids.insert((*rit)->identify());
1193 }
1194 }
1195 }
1196 }
1197
1199 // check whether one of the two entries has no phi hits in which case return true
1200 if (entry1.phiHits().empty() || entry2.phiHits().empty()) return true;
1201
1202 std::set<Identifier> ids1;
1203 getIdentifierSet(entry1.phiHits(), ids1);
1204
1205 std::set<Identifier> ids2;
1206 getIdentifierSet(entry2.phiHits(), ids2);
1207
1208 std::vector<Identifier> intersection;
1209 std::set_intersection(ids1.begin(), ids1.end(), ids2.begin(), ids2.end(), std::back_inserter(intersection));
1210
1211 unsigned int intersectionSize = intersection.size();
1212 // require a full overlap between the two entries or that one of the two is a subset of the other
1213 if (intersectionSize == ids1.size() || intersectionSize == ids2.size()) return true;
1214
1215 // also accept if there is no overlap
1216 if (intersectionSize == 0) return true;
1217
1218 return false;
1219 }
1220
1222 DistanceToPars distToPars(&entry1.entryPars());
1223 double distance = distToPars(entry2.entryPars().position());
1224 if (std::abs(distance) > 5000.) {
1225 ATH_MSG_VERBOSE(" large distance between segments, not using segment " << distance);
1226 return false;
1227 }
1228 return true;
1229 }
1230
1232 Identifier chid1 = seg1.chid;
1233 Identifier chid2 = seg2.chid;
1234 if (msgLvl(MSG::VERBOSE)) {
1235 msg(MSG::VERBOSE) << "check if chambers are neighbours: " << m_idHelperSvc->toStringChamber(chid1) << " and "
1236 << m_idHelperSvc->toStringChamber(chid2) << ": ";
1237 }
1238 // if in same chamber, then OK
1239 if (chid1 == chid2) {
1240 if (msgLvl(MSG::VERBOSE)) msg(MSG::VERBOSE) << "in same chamber" << endmsg;
1241 return true;
1242 }
1243 // check in r
1244 if (seg1.stIndex != seg2.stIndex) {
1245 if (msgLvl(MSG::VERBOSE)) msg(MSG::VERBOSE) << "not in same station" << endmsg;
1246 return false;
1247 }
1248
1249 // check in phi
1250 int secDiff = std::abs(m_idHelperSvc->sector(chid1) - m_idHelperSvc->sector(chid2));
1251 if (secDiff > 1 && secDiff != 15) {
1252 if (msgLvl(MSG::VERBOSE))
1253 msg(MSG::VERBOSE) << "sec1=" << m_idHelperSvc->sector(chid1) << "sec2=" << m_idHelperSvc->sector(chid2)
1254 << " => not in neighbouring phi " << endmsg;
1255 return false;
1256 }
1257
1258 // check in eta
1259 if (seg1.isEndcap && seg2.isEndcap) {
1260 // both in endcap
1261 // endcap: can compare eta indices
1262 if (std::abs(m_idHelperSvc->stationEta(chid1) - m_idHelperSvc->stationEta(chid2)) > 1) {
1263 if (msgLvl(MSG::VERBOSE)) msg(MSG::VERBOSE) << "not in neighbouring eta" << endmsg;
1264 return false;
1265 }
1266 } else if (!seg1.isEndcap && !seg2.isEndcap) {
1267 // both in barrel
1268 const std::string& stationName1 =
1269 m_idHelperSvc->mdtIdHelper().stationNameString(m_idHelperSvc->mdtIdHelper().stationName(chid1));
1270 const std::string& stationName2 =
1271 m_idHelperSvc->mdtIdHelper().stationNameString(m_idHelperSvc->mdtIdHelper().stationName(chid2));
1272 std::string exceptions("MRFG");
1273 if (exceptions.find(stationName1[2]) == std::string::npos && exceptions.find(stationName2[2]) == std::string::npos) {
1274 // the normal case
1275 if (std::abs(m_idHelperSvc->stationEta(chid1) - m_idHelperSvc->stationEta(chid2)) > 1) {
1276 if (msgLvl(MSG::VERBOSE)) msg(MSG::VERBOSE) << "not in neighbouring eta " << endmsg;
1277 return false;
1278 }
1279 } else {
1280 // the exceptions: use geometrical information
1281 const std::set<const MuonGM::MuonReadoutElement*> roEls1 = m_candidateTool->readoutElements(seg1);
1282 const std::set<const MuonGM::MuonReadoutElement*> roEls2 = m_candidateTool->readoutElements(seg2);
1283 for (const MuonGM::MuonReadoutElement* read_ele1 : roEls1) {
1284 for (const MuonGM::MuonReadoutElement* read_ele2 : roEls2) {
1285 double distZ = std::abs(read_ele1->center().z() - read_ele2->center().z());
1286 // subtract sizes
1287 distZ -= 0.5 * (read_ele1->getZsize() + read_ele2->getZsize());
1288 if (msgLvl(MSG::VERBOSE)) {
1289 msg(MSG::VERBOSE) << std::endl
1290 << read_ele1->getStationType() << ": z=" << read_ele1->center().z() << "+-"
1291 << 0.5 * read_ele1->getZsize() << " " << read_ele2->getStationType()
1292 << ": z=" << read_ele2->center().z() << "+-" << 0.5 * read_ele2->getZsize() << " "
1293 << "distZ=" << distZ;
1294 }
1295 // allow some distance
1296 if (distZ > 100.0) {
1297 if (msgLvl(MSG::VERBOSE)) msg(MSG::VERBOSE) << " z-position too far apart" << endmsg;
1298 return false;
1299 }
1300 }
1301 }
1302 }
1303 } else {
1304 // don't mix barrel/endcap
1305 ATH_MSG_VERBOSE(__FILE__<<":"<<__LINE__<< "endcap/barrel mix");
1306 return false;
1307 }
1308
1309 ATH_MSG_VERBOSE(__FILE__<<":"<<__LINE__<< " Yes!");
1310 return true;
1311 }
1312} // namespace Muon
#define M_PI
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define AmgSymMatrix(dim)
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
const double width
#define x
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
bool msgLvl(const MSG::Level lvl) const
MsgStream & msg() const
void getInitializedCache(MagField::AtlasFieldCache &cache) const
get B field cache for evaluation as a function of 2-d or 3-d position.
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
const_iterator end() const noexcept
Return a const_iterator pointing past the end of the collection.
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
bool is_valid() const
Check if id is in a valid state.
Local cache for magnetic field (based on MagFieldServices/AtlasFieldSvcTLS.h)
Base class for the XxxReadoutElement, with Xxx = Mdt, Rpc, Tgc, Csc.
Class for competing MuonClusters, it extends the Trk::CompetingRIOsOnTrack base class.
const std::vector< const MuonClusterOnTrack * > & containedROTs() const
returns the vector of SCT_ClusterOnTrack objects .
bool checkSegmentDistance(const MuPatSegment &entry1, const MuPatSegment &entry2) const
evaluate distance between two segments, if too large return false (cut at 3000.).
Gaudi::Property< bool > m_doTrackSegmentMatching
virtual StatusCode finalize() override
finialize method, method taken from bass-class AlgTool
TrackSegmentMatchCuts getMatchingCuts(const MuPatTrack &entry1, const MuPatSegment &entry2, bool useTightCuts) const
bool sameSide(const MuPatSegment &entry1, const MuPatSegment &entry2, bool requireSameSideOfPerigee) const
check whether two segments are on the same side of the point of closest approach to the perigee of th...
double m_caloMatchZ
Z position of calo end-cap disks.
bool match(const EventContext &ctx, const MuPatSegment &entry1, const MuPatSegment &entry2, bool useTightCuts) const
match two segment entries
bool applyTrackSegmentCuts(const EventContext &ctx, MooTrackSegmentMatchResult &info, const TrackSegmentMatchCuts &cuts) const
static void getIdentifierSet(const std::vector< const Trk::MeasurementBase * > &measurements, std::set< Identifier > &ids)
extract Idenfitiers from a vector of measurements and copy them into a set
MooCandidateMatchingTool(const std::string &, const std::string &, const IInterface *)
default AlgTool constructor
Gaudi::Property< int > m_trackSegmentPreMatchingStrategy
bool areInNeighbouringChambers(const MuPatSegment &seg1, const MuPatSegment &seg2) const
return whether the 2 segments are in neighbouring chambers
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_fieldCacheCondObjInputKey
ToolHandle< IMuonSegmentMatchingTool > m_segmentMatchingTool
void calculateTrackSegmentMatchResult(const EventContext &ctx, const MuPatTrack &entry1, const MuPatSegment &entry2, MooTrackSegmentMatchResult &info) const
calculate the info needed for the matching decision
PublicToolHandle< MuonEDMPrinterTool > m_printer
ToolHandle< MuPatCandidateTool > m_candidateTool
std::atomic_ulong m_reasonsForMatchOk[TrackSegmentMatchResult::NumberOfReasons]
ServiceHandle< IMuonEDMHelperSvc > m_edmHelperSvc
ToolHandle< IMuonSegmentMatchingTool > m_segmentMatchingToolTight
virtual ~MooCandidateMatchingTool()
destructor
ToolHandle< Trk::IExtrapolator > m_atlasExtrapolator
static bool checkPhiHitConsistency(const MuPatCandidateBase &entry1, const MuPatCandidateBase &entry2)
evaluate overlap between phi hits of two entries.
std::atomic_ulong m_reasonsForMatchNotOk[TrackSegmentMatchResult::NumberOfReasons]
virtual StatusCode initialize() override
initialize method, method taken from bass-class AlgTool
std::atomic_ulong m_goodSegmentMatches
matching counters
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
bool m_requireSameSide
require entries to be on the same side of the Perigee or Calorimeter
track candidate entry object.
bool containsChamber(MuonStationIndex::ChIndex chIndex) const
returns whether the ChamberIndex is already contained in candidate
const std::set< Identifier > & chamberIds() const
returns set with contained chamber ids
const std::set< MuonStationIndex::StIndex > & stations() const
returns set with contained stationIndices
bool hasEndcap() const
returns whether the entry contains endcap hits
const std::set< MuonStationIndex::ChIndex > & chambers() const
returns set with contained chamberIndices
const MeasVec & phiHits() const
return all phi hits on the entry
segment candidate object.
const Trk::TrackParameters & entryPars() const
returns first track parameters
bool isMdt
true for MDT, false for CSC
const MuonSegment * segment
track candidate object.
Definition MuPatTrack.h:37
Trk::Track & track() const
access to track
Definition MuPatTrack.h:175
bool hasMomentum() const
returns whether canditate has a momentum measurement
std::string segmentNames() const
string containing the names of the segments on the candidate
const Trk::TrackParameters & entryPars() const
returns first track parameters
Definition MuPatTrack.h:177
const std::vector< MuPatSegment * > & segments() const
access to segments
Definition MuPatTrack.h:167
This is the common class for 3D segments used in the muon spectrometer.
virtual const Trk::PlaneSurface & associatedSurface() const override final
returns the surface for the local to global transformation
This jacobian transforms the polar and azimutal angle of a global momentum representation to a local...
represents the three-dimensional global direction with respect to a planar surface frame.
double angleXZ() const
access method for angle of local XZ projection
double angleYZ() const
access method for angle of local YZ projection
This class is the pure abstract base class for all fittable tracking measurements.
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.
void globalToLocalDirection(const Amg::Vector3D &glodir, Trk::LocalDirection &locdir) const
This method transforms the global direction to a local direction wrt the plane.
Class to handle pseudo-measurements in fitters and on track objects.
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
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
const Trk::TrackStates * trackStateOnSurfaces() const
return a pointer to a const DataVector of const TrackStateOnSurfaces.
std::vector< std::string > intersection(std::vector< std::string > &v1, std::vector< std::string > &v2)
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, 3, 1 > Vector3D
Eigen::Matrix< double, Eigen::Dynamic, 1 > VectorX
Dynamic Vector - dynamic allocation.
StIndex
enum to classify the different station layers in the muon spectrometer
const std::string & chName(ChIndex index)
convert ChIndex into a string
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
@ anyDirection
DataVector< const Trk::TrackStateOnSurface > TrackStates
@ locY
local cartesian
Definition ParamDefs.h:38
@ locX
Definition ParamDefs.h:37
@ theta
Definition ParamDefs.h:66
@ qOverP
perigee
Definition ParamDefs.h:67
@ phi
Definition ParamDefs.h:75
ParametersBase< TrackParametersDim, Charged > TrackParameters