ATLAS Offline Software
Loading...
Searching...
No Matches
MuonSegmentMatchingTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <cmath>
8#include <iostream>
9
11
12namespace Muon {
13
15
16MuonSegmentMatchingTool::MuonSegmentMatchingTool(const std::string& ty, const std::string& na, const IInterface* pa)
17 : base_class(ty, na, pa) {
18 declareProperty("UseCosmicsSettings", m_isCosmics = false, "Pick up settings for cosmics");
19 declareProperty("DoOverlapMatch", m_doOverlapMatch = true,
20 "Perform matching for segments in a small/large overlap");
21 declareProperty("DoStraightLineMatch", m_doStraightLineMatch = true,
22 "Perform matching for segments in regions without field");
23 declareProperty("DoCurvedMatch", m_doCurvedMatch = true, "Perform matching for segments in a field regions");
24 declareProperty("doThetaMatching", m_thetaMatch = false, "Pre-matching in theta");
25 declareProperty("doPhiMatching", m_phiMatch = false, "Pre-matching in phi");
26
27 declareProperty(
28 "OverlapMatchAngleDPhiCut", m_overlapMatchAngleDPhiCut = 0.15,
29 "Cut on the angular difference between the best phi and the one consistent with the chamber bounds");
30 declareProperty(
31 "OverlapMatchAngleDYZCut", m_overlapMatchAngleDYZCut = 0.05,
32 "Cut on the angular difference between the best phi and the one consistent with the chamber bounds");
33 declareProperty("OverlapMatchPositionCut", m_overlapMatchPositionCut = 100.,
34 "Cut on the distance of recalculated position to the tube edge");
35 declareProperty("OverlapMatchPositionResidualCut", m_overlapMatchPositionResidualCut = 30.,
36 "Cut on the segment position residual after recalculation of the paramters");
37 declareProperty("OverlapMatchAveragePhiHitPullCut", m_overlapMatchPhiHitPullCut = 20.,
38 "Cut on the average pull of the phi hits with the new segment parameters");
39
40 declareProperty("StraightLineMatchAngleCut", m_straightLineMatchAngleCut = 0.1,
41 "Cut on the angular difference between the extrapolated segment angle and reference");
42 declareProperty("StraightLineMatchPositionCut", m_straightLineMatchPositionCut = 200.,
43 "Cut on the distance of extrapolated segment position and reference");
44 declareProperty("MaxDistanceBetweenSegments", m_maxDistSegments = 5000.,
45 "If the two segments are further apart than this distance, they are considered to not match");
46
47 declareProperty("OnlySameSectorIfTight", m_onlySameSectorIfTight = true,
48 "Accept only segments that are in the same sector for tight matching");
49 declareProperty("TightSegmentMatching", m_useTightCuts = false,
50 "Use tight selection for busy event to suppress combinatorics and improve CPU");
51
52 declareProperty("DoMatchingCutsBIBM_S", m_matchingbibm_sphisec = 0.015,
53 "Cut on sumDeltaYZ, segments in BI and BM, small phi sec");
54 declareProperty("DoMatchingCutsBIBO_S", m_matchingbibo_sphisec = 0.015,
55 "Cut on sumDeltaYZ, segments in BI and BO, small phi sec");
56 declareProperty("DoMatchingCutsBMBO_S", m_matchingbmbo_sphisec = 0.015,
57 "Cut on sumDeltaYZ, segments in BM and BO, small phi sec");
58 declareProperty("DoMatchingCutsEIEM_S", m_matchingeiem_sphisec = 0.010 * 2,
59 "Cut on sumDeltaYZ, segments in EI and EM, small phi sec");
60 declareProperty("DoMatchingCutsEIEO_S", m_matchingeieo_sphisec = 0.020 * 2,
61 "Cut on sumDeltaYZ, segments in EI and EO, small phi sec");
62 declareProperty("DoMatchingCutsEMEO_S", m_matchingemeo_sphisec = 0.002,
63 "Cut on sumDeltaYZ, segments in EM and EO, small phi sec");
64 declareProperty("DoMatchingCutsBIBM_L", m_matchingbibm_lphisec = 0.005,
65 "Cut on sumDeltaYZ, segments in BI and BM, large phi sec");
66 declareProperty("DoMatchingCutsBIBO_L", m_matchingbibo_lphisec = 0.015,
67 "Cut on sumDeltaYZ, segments in BI and BO, large phi sec");
68 declareProperty("DoMatchingCutsBMBO_L", m_matchingbmbo_lphisec = 0.010,
69 "Cut on sumDeltaYZ, segments in BM and BO, large phi sec");
70 declareProperty("DoMatchingCutsEIEM_L", m_matchingeiem_lphisec = 0.015 * 2,
71 "Cut on sumDeltaYZ, segments in EI and EM, large phi sec");
72 declareProperty("DoMatchingCutsEIEO_L", m_matchingeieo_lphisec = 0.025 * 2,
73 "Cut on sumDeltaYZ, segments in EI and EO, large phi sec");
74 declareProperty("DoMatchingCutsEMEO_L", m_matchingemeo_lphisec = 0.002,
75 "Cut on sumDeltaYZ, segments in EM and EO, large phi sec");
76 declareProperty("UseEndcapExtrapolationMatching", m_useEndcapExtrapolationMatching = true);
77 declareProperty("DrExtrapolationRMS", m_drExtrapRMS = 10);
78 declareProperty("DThetaExtrapolationRMS", m_dthetaExtrapRMS = 0.01 * 2);
79 declareProperty("DrExtrapolationAlignementOffset", m_drExtrapAlignmentOffset = 50);
80}
81
82StatusCode
84{
85 ATH_CHECK(AthAlgTool::initialize());
86 ATH_CHECK(m_edmHelperSvc.retrieve());
87 ATH_CHECK(m_printer.retrieve());
88 ATH_CHECK(m_idHelperSvc.retrieve());
89 ATH_CHECK(m_pairMatchingTool.retrieve());
91 return StatusCode::SUCCESS;
92}
93
94StatusCode
96{
97 double goodOverlapMatchFraction =
98 m_overlapMatches != 0 ? (double)m_overlapMatchesGood / ((double)m_overlapMatches) : 0.;
99 ATH_MSG_INFO("Overlap matches: total " << std::setw(7) << m_overlapMatches << " good " << std::setw(7)
100 << m_overlapMatchesGood << " fraction " << goodOverlapMatchFraction);
101
102 double goodStraightLineMatchFraction =
104 ATH_MSG_INFO("StraightLine matches: total " << std::setw(7) << m_straightLineMatches << " good " << std::setw(7)
105 << m_straightLineMatchesGood << " fraction "
106 << goodStraightLineMatchFraction);
107
108 double goodCurvedMatchFraction =
109 m_curvedMatches != 0 ? (double)m_curvedMatchesGood / ((double)m_curvedMatches) : 0.;
110 ATH_MSG_INFO("Curved matches: total " << std::setw(7) << m_curvedMatches << " good " << std::setw(7)
111 << m_curvedMatchesGood << " fraction " << goodCurvedMatchFraction);
112
113 ATH_MSG_INFO("Segments sharing hits: total " << std::setw(7) << m_duplicateHitUses);
114
115
116 return StatusCode::SUCCESS;
117}
118bool
119MuonSegmentMatchingTool::match(const EventContext& ctx, const MuonSegment& seg1, const MuonSegment& seg2) const {
120
121 ATH_MSG_VERBOSE(" match: segments " << std::endl << m_printer->print(seg1) << std::endl << m_printer->print(seg2));
122
123 // get identifiers
124 Identifier chid1 = m_edmHelperSvc->chamberId(seg1);
125 Identifier chid2 = m_edmHelperSvc->chamberId(seg2);
126 if (chid1 == chid2) return false;
127
128 StIndex stIndex1 = m_idHelperSvc->stationIndex(chid1);
129 StIndex stIndex2 = m_idHelperSvc->stationIndex(chid2);
130
131 if (isSLMatch(chid1, chid2)) {
132 if (!m_idHelperSvc->isMdt(chid1) || !m_idHelperSvc->isMdt(chid2)) return false;
133 // if there is a stereo angle match using overlap matching tool
134
135 if (stIndex1 == stIndex2) {
136
137 if (hasStereoAngle(chid1, chid2)) {
138 if (!m_doOverlapMatch) return true;
139 const int eta1 = m_idHelperSvc->mdtIdHelper().stationEta(chid1);
140 const int eta2 = m_idHelperSvc->mdtIdHelper().stationEta(chid2);
141 const int phi1 = m_idHelperSvc->sector(chid1);
142 const int phi2 = m_idHelperSvc->sector(chid2);
143 // require that the two segments are close in eta AND are in adjecent sectors
144 if ( std::abs(eta1-eta2) <=1
145 && ( std::abs(phi1 - phi2) == 1 || (phi1 == 1 && phi2 == 16)
146 || (phi1 == 16 && phi2 == 1)))
147 {
148 return overlapMatch(ctx, seg1, seg2);
149 } else
150 return false;
151 }
152 }
153 if (!m_doStraightLineMatch) return true;
154
155 if (stIndex1 == stIndex2) return false;
156
157 return straightLineMatch(seg1, seg2);
158 }
159
160 // if we get here perform a curved matching
161 if (!m_doCurvedMatch) return true;
162 if (stIndex1 == stIndex2) return false;
163
164 return curvedMatch(seg1, seg2);
165}
166
167
168bool
170{
172
173 ATH_MSG_VERBOSE(" straight line match ");
174
175 // Suppress cavern background noise and combinatorics using both theta and phi matching
176 if (m_thetaMatch)
177 if (!suppressNoise(seg1, seg2, m_useTightCuts)) {
178 return false;
179 }
180
181 // Suppress cavern background noise and combinatorics using phi matching
182 if (m_phiMatch) {
183 if (!suppressNoisePhi(seg1, seg2, m_useTightCuts)) return false;
184 }
185
187 return true;
188}
189
190bool
192{
194
195 ATH_MSG_VERBOSE(" curved match ");
196
197 // Suppress cavern background noise and combinatorics using both theta and phi matching
198 if (m_thetaMatch)
199 if (!suppressNoise(seg1, seg2, m_useTightCuts)) {
200 return false;
201 }
202
203 // Suppress cavern background noise and combinatorics using phi matching
204 if (m_phiMatch) {
205 if (!suppressNoisePhi(seg1, seg2, m_useTightCuts)) return false;
206 }
207
209 return true;
210}
211
212bool
213MuonSegmentMatchingTool::overlapMatch(const EventContext& ctx, const MuonSegment& seg1, const MuonSegment& seg2) const
214{
216
217 ATH_MSG_VERBOSE(" overlap match ");
218
219 Identifier chid = m_edmHelperSvc->chamberId(seg1);
220
221 // check the distance between the two segments
222 const float segDist = (seg1.globalPosition() - seg2.globalPosition()).mag();
223 ATH_MSG_VERBOSE(" Distance between segments " << segDist);
224 if (m_isCosmics && segDist > m_minDistSegmentsCosmics) {
225 ATH_MSG_DEBUG(" Too far appart, accepting ");
226 return true;
227 }
228 if (segDist > m_maxDistSegments) return false;
229
230 if (!m_idHelperSvc->isMdt(chid)) {
231 ATH_MSG_DEBUG(" not a mdt segment " << m_idHelperSvc->toString(chid));
232 return true;
233 }
234
236
237 ATH_MSG_VERBOSE(result.toString());
238
239 if (!result.goodMatch()) {
240 ATH_MSG_DEBUG(" bad match ");
241 return false;
242 }
243
244 result.phiResult = m_overlapResolvingTool->bestPhiMatch(seg1, seg2);
245 if (std::abs(result.angularDifferencePhi) > m_overlapMatchAngleDPhiCut
246 || std::abs(result.phiResult.deltaYZ) > m_overlapMatchAngleDYZCut)
247 {
248 ATH_MSG_DEBUG(" failed angle cut: diff phi " << result.angularDifferencePhi << " deltaYZ "
249 << result.phiResult.deltaYZ);
250 return false;
251 }
252
253 if (std::abs(result.averagePhiHitPullSegment1) > m_overlapMatchPhiHitPullCut
254 || std::abs(result.averagePhiHitPullSegment2) > m_overlapMatchPhiHitPullCut)
255 {
256 ATH_MSG_DEBUG(" failed phi hit pull cut: seg1 " << result.averagePhiHitPullSegment1 << " seg2 "
257 << result.averagePhiHitPullSegment2);
258 return false;
259 }
260
261 if (!result.segmentResult1.inBounds(m_overlapMatchPositionCut)
262 || !result.segmentResult2.inBounds(m_overlapMatchPositionCut))
263 {
264 ATH_MSG_DEBUG(" failed position cut ");
265 return false;
266 }
267
268 if (std::abs(result.segmentResult1.positionResidual) > m_overlapMatchPositionResidualCut
269 || std::abs(result.segmentResult2.positionResidual) > m_overlapMatchPositionResidualCut)
270 {
271 ATH_MSG_DEBUG(" failed position residual cut: seg1 " << result.segmentResult1.positionResidual << " seg2 "
272 << result.segmentResult2.positionResidual);
273 return false;
274 }
275
277 return true;
278}
279
280bool
282{
283
284 // check whether there is field
285 if (!m_toroidOn) return true;
286
287 StIndex stIndex1 = m_idHelperSvc->stationIndex(chid1);
288 StIndex stIndex2 = m_idHelperSvc->stationIndex(chid2);
289
290 // check whether segments in same station
291 if (stIndex1 == stIndex2) return true;
292
293 // check whether segments in endcap EM/EO region
294 if ((stIndex1 == StIndex::EO && stIndex2 == StIndex::EM)||
295 (stIndex1 == StIndex::EM && stIndex2 == StIndex::EO))
296 return true;
297
298 // all other cases should be treated with curvature
299 return false;
300}
301
302bool
304{
305
306 // check whether same phi, else stereo angle (need correction for cosmic up-down tracks)
307 int phi1 = m_idHelperSvc->mdtIdHelper().stationPhi(id1);
308 int phi2 = m_idHelperSvc->mdtIdHelper().stationPhi(id2);
309
310 if (phi1 != phi2) return true;
311
312 // check whether there is a small/large overlap
313 bool isSmallChamber1 = m_idHelperSvc->isSmallChamber(id1);
314 bool isSmallChamber2 = m_idHelperSvc->isSmallChamber(id2);
315
316 return isSmallChamber1 != isSmallChamber2;
317}
318
319
320// DOMINIQUE:
321// Check that segment pairs is compatible with being produce within the calorimeter volume
322// Keep it loose to retain long live particles decaying in calo
323bool
324MuonSegmentMatchingTool::suppressNoise(const MuonSegment& seg1, const MuonSegment& seg2, const bool& useTightCuts) const
325{
326
327 // calculate matching variables
329
330 StIndex station_a = m_idHelperSvc->stationIndex(result.chid_a);
331 StIndex station_b = m_idHelperSvc->stationIndex(result.chid_b);
332
333 bool isEndcap_a = m_idHelperSvc->isEndcap(result.chid_a);
334 bool isCSC_a = m_idHelperSvc->isCsc(result.chid_a);
335 bool isBEE_a = station_a == StIndex::BE;
336
337 bool isEndcap_b = m_idHelperSvc->isEndcap(result.chid_b);
338 bool isCSC_b = m_idHelperSvc->isCsc(result.chid_b);
339 bool isBEE_b = station_b == StIndex::BE;
340
341
342
343
344 ATH_MSG_VERBOSE("SegmentPositionChange "
345 << " " << m_idHelperSvc->chamberNameString(result.chid_a) << " "
346 << m_idHelperSvc->chamberNameString(result.chid_b) << " " << result.phiSector_a << " "
347 << result.phiSector_b << " " << result.deltaTheta_a << " " << result.deltaTheta_b << " "
348 << result.deltaTheta << " " << result.angleAC << " " << result.angleBC << " " << result.angleAB);
349
350
351 ATH_MSG_VERBOSE("matching " << m_idHelperSvc->chamberNameString(result.chid_a) << " "
352 << m_idHelperSvc->chamberNameString(result.chid_b) << " phis " << result.phiSector_a
353 << " " << result.phiSector_b << " thetas " << result.deltaTheta_a << " "
354 << result.deltaTheta_b << " thetaSum " << result.deltaTheta << " tight cuts "
355 << useTightCuts);
356
357 // The difference between the segment direction in the inner and outer stations ~< 60 degrees in all cases
358 if (result.angleAB > 1.0) return false;
359
360
361 // First: loose selection
362 if (!useTightCuts) {
363 if (isCSC_a || isCSC_b) {
364 ATH_MSG_VERBOSE(" check CSC result ");
365 if (result.phiSector_a != result.phiSector_b) {
366 return false;
367 }
368 if ((isCSC_a && !isEndcap_b) || (isCSC_b && !isEndcap_a)) return false;
369 return endcapExtrapolationMatch(seg1, seg2, useTightCuts);
370 }
371 // BEE
372 else if (isBEE_a || isBEE_b)
373 {
374 ATH_MSG_VERBOSE(" check BEE result ");
375 return result.deltaTheta <= 0.300;
376 }
377 // Barrel/endcap overlap
378 else if (isEndcap_a != isEndcap_b)
379 {
380 ATH_MSG_VERBOSE(" check B-E result ");
381 return result.deltaTheta <= 0.300;
382 }
383 // Phi-sector overlap
384 else if (result.phiSector_a != result.phiSector_b)
385 {
386 ATH_MSG_VERBOSE(" check phiSector result ");
387 if (result.deltaTheta > 0.300) {
388 ATH_MSG_VERBOSE(" check phiSector reject ");
389 return false;
390 } else {
391 return true;
392 }
393 }
394 // Barrel inner to middle station
395 else if (station_a == StIndex::BI && station_b == StIndex::BM)
396 {
397 ATH_MSG_VERBOSE(" check BI BM result ");
398 if (result.phiSector_a % 2 == 0) {
399 return result.deltaTheta <= 6.67 * m_matchingbibm_sphisec;
400 } else if (result.phiSector_a % 2 == 1) {
401 return result.deltaTheta <= 6.67 * m_matchingbibm_lphisec;
402 }
403 }
404 // Barrel inner to outer station
405 else if (station_a == StIndex::BI && station_b == StIndex::BO)
406 {
407 ATH_MSG_VERBOSE(" check BI BO result ");
408 if (result.phiSector_a % 2 == 0) {
409 return result.deltaTheta <= 6.67 * m_matchingbibo_sphisec;
410 } else if (result.phiSector_a % 2 == 1) {
411 return result.deltaTheta <= 6.67 * m_matchingbibo_lphisec;
412 }
413 }
414
415 // Barrel middle to outer station
416 else if (station_a == StIndex::BM && station_b == StIndex::BO)
417 {
418 ATH_MSG_VERBOSE(" check BM BO result ");
419 if (result.phiSector_a % 2 == 0) {
420 return result.deltaTheta <= 6.67 * m_matchingbmbo_sphisec;
421 } else if (result.phiSector_a % 2 == 1) {
422 return result.deltaTheta <= 6.67 * m_matchingbmbo_lphisec;
423 }
424 }
425 // Endcap inner to middle station
426 else if (station_a == StIndex::EI && (station_b == StIndex::EM))
427 {
428 ATH_MSG_VERBOSE(" check EI EM result ");
429 if (result.phiSector_a % 2 == 0) {
430 if (result.deltaTheta > 6.67 * m_matchingeiem_sphisec) {
431 ATH_MSG_VERBOSE(" reject EI EM S result ");
432 return false;
433 } else {
434 return endcapExtrapolationMatch(seg1, seg2, useTightCuts);
435 }
436 } else if (result.phiSector_a % 2 == 1) {
437 if (result.deltaTheta > 6.67 * m_matchingeiem_lphisec) {
438 ATH_MSG_VERBOSE(" reject EI EM L result ");
439 return false;
440 } else {
441 return endcapExtrapolationMatch(seg1, seg2, useTightCuts);
442 }
443 }
444 }
445 // Endcap inner to outer station
446 else if (station_a == StIndex::EI && (station_b == StIndex::EO))
447 {
448 ATH_MSG_VERBOSE(" check EI EO result ");
449 if (result.phiSector_a % 2 == 0) {
450 if (result.deltaTheta > 6.67 * m_matchingeieo_sphisec) {
451 ATH_MSG_VERBOSE(" reject EI EO S result ");
452 return false;
453 } else {
454 return endcapExtrapolationMatch(seg1, seg2, useTightCuts);
455 }
456 } else if (result.phiSector_a % 2 == 1) {
457 if (result.deltaTheta > 6.67 * m_matchingeieo_lphisec) {
458 ATH_MSG_VERBOSE(" reject EI EO L result ");
459 return false;
460 } else {
461 return endcapExtrapolationMatch(seg1, seg2, useTightCuts);
462 }
463 }
464 }
465 // Endcap middle to outer station
466 else if (station_a == StIndex::EM && station_b == StIndex::EO)
467 {
468 // 5 mrad
469 ATH_MSG_VERBOSE(" check EM EO result ");
470 if (result.phiSector_a % 2 == 0) {
471 return result.deltaTheta <= 6.67 * m_matchingemeo_sphisec;
472 } else if (result.phiSector_a % 2 == 1) {
473 return result.deltaTheta <= 6.67 * m_matchingemeo_lphisec;
474 }
475 }
476
477 return true;
478 }
479
480 ATH_MSG_VERBOSE(" check further matching result ");
481
482 // Second: tight selection if only if requested
483 if (m_onlySameSectorIfTight && result.phiSector_a != result.phiSector_b) {
484 ATH_MSG_VERBOSE(" rejection pair as in different sector and using tight cuts");
485 return false;
486 }
487 if (isCSC_a || isCSC_b) {
488 if (result.phiSector_a != result.phiSector_b) {
489 return false;
490 } else {
491 if (result.deltaTheta > 0.100) {
492 return false;
493 } else {
494 if ((isCSC_a && !isEndcap_b) || (isCSC_b && !isEndcap_a)) return false;
495 return endcapExtrapolationMatch(seg1, seg2, useTightCuts);
496 }
497 }
498
499
500 }
501 // BEE
502 else if (isBEE_a || isBEE_b)
503 {
504 return result.deltaTheta <= 0.200;
505 }
506 // Looser cut for segment in two different phi sectors
507 else if (result.phiSector_a != result.phiSector_b)
508 {
509 return result.deltaTheta <= 0.150;
510 }
511 // Barrel/endcap overlap
512 else if (isEndcap_a != isEndcap_b)
513 {
514 return result.deltaTheta <= 0.150;
515 }
516 // Barrel inner to middle station
517 else if (station_a == StIndex::BI && station_b == StIndex::BM)
518 {
519 if (result.phiSector_a % 2 == 0) {
520 return result.deltaTheta <= m_matchingbibm_sphisec;
521 } else if (result.phiSector_a % 2 == 1) {
522 return result.deltaTheta <= m_matchingbibm_lphisec;
523 }
524 }
525 // Barrel inner to outer station
526 else if (station_a == StIndex::BI && station_b == StIndex::BO)
527 {
528 if (result.phiSector_a % 2 == 0) {
529 return result.deltaTheta <= m_matchingbibo_sphisec;
530 } else if (result.phiSector_a % 2 == 1) {
531 return result.deltaTheta <= m_matchingbibo_lphisec;
532 }
533 }
534 // Barrel middle to outer station
535 else if (station_a == StIndex::BM && station_b == StIndex::BO)
536 {
537 if (result.phiSector_a % 2 == 0) {
538 return result.deltaTheta <= m_matchingbmbo_sphisec;
539 } else if (result.phiSector_a % 2 == 1) {
540 return result.deltaTheta <= m_matchingbmbo_lphisec;
541 }
542 }
543 // Endcap inner to middle station
544 else if ((station_a == StIndex::EI || station_a == StIndex::BI)
545 && station_b == StIndex::EM)
546 {
547 if (result.phiSector_a % 2 == 0) {
548 if (result.deltaTheta > m_matchingeiem_sphisec) {
549 return false;
550 } else {
551 return endcapExtrapolationMatch(seg1, seg2, useTightCuts);
552 }
553 } else if (result.phiSector_a % 2 == 1) {
554 if (result.deltaTheta > m_matchingeiem_lphisec) {
555 return false;
556 } else {
557 return endcapExtrapolationMatch(seg1, seg2, useTightCuts);
558 }
559 }
560 }
561 // Endcap inner to outer station
562 else if (station_a == StIndex::EI && (station_b == StIndex::EO))
563 {
564 if (result.phiSector_a % 2 == 0) {
565 if (result.deltaTheta > m_matchingeieo_sphisec) {
566 return false;
567 } else {
568 return endcapExtrapolationMatch(seg1, seg2, useTightCuts);
569 }
570 } else if (result.phiSector_a % 2 == 1) {
571 if (result.deltaTheta > m_matchingeieo_lphisec) {
572 return false;
573 } else {
574 return endcapExtrapolationMatch(seg1, seg2, useTightCuts);
575 }
576 }
577 }
578 // Endcap middle to outer station
579 else if (station_a == StIndex::EM && station_b == StIndex::EO)
580 {
581 if (result.phiSector_a % 2 == 0) {
582 return result.deltaTheta <= m_matchingemeo_sphisec;
583 } else if (result.phiSector_a % 2 == 1) {
584 return result.deltaTheta <= m_matchingemeo_lphisec;
585 }
586 }
587
588 return true;
589} // if m_useLocalAngles
590
591bool
593 const bool& useTightCuts) const
594{
595 // calculate matching variables
597
598 StIndex station_a = m_idHelperSvc->stationIndex(result.chid_a);
599 StIndex station_b = m_idHelperSvc->stationIndex(result.chid_b);
600
601 bool isEndcap_a = m_idHelperSvc->isEndcap(result.chid_a);
602
603 bool isEndcap_b = m_idHelperSvc->isEndcap(result.chid_b);
604
605
606 ATH_MSG_VERBOSE("SegmentPositionChange Phi"
607 << " " << m_idHelperSvc->chamberNameString(result.chid_a) << " "
608 << m_idHelperSvc->chamberNameString(result.chid_b) << " deltaPhipos " << result.deltaPhipos
609 << " deltaPhidir " << result.deltaPhidir << " phiposerr_a " << result.phiposerr_a << " phiposerr_b "
610 << result.phiposerr_b << " phidirerr_a " << result.phidirerr_a << " phidirerr_b "
611 << result.phidirerr_b << " shorttube_a " << result.shorttube_a << " shorttube_b "
612 << result.shorttube_b);
613
614 // Keep segments only if they are in the same or adjacent phi sectors
615 if (result.phiSector_a != result.phiSector_b
616 && ((result.phiSector_a != 16 && result.phiSector_b != 1)
617 && (result.phiSector_a != 1 && result.phiSector_b != 16))
618 && (result.phiSector_a != (result.phiSector_b + 1) && result.phiSector_a != (result.phiSector_b - 1)))
619 return false;
620
621 // First: loose selection
622 if (!useTightCuts) {
623 // cuts on second coordinate
624 if (result.phiSector_a == result.phiSector_b) {
625 if (result.phiposerr_a < 10001.000 && result.phiposerr_b < 10001.000) {
626
627 if (!isEndcap_a && !isEndcap_b) {
628 return result.deltaPhipos <= 0.1;
629 }
630 if (isEndcap_a && isEndcap_b) {
631 // small sectors
632 if (result.phiSector_a % 2 == 0) {
633 return result.deltaPhipos <= 0.1;
634 }
635 // large sectors
636 if (result.phiSector_a % 2 == 1) {
637 return result.deltaPhipos <= 0.2;
638 }
639 }
640 }
641 }
642
643 if (result.phiSector_a != result.phiSector_b) {
644 if (result.phiposerr_a < 10001.000 && result.phiposerr_b < 10001.000) {
645 if (!isEndcap_a && !isEndcap_b) {
646 return result.deltaPhipos <= 0.1;
647 }
648 if (isEndcap_a && isEndcap_b) {
649 return result.deltaPhipos <= 0.2;
650 }
651 }
652 }
653
654 // cuts on distance to tube edge
655 // only if in a different phi sector
656 if (result.phiSector_a != result.phiSector_b) {
657 // measured inner segment
658 if (result.phiposerr_a < 10001.000) {
659 if (station_a == StIndex::BM && station_b == StIndex::BO) {
660 return result.shorttube_a <= 800;
661 }
662 if (station_a == StIndex::EI && station_b == StIndex::EM) {
663 // MM or STGC have result.shorttube = 99999.
664 return result.shorttube_a <= 3500 || result.shorttube_a == 99999.;
665 }
666 if (station_a == StIndex::EI && station_b == StIndex::EO) {
667 return result.shorttube_a <= 3500 || result.shorttube_a == 99999.;
668 }
669 if (station_a == StIndex::EM && station_b == StIndex::EO) {
670 return result.shorttube_a <= 800;
671 }
672 }
673 // measured outer segment
674 if (result.phiposerr_b < 10001.000) {
675 if (station_a == StIndex::BI && station_b == StIndex::BM) {
676 return result.shorttube_b <= 800;
677 }
678 if (station_a == StIndex::BI && station_b == StIndex::BO) {
679 return result.shorttube_b <= 800;
680 }
681 if (station_a == StIndex::BM && station_b == StIndex::BO) {
682 return result.shorttube_b <= 800;
683 }
684 if (station_a == StIndex::EI && station_b == StIndex::EM) {
685 return result.shorttube_b <= 1400;
686 }
687 }
688 }
689 return true;
690 }
691
692
693 // Second: tight selection if only if requested
694 // cuts on second coordinate
695 if (result.phiSector_a == result.phiSector_b) {
696 if (result.phiposerr_a < 10001.000 && result.phiposerr_b < 10001.000) {
697 if (!isEndcap_a && !isEndcap_b) {
698 return result.deltaPhipos <= 0.1;
699 }
700 if (isEndcap_a && isEndcap_b) {
701 // small sectors
702 if (result.phiSector_a % 2 == 0) {
703 return result.deltaPhipos <= 0.08;
704 }
705 // large sectors
706 if (result.phiSector_a % 2 == 1) {
707 return result.deltaPhipos <= 0.1;
708 }
709 }
710 }
711 }
712 // cuts on distance to tube edge
713 // only if in a different phi sector
714 if (result.phiSector_a != result.phiSector_b) {
715 if (result.phiposerr_a < 10001.000 && result.phiposerr_b < 10001.000) {
716 if (!isEndcap_a && !isEndcap_b) {
717 return result.deltaPhipos <= 0.05;
718 }
719 if (isEndcap_a && isEndcap_b) {
720 return result.deltaPhipos <= 0.1;
721 }
722 }
723
724
725 // measured inner segment
726 if (result.phiposerr_a < 10001.000) {
727 if (station_a == StIndex::BM && station_b == StIndex::BO) {
728 return result.shorttube_a <= 600;
729 }
730 if (station_a == StIndex::EI && station_b == StIndex::EM) {
731 return result.shorttube_a <= 3500 || result.shorttube_a == 99999.;
732 }
733 if (station_a == StIndex::EI && station_b == StIndex::EO) {
734 return result.shorttube_a <= 3500 || result.shorttube_a == 99999.;
735 }
736 if (station_a == StIndex::EM && station_b == StIndex::EO) {
737 return result.shorttube_a <= 500;
738 }
739 }
740 // measured outer segment
741 if (result.phiposerr_b < 10001.000) {
742 if (station_a == StIndex::BI && station_b == StIndex::BM) {
743 return result.shorttube_b <= 600;
744 }
745 if (station_a == StIndex::BI && station_b == StIndex::BO) {
746 return result.shorttube_b <= 700;
747 }
748 if (station_a == StIndex::BM && station_b == StIndex::BO) {
749 return result.shorttube_b <= 700;
750 }
751 if (station_a == StIndex::EI && station_b == StIndex::EM) {
752 return result.shorttube_b <= 700;
753 }
754 }
755
756 }
757 return true;
758} // if m_useLocalAngles
759
760
761bool
763 bool useTightCuts) const
764{
765
766 if (!m_useEndcapExtrapolationMatching) return true;
767
768 Identifier chid1 = m_edmHelperSvc->chamberId(seg1);
769 Identifier chid2 = m_edmHelperSvc->chamberId(seg2);
770 if (chid1 == chid2) return false;
771
772 StIndex stIndex1 = m_idHelperSvc->stationIndex(chid1);
773 StIndex stIndex2 = m_idHelperSvc->stationIndex(chid2);
774 if (stIndex1 == stIndex2) return false;
775
776 const MuonSegment* segInner = nullptr;
777 if (stIndex1 == StIndex::EI) segInner = &seg1;
778 if (stIndex2 == StIndex::EI) segInner = &seg2;
779
780 const MuonSegment* segOuter = nullptr;
781 if (stIndex1 == StIndex::EM || stIndex1 == StIndex::EO) segOuter = &seg1;
782 if (stIndex2 == StIndex::EM || stIndex2 == StIndex::EO) segOuter = &seg2;
783
784 if (!segInner || !segOuter) {
785 return false;
786 }
787 const Amg::Vector3D& pos1 = segOuter->globalPosition();
788 const Amg::Vector3D& dir1 = segOuter->globalDirection();
789 const Amg::Vector3D& pos2 = segInner->globalPosition();
790 const Amg::Vector3D& dir2 = segInner->globalDirection();
791
792 // extrapolate the first segment to the inner layer
793 double r_expected{0.}, theta_expected{0.}, rhoInv{0.};
794 simpleEndcapExtrapolate(pos1.x(), pos1.y(), pos1.z(), dir1.theta(), pos2.z(), r_expected, theta_expected, rhoInv);
795
796 if (rhoInv < 0) rhoInv *= -1.;
797 double dr = pos2.perp() - r_expected;
798 double dtheta = dir2.theta() - theta_expected;
799
800
801 double drCut = m_drExtrapRMS + 5.e6 * rhoInv;
802 if (useTightCuts)
803 drCut *= 2;
804 else
805 drCut *= 4;
806
807 if ((stIndex1 == StIndex::EM && stIndex2 == StIndex::BI)
808 || (stIndex1 == StIndex::BI && stIndex2 == StIndex::EM))
809 {
810 drCut += 3 * m_drExtrapAlignmentOffset;
811 } else {
813 }
814
815 double dthetaCut = m_dthetaExtrapRMS + 1.5e3 * rhoInv;
816 if (useTightCuts)
817 dthetaCut *= 2;
818 else
819 dthetaCut *= 4;
820
821 ATH_MSG_VERBOSE(" simple match " << m_printer->print(seg1) << std::endl
822 << " " << m_printer->print(seg2) << std::endl
823 << " dr " << dr << " cut " << drCut << " dtheta " << dtheta << " cut " << dthetaCut
824 << " rhoInv " << 1e6 * rhoInv);
825
826 if (std::abs(dr) > drCut) return false;
827 if (std::abs(dtheta) > dthetaCut) return false;
828 return true;
829}
830
831
832void
833MuonSegmentMatchingTool::simpleEndcapExtrapolate(double x_segment, double y_segment, double z_segment,
834 double theta_segment, double z_extrapolated, double& r_expected,
835 double& theta_expected, double& rhoInv) const
836{
837 //
838 // Endcap extrapolation with a parabolic track model
839 //
840 // In the region z = z start - z end of the Toroid one has:
841 // r_expected = z tan(theta) + (z - z start)*(z - z start)/ rho
842 //
843 // outside this region No field
844 //
845 // here z start = 6 000 z end = 10 000
846 // theta = direction at the vertex rho is the effective curvature
847 //
848 double z_start = 7000.;
849 double z_end = 12000.;
850
851 if (z_extrapolated < 0) z_start = -z_start;
852 if (z_extrapolated < 0) z_end = -z_end;
853
854 double r_segment = std::hypot(x_segment , y_segment);
855
856 if (std::abs(z_extrapolated) > std::abs(z_segment)) {
857 ATH_MSG_WARNING(" extrapolate outwards is not implemented for z " << z_extrapolated);
858 r_expected = 0;
859 theta_expected = 0.;
860 return;
861 }
862 if (std::abs(z_segment) < std::abs(z_end)) {
863 ATH_MSG_WARNING(" segment before end of Toroid: SL extrapolation is used implemented " << z_segment);
864 }
865
866 // use SL extrapolation to go to the z_end of the Toroid
867 const double tan_seg = std::tan(theta_segment);
868
869 double r_end = r_segment + (z_end - z_segment) * tan_seg;
870
871 double zgeo = (z_end - z_start) * (z_end - z_start) - 2 * z_end * (z_end - z_start);
872 rhoInv = (r_end - z_end * tan_seg) / zgeo;
873 double tantheta = tan_seg - 2 * (z_end - z_start) * rhoInv;
874 r_expected = z_extrapolated * tantheta + (z_extrapolated - z_start) * (z_extrapolated - z_start) * rhoInv;
875 //
876 // increase radius by 30% wrt straight line
877 //
878 double r_SL = r_segment + (z_extrapolated - z_segment) * tan_seg;
879 r_expected = r_expected + 0.3 * (r_expected - r_SL);
880 theta_expected = std::atan(tantheta + 2 * (z_extrapolated - z_start) * rhoInv);
881
882 if (tan_seg < 0 && theta_expected < 0) theta_expected += M_PI;
883 if (tan_seg > 0 && theta_expected < 0) theta_expected = -theta_expected;
884}
885
886
887} // namespace Muon
#define M_PI
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
HWIdentifier id2
ServiceHandle< Muon::IMuonEDMHelperSvc > m_edmHelperSvc
EDM Helper tool.
StatusCode finalize()
AlgTool finalize.
bool endcapExtrapolationMatch(const MuonSegment &seg1, const MuonSegment &seg2, bool useTightCuts) const
match an endcap middle or outer segment with an inner segment using a simple analytic extrapolation m...
double m_minDistSegmentsCosmics
cut on the minimum distance between the segments, if the distance is larger
StatusCode initialize()
AlgTool initilize.
bool straightLineMatch(const MuonSegment &seg1, const MuonSegment &seg2) const
perform straight line matching using SL extrapolation
bool overlapMatch(const EventContext &ctx, const MuonSegment &seg1, const MuonSegment &seg2) const
perform overlap matching
double m_maxDistSegments
cut on the maximum distance between the segments
bool suppressNoise(const MuonSegment &seg1, const MuonSegment &seg2, const bool &useTightCuts) const
Suppress noise from cavern background/pile up using basic cuts.
bool match(const EventContext &ctx, const MuonSegment &seg1, const MuonSegment &seg2) const
match two segments
void simpleEndcapExtrapolate(double x_segment, double y_segment, double z_segment, double theta_segment, double z_extrapolated, double &r_expected, double &theta_expected, double &rhoInv) const
extrapolate segment in middle or outer endcap station to inner layer assuming the particle came from ...
bool isSLMatch(const Identifier &chid1, const Identifier &chid2) const
check whether we should perform a straight line match
bool m_useTightCuts
only apply tight selection for busy combinations
bool m_onlySameSectorIfTight
reject all segments in different sectors if in tight matching
MuonSegmentMatchingTool(const std::string &, const std::string &, const IInterface *)
constructor
ToolHandle< Muon::IMuonSegmentInOverlapResolvingTool > m_overlapResolvingTool
matching tool to handle the overlaps
PublicToolHandle< Muon::MuonEDMPrinterTool > m_printer
EDM printer tool.
bool curvedMatch(const MuonSegment &seg1, const MuonSegment &seg2) const
perform curved matching
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
ToolHandle< Muon::IMuonSegmentPairMatchingTool > m_pairMatchingTool
matching tool to handle the pairs of segments
double m_overlapMatchPhiHitPullCut
cut on the average pull of the phi hits with the new segment parameters
double m_overlapMatchPositionResidualCut
cut on the position residual for the best position match
double m_overlapMatchAngleDYZCut
cut of the angular difference between phi from phi match and phi from positions
bool suppressNoisePhi(const MuonSegment &seg1, const MuonSegment &seg2, const bool &useTightCuts) const
Suppress noise from cavern background/pile up using basic cuts in phi.
bool hasStereoAngle(const Identifier &id1, const Identifier &id2) const
check whether the two segments have a stereo angle
double m_overlapMatchAngleDPhiCut
cut of the angular difference between phi from phi match and phi from positions
double m_overlapMatchPositionCut
cut on the distance of best position from the chamber bounds
This is the common class for 3D segments used in the muon spectrometer.
virtual const Amg::Vector3D & globalPosition() const override final
global position
Eigen::Matrix< double, 3, 1 > Vector3D
StIndex
enum to classify the different station layers in the muon spectrometer
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.