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;
36 inline double phi_diff(
double x) {
44 std::ostringstream oss;
58 MCTBSegment =
nullptr;
63 declareInterface<MooCandidateMatchingTool>(
this);
64 declareInterface<IMuonTrackSegmentMatchingTool>(
this);
67 "require entries to be on the same side of the Perigee or Calorimeter");
71 "Local X (phi) angle difference cut for track-segment matching. Disabled if 0");
73 "Local Y (theta) angle difference cut for track-segment matching. Disabled if 0");
75 "Local X (phi) angle difference pull cut for track-segment matching. Disabled if 0");
77 "Local Y (theta) angle difference pull cut for track-segment matching. Disabled if 0");
79 "Local X (2nd coord) position difference cut (mm) for track-segment matching. Disabled if 0");
81 "Local Y (precision) position difference cut (mm) for track-segment matching. Disabled if 0");
85 "Cut on the track-segment matching chi-squared in case a tight cut is requested");
109 return StatusCode::SUCCESS;
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)
125 <<
" fraction " << goodSegmentMatchesLoose * scaleLoose * sameScale <<
endmsg <<
" good tight " << std::setw(7)
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)
139 <<
" good loose " << std::setw(7) << goodSegmentTrackMatchesLoose <<
" fraction "
140 << goodSegmentTrackMatchesLoose * scaleTrackLoose * sameScaleTrack <<
endmsg <<
" good tight " << std::setw(7)
145 unsigned int width = 0;
146 for (
unsigned int i = 0;
i < nReasons; ++
i) {
151 msg(MSG::INFO) <<
" Reasons for match failures:" <<
endmsg;
152 for (
unsigned int i = 0;
i < nReasons; ++
i) {
159 msg(MSG::INFO) <<
" Reasons for match successes:" <<
endmsg;
160 for (
unsigned int i = 0;
i < nReasons; ++
i) {
168 return StatusCode::SUCCESS;
175 if (&entry1 == &entry2) {
176 ATH_MSG_DEBUG(
"Matching segment with itself: " << entry1.
name <<
". Should not happen!. Returning false.");
181 bool isSLOverlap =
false;
242 ATH_MSG_DEBUG(
"Match track/segment: useTightCuts " << useTightCuts);
244 std::unique_ptr<Trk::Track> inTrack = std::make_unique<Trk::Track>(
track);
245 std::unique_ptr<MuPatTrack> candidate =
m_candidateTool->createCandidate(inTrack);
257 const bool ok =
match(ctx, *candidate, *segInfo, useTightCuts);
281 bool haveMatch =
true;
283 bool haveAllMatch =
true;
284 bool haveAnyMatch =
false;
285 const std::vector<MuPatSegment*>& segments = entry1.
segments();
288 haveAllMatch =
false;
294 haveMatch = haveAnyMatch;
296 haveMatch = haveAllMatch;
300 ATH_MSG_VERBOSE(
"track-segment match: -> Failed in comparing segments on track");
329 bool useTightCuts)
const {
331 cuts.useTightCuts = useTightCuts;
346 cuts.cutOnMatchChiSquared =
true;
349 cuts.cutOnPosX =
true;
350 cuts.cutOnPosY =
true;
351 cuts.cutOnPosXPull =
true;
352 cuts.cutOnPosYPull =
true;
353 cuts.cutOnAngleX =
true;
354 cuts.cutOnAngleY =
true;
355 cuts.cutOnAngleXPull =
true;
356 cuts.cutOnAngleYPull =
true;
359 cuts.cutOnPosX =
false;
360 cuts.cutOnPosY =
true;
361 cuts.cutOnPosXPull =
false;
362 cuts.cutOnPosYPull =
true;
363 cuts.cutOnAngleX =
false;
364 cuts.cutOnAngleY =
true;
365 cuts.cutOnAngleXPull =
false;
366 cuts.cutOnAngleYPull =
true;
369 if (
cuts.posXCut == 0.0)
cuts.cutOnPosX =
false;
370 if (
cuts.posYCut == 0.0)
cuts.cutOnPosY =
false;
371 if (
cuts.angleXCut == 0.0)
cuts.cutOnAngleX =
false;
372 if (
cuts.angleYCut == 0.0)
cuts.cutOnAngleY =
false;
373 if (
cuts.posXPullCut == 0.0)
cuts.cutOnPosXPull =
false;
374 if (
cuts.posYPullCut == 0.0)
cuts.cutOnPosYPull =
false;
375 if (
cuts.angleXPullCut == 0.0)
cuts.cutOnAngleXPull =
false;
376 if (
cuts.angleYPullCut == 0.0)
cuts.cutOnAngleYPull =
false;
377 if (
cuts.matchChiSquaredCut == 0.0)
cuts.cutOnMatchChiSquared =
false;
389 double closestSegmentDist = 1E9;
390 std::vector<MuPatSegment*>::const_iterator itS =
info.MCTBTrack->segments().begin(), itS_end =
info.MCTBTrack->segments().end();
391 for (; itS != itS_end; ++itS) {
394 (
info.MCTBSegment->entryPars().position() - (*itS)->entryPars().position()).
dot((*itS)->entryPars().momentum().unit());
396 if (std::abs(dist) < std::abs(closestSegmentDist)) {
397 closestSegmentDist = dist;
398 closestSegment = *itS;
402 if (!closestSegment) {
407 if (
cuts.useTightCuts) {
418 msg(
MSG::DEBUG) <<
" segment match between segment-on-track "
423 info.trackChamberId = closestSegment->
chid;
431 if (
info.havePosXError) {
433 double totErr = std::sqrt(
info.posXTotalErr2);
434 double pull = totErr != 0.0 ?
diff / totErr : 0.0;
436 << std::setprecision(3) <<
"deltaPosX =" << std::setw(8) <<
diff <<
" +- " << std::left << std::setw(8)
437 << totErr << std::right << std::setprecision(2) <<
" pull=" << std::setw(5) <<
pull << std::setprecision(3)
439 <<
" pred=" << std::sqrt(
info.posXPredErr2) <<
")";
441 if (
info.havePosYError) {
443 double totErr = std::sqrt(
info.posYTotalErr2);
444 double pull = totErr != 0.0 ?
diff / totErr : 0.0;
446 << std::setprecision(3) <<
"deltaPosY =" << std::setw(8) <<
diff <<
" +- " << std::left << std::setw(8)
447 << totErr << std::right << std::setprecision(2) <<
" pull=" << std::setw(5) <<
pull
449 <<
" pred=" << std::sqrt(
info.posYPredErr2) <<
")";
451 if (
info.haveAngleXError) {
453 double totErr = std::sqrt(
info.angleXTotalErr2);
454 double pull = totErr != 0.0 ?
diff / totErr : 0.0;
456 << std::setprecision(5) <<
"deltaAngleX=" << std::setw(8) <<
diff <<
" +- " << std::left << std::setw(8)
457 << totErr << std::right << std::setprecision(2) <<
" pull=" << std::setw(5) <<
pull << std::setprecision(5)
459 <<
" pred=" << std::sqrt(
info.angleXPredErr2) <<
")";
461 if (
info.haveAngleYError) {
463 double totErr = std::sqrt(
info.angleYTotalErr2);
464 double pull = totErr != 0.0 ?
diff / totErr : 0.0;
466 << std::setprecision(5) <<
"deltaAngleY=" << std::setw(8) <<
diff <<
" +- " << std::left << std::setw(8)
467 << totErr << std::right << std::setprecision(2) <<
" pull=" << std::setw(5) <<
pull << std::setprecision(5)
469 <<
" pred=" << std::sqrt(
info.angleYPredErr2) <<
")";
472 msg(
MSG::DEBUG) << std::endl << std::setprecision(5) <<
"Difference vector:" <<
info.diffVector;
473 msg(
MSG::DEBUG) << printCovCorr(
info.measuredCovariance,
"Measured") << printCovCorr(
info.predictionCovariance,
"Predicted")
474 << printCovCorr(
info.totalCovariance,
"Total") <<
"Match chi-squared: " <<
info.matchChiSquared
475 <<
" sqrt=" << std::sqrt(
info.matchChiSquared);
488 double scaledPosXErr2 =
cuts.posXPullCut *
cuts.posXPullCut *
info.posXTotalErr2;
491 if (
cuts.cutOnPosX &&
info.havePosX) {
492 double posXCut2 =
cuts.posXCut *
cuts.posXCut + scaledPosXErr2;
493 if (
info.localPosXDiff *
info.localPosXDiff > posXCut2) {
497 <<
" X position cut: " <<
info.localPosXDiff <<
" > " << std::sqrt(posXCut2) <<
endmsg;
505 double scaledPosYErr2 =
cuts.posYPullCut *
cuts.posYPullCut *
info.posYTotalErr2;
508 if (
cuts.cutOnPosY &&
info.havePosY) {
509 double posYCut2 =
cuts.posYCut *
cuts.posYCut + scaledPosYErr2;
510 if (
info.localPosYDiff *
info.localPosYDiff > posYCut2) {
514 <<
" Y position cut: " <<
info.localPosYDiff <<
" > " << std::sqrt(posYCut2) <<
endmsg;
523 if (
cuts.cutOnPosXPull &&
info.havePosX &&
info.posXTotalErr2 > 0.0) {
524 if (
info.localPosXDiff *
info.localPosXDiff > scaledPosXErr2) {
526 double pull =
info.localPosXDiff / std::sqrt(
info.posXTotalErr2);
529 <<
" X position pull cut: |" <<
pull <<
"| > " <<
cuts.posXPullCut <<
endmsg;
538 if (
cuts.cutOnPosYPull &&
info.havePosY &&
info.posYTotalErr2 > 0.0) {
539 if (
info.localPosYDiff *
info.localPosYDiff > scaledPosYErr2) {
541 double pull =
info.localPosYDiff / std::sqrt(
info.posYTotalErr2);
544 <<
" Y position pull cut: |" <<
pull <<
"| > " <<
cuts.posYPullCut <<
endmsg;
555 double scaledAngleXErr2 =
cuts.angleXPullCut *
cuts.angleXPullCut *
info.angleXTotalErr2;
558 if (
cuts.cutOnAngleX &&
info.haveAngleX) {
559 double angleXCut2 =
cuts.angleXCut *
cuts.angleXCut + scaledAngleXErr2;
560 if (
info.localAngleXDiff *
info.localAngleXDiff > angleXCut2) {
564 <<
" X angle cut: " <<
info.localAngleXDiff <<
" > " << std::sqrt(angleXCut2) <<
endmsg;
572 double scaledAngleYErr2 =
cuts.angleYPullCut *
cuts.angleYPullCut *
info.angleYTotalErr2;
575 if (
cuts.cutOnAngleY &&
info.haveAngleY) {
576 double angleYCut2 =
cuts.angleYCut *
cuts.angleYCut + scaledAngleYErr2;
577 if (
info.localAngleYDiff *
info.localAngleYDiff > angleYCut2) {
581 <<
" Y angle cut: " <<
info.localAngleYDiff <<
" > " << std::sqrt(angleYCut2) <<
endmsg;
590 if (
cuts.cutOnAngleXPull &&
info.haveAngleX &&
info.angleXTotalErr2 > 0.0) {
591 if (
info.localAngleXDiff *
info.localAngleXDiff > scaledAngleXErr2) {
593 double pull =
info.localAngleXDiff / std::sqrt(
info.angleXTotalErr2);
596 <<
" X angle pull cut: |" <<
pull <<
"| > " <<
cuts.angleXPullCut <<
endmsg;
604 if (
cuts.cutOnAngleYPull &&
info.haveAngleY &&
info.angleYTotalErr2 > 0.0) {
606 if (
info.localAngleYDiff *
info.localAngleYDiff > scaledAngleYErr2) {
608 double pull =
info.localAngleYDiff / std::sqrt(
info.angleYTotalErr2);
611 <<
" Y angle pull cut: |" <<
pull <<
"| > " <<
cuts.angleYPullCut <<
endmsg;
622 if (
cuts.cutOnMatchChiSquared &&
info.haveMatchChiSquared) {
624 if (
info.matchChiSquared >
cuts.matchChiSquaredCut) {
628 <<
" match chi-squared cut: " <<
info.matchChiSquared <<
" > " <<
cuts.matchChiSquaredCut <<
endmsg;
641 info.matchOK =
false;
643 if (
info.appliedAnyCut()) {
644 if (
info.passedAllCuts()) {
685 info.MCTBTrack = &entry1;
686 info.MCTBSegment = &entry2;
689 info.segmentChamberId = entry2.
chid;
691 ATH_MSG_WARNING(__FUNCTION__ <<
" entry2 does not have segment pointer.");
696 bool hasStereoAngle =
false;
700 double closestParsDist = 1E9;
702 double closestMeasParsDist = 1E9;
705 double closestIdDist = 1E9;
706 bool trackHasPhi =
true;
713 if (fieldCondObj ==
nullptr) {
717 fieldCondObj->getInitializedCache(fieldCache);
723 for (;
tit != tit_end; ++
tit) {
744 if (!
pars) {
continue; }
749 if (std::abs(dist) < std::abs(closestParsDist)) {
751 closestParsDist = dist;
753 if (
pars->covariance()) {
754 closestMeasParsDist = dist;
755 closestMeasPars =
pars;
759 if (std::abs(dist) < std::abs(closestIdDist)) {
762 closestIdDist = dist;
768 if (entry1.
phiHits().size() > 1) {
775 double distance = entry1.
hasEndcap() ? fabs(globalDistance.z()) : globalDistance.perp();
777 if (
distance > 500) trackHasPhi =
true;
781 ATH_MSG_DEBUG(
"track-segment match: No closest track parameters found.");
793 if (closestMeasPars) tmpPars = closestMeasPars->covariance() ? closestMeasPars :
nullptr;
796 <<
"Closest measured track parameters: " <<
m_printer->print(*tmpPars) << std::endl
797 <<
Amg::toString(*tmpPars->covariance(), 10) <<
" distance=" << closestMeasParsDist;
799 if (!tmpPars || tmpPars != closestPars) {
801 <<
"Closest track parameters : " <<
m_printer->print(*closestPars)
802 <<
" distance=" << closestParsDist;
807 bool straightLineMatch = !fieldCache.
toroidOn();
808 if (hasStereoAngle && !trackHasPhi && (straightLineMatch || entry1.
hasMomentum())) {
815 if (!straightLineMatch && !entry1.
hasMomentum() &&
info.trackChamberId.is_valid()) {
821 straightLineMatch =
true;
824 <<
" => doing straight line extrapolation match");
833 std::unique_ptr<const Trk::TrackParameters> exPars;
835 if (closestMeasPars) {
836 const Trk::TrackParameters* tmpPars = closestMeasPars->covariance() ? closestMeasPars :
nullptr;
846 int sectorDiff = std::abs(trackSector - segmentSector);
847 if (sectorDiff > 1 && sectorDiff != 15) {
848 ATH_MSG_VERBOSE(
"track sector =" << trackSector <<
" segment sector =" << segmentSector
849 <<
" => not in neighbouring sectors ");
867 ATH_MSG_DEBUG(
"track-segment match: Failed to extrapolate measured track parameters\n"
869 <<
" to segment surface " <<
m_idHelperSvc->toStringChamber(
info.segmentChamberId));
870 info.matchOK =
false;
875 exMeasPars = exPars->covariance() ? exPars.get() :
nullptr;
877 ATH_MSG_DEBUG(
"track-segment match: Did not get measured track parameters from extrapolation\n"
878 <<
"\nfrom " <<
m_idHelperSvc->toStringChamber(
info.trackChamberId) <<
" to segment surface "
897 ATH_MSG_DEBUG(
"track-segment match: Failed to extrapolate track parameters without errors\n"
899 <<
" to segment surface " <<
m_idHelperSvc->toStringChamber(
info.segmentChamberId));
900 info.matchOK =
false;
911 if (posXMeasErr2 <= 999.0) {
912 info.havePosX =
true;
913 info.havePosXError =
true;
914 info.posXMeasErr2 = posXMeasErr2;
915 info.posXTotalErr2 += posXMeasErr2;
919 if (
info.posYMeasErr2 <= 999.0) {
920 info.havePosY =
true;
921 info.havePosYError =
true;
922 info.posYMeasErr2 = posYMeasErr2;
923 info.posYTotalErr2 += posYMeasErr2;
927 if (phiMeasErr2 <= 999.0) {
928 info.haveAngleX =
true;
929 info.haveAngleXError =
true;
930 info.angleXMeasErr2 = phiMeasErr2;
931 info.angleXTotalErr2 += phiMeasErr2;
933 if (thetaMeasErr2 <= 999.0) {
934 info.haveAngleY =
true;
935 info.haveAngleYError =
true;
936 info.angleYMeasErr2 = thetaMeasErr2;
937 info.angleYTotalErr2 += thetaMeasErr2;
942 info.haveAngleXError =
false;
943 info.haveAngleYError =
false;
944 info.havePosXError =
false;
945 info.havePosYError =
false;
963 localPredCovar.setIdentity();
965 if (
info.haveAngleXError ||
info.haveAngleYError ||
info.havePosXError ||
info.havePosYError) {
974 globalToLocalPredJacobian.setIdentity();
977 globalToLocalPredJacobian(
Trk::phi,
Trk::phi) = globalToLocalPredAnglesJacobian(0, 0);
980 globalToLocalPredAnglesJacobian(0, 1);
983 const AmgSymMatrix(5)& globalPredCovar = *exMeasPars->covariance();
984 localPredCovar = globalPredCovar.similarity(globalToLocalPredJacobian);
987 if (
info.haveAngleXError &&
info.haveAngleYError &&
info.havePosXError &&
info.havePosYError) {
989 info.measuredCovariance = measErrors.block<4, 4>(0, 0);
990 info.predictionCovariance = localPredCovar.block<4, 4>(0, 0);
991 info.totalCovariance =
info.measuredCovariance +
info.predictionCovariance;
1005 info.diffVector = diffVec;
1009 info.matchChiSquared =
info.diffVector.transpose() * weightMatrix *
info.diffVector;
1010 info.haveMatchChiSquared =
true;
1018 info.posXTotalErr2 +=
info.posXPredErr2;
1019 info.posYTotalErr2 +=
info.posYPredErr2;
1020 info.angleXTotalErr2 +=
info.angleXPredErr2;
1021 info.angleYTotalErr2 +=
info.angleYPredErr2;
1027 }
else if (
info.haveAngleYError &&
info.havePosYError) {
1036 predCovar(0, 1) = predCovar(1, 0);
1037 info.predictionCovariance = predCovar;
1041 measCovar.setIdentity();
1045 measCovar(0, 1) = measCovar(1, 0);
1047 info.measuredCovariance = measCovar;
1048 info.totalCovariance =
info.predictionCovariance +
info.measuredCovariance;
1052 if (std::abs(
info.totalCovariance.determinant()) <
1053 std::numeric_limits<float>::epsilon()){
1059 diffVec[0] =
info.localPosYDiff;
1060 diffVec[1] =
info.localAngleYDiff;
1061 info.diffVector = diffVec;
1065 info.matchChiSquared =
info.diffVector.transpose() * weightMatrix *
info.diffVector;
1066 info.haveMatchChiSquared =
true;
1074 info.posYTotalErr2 +=
info.posYPredErr2;
1075 info.angleYTotalErr2 +=
info.angleYPredErr2;
1113 bool requireSameSideOfPerigee)
const {
1116 dirxy = dirxy.unit();
1117 double distFromPerigee1 = pos1.dot(dirxy);
1118 double distFromPerigee2 = pos2.dot(dirxy);
1119 bool sameSideOfPerigee = (distFromPerigee1 * distFromPerigee2 > 0.);
1120 bool same = sameSideOfPerigee;
1123 bool inOppositeEndcap =
false;
1124 constexpr
double etaEndcap = 1.1;
1125 double eta1 = pos1.eta();
1126 double eta2 = pos2.eta();
1127 if ((
eta1 > +etaEndcap &&
eta2 < -etaEndcap) || (
eta1 < -etaEndcap &&
eta2 > +etaEndcap)) {
1128 inOppositeEndcap =
true;
1134 double sign1 = pos1.y() < 0 ? -1. : 1.;
1135 double sign2 = pos2.y() < 0 ? -1. : 1.;
1136 msg(
MSG::DEBUG) <<
" Direction " <<
dir << std::fixed << std::setprecision(0) << std::endl
1137 <<
" pos1: dist " << std::setw(6) << distFromPerigee1 <<
" r " << std::setw(6) << pos1.perp() * sign1
1138 <<
" (x,y,z)=(" << std::setw(5) << pos1.x() <<
"," << std::setw(5) << pos1.y() <<
"," << std::setw(5)
1139 << pos1.z() <<
")" << std::endl
1140 <<
" pos2: dist " << std::setw(6) << distFromPerigee2 <<
" r " << std::setw(6) << pos2.perp() * sign2
1141 <<
" (x,y,z)=(" << std::setw(5) << pos2.x() <<
"," << std::setw(5) << pos2.y() <<
"," << std::setw(5)
1142 << pos2.z() <<
")" << std::setprecision(6);
1144 if (sameSideOfPerigee) {
1149 if (inOppositeEndcap) {
msg(
MSG::DEBUG) <<
" In opposite end-cap."; }
1159 if (requireSameSideOfPerigee) {
1168 if (seg)
return match(ctx, *seg, entry2, useTightCuts);
1177 std::set<Identifier>&
ids) {
1179 std::vector<const Trk::MeasurementBase*>::const_iterator
it = measurements.begin();
1180 std::vector<const Trk::MeasurementBase*>::const_iterator it_end = measurements.end();
1181 for (;
it != it_end; ++
it) {
1188 const std::vector<const MuonClusterOnTrack*>& rots = crot->
containedROTs();
1189 std::vector<const MuonClusterOnTrack*>::const_iterator rit = rots.begin();
1190 std::vector<const MuonClusterOnTrack*>::const_iterator rit_end = rots.end();
1191 for (; rit != rit_end; ++rit)
ids.insert((*rit)->identify());
1199 if (entry1.
phiHits().empty() || entry2.
phiHits().empty())
return true;
1201 std::set<Identifier> ids1;
1204 std::set<Identifier> ids2;
1212 if (intersectionSize == ids1.size() || intersectionSize == ids2.size())
return true;
1215 if (intersectionSize == 0)
return true;
1238 if (chid1 == chid2) {
1250 if (secDiff > 1 && secDiff != 15) {
1253 <<
" => not in neighbouring phi " <<
endmsg;
1267 const std::string& stationName1 =
1269 const std::string& stationName2 =
1271 std::string exceptions(
"MRFG");
1272 if (exceptions.find(stationName1[2]) == std::string::npos && exceptions.find(stationName2[2]) == std::string::npos) {
1280 const std::set<const MuonGM::MuonReadoutElement*> roEls1 =
m_candidateTool->readoutElements(seg1);
1281 const std::set<const MuonGM::MuonReadoutElement*> roEls2 =
m_candidateTool->readoutElements(seg2);
1284 double distZ = std::abs(read_ele1->center().z() - read_ele2->center().z());
1286 distZ -= 0.5 * (read_ele1->getZsize() + read_ele2->getZsize());
1289 << read_ele1->getStationType() <<
": z=" << read_ele1->center().z() <<
"+-"
1290 << 0.5 * read_ele1->getZsize() <<
" " << read_ele2->getStationType()
1291 <<
": z=" << read_ele2->center().z() <<
"+-" << 0.5 * read_ele2->getZsize() <<
" "
1292 <<
"distZ=" << distZ;
1295 if (distZ > 100.0) {