29 constexpr
double probCut = .00001;
40 declareInterface<IMuonCombinedTagTool>(
this);
60 return StatusCode::SUCCESS;
65 const EventContext& ctx)
const {
68 std::unique_ptr<CombinedFitTag> bestTag, currentTag;
69 std::unique_ptr<Trk::Track> bestCombTrack, bestMETrack,
combinedTrack, METrack;
73 using InDetProbMatch = std::pair<double, const InDetCandidate*>;
74 std::vector<InDetProbMatch> sortedInDetCandidates;
75 sortedInDetCandidates.reserve(indetCandidates.size());
78 const Trk::Track* id_track = idTP->indetTrackParticle().track();
80 double innerMatchProb = -1;
83 const double maxProb =
std::max(outerMatchProb, innerMatchProb);
84 sortedInDetCandidates.emplace_back(maxProb, idTP);
87 std::sort(sortedInDetCandidates.begin(), sortedInDetCandidates.end(),
88 [](
const InDetProbMatch&
a,
const InDetProbMatch&
b) { return a.first > b.first; });
90 bool fitBadMatches =
false;
91 for (
const InDetProbMatch& cand_prob : sortedInDetCandidates) {
93 if (cand_prob.first < probCut && !fitBadMatches) {
102 const Trk::Track* id_track = cand_prob.second->indetTrackParticle().track();
103 ATH_MSG_DEBUG(
"Doing combined fit with ID track " << cand_prob.second->toString());
129 *bestCombTrack, bestMETrack.get())) {
130 bestCandidate = cand_prob.second;
131 bestTag.swap(currentTag);
133 bestMETrack.swap(METrack);
138 for (
const InDetProbMatch& cand_prob : sortedInDetCandidates) {
139 const Trk::Track* id_track = cand_prob.second->indetTrackParticle().track();
162 *bestTag, *bestCombTrack, bestMETrack.get())) {
163 bestCandidate = cand_prob.second;
164 bestTag.swap(currentTag);
166 bestMETrack.swap(METrack);
174 if (msgLevel() >=
MSG::DEBUG && bestMETrack) {
175 dumpCaloEloss(ctx, bestCombTrack.get(),
" bestCandidate Combined Track ");
176 dumpCaloEloss(ctx, bestMETrack.get(),
" bestCandidate Extrapolated Track ");
181 <<
" match chi2 " << bestTag->matchChi2());
182 combTracks->
push_back(std::move(bestCombTrack));
184 bestTag->setCombinedTrackLink(comblink);
186 METracks->
push_back(std::move(bestMETrack));
188 bestTag->setUpdatedExtrapolatedTrackLink(melink);
192 tagMap.
addEntry(bestCandidate, bestTag.release());
201 if (!extrapolatedTrack) extrapolatedTrack = &spectrometerTrack;
204 double combinedFitChi2 = 9999.;
213 std::unique_ptr<Trk::Track> outwardsTrack(
214 m_outwardsBuilder->combinedFit(ctx, indetTrack, *extrapolatedTrack, spectrometerTrack));
215 if (outwardsTrack &&
chi2(outwardsTrack->
fitQuality()) < combinedFitChi2) {
237 ATH_MSG_DEBUG(
" No Calorimeter CaloDeposit found on combined track ");
243 ATH_MSG_DEBUG(
" combinedTrackQualityCheck fails with momentumBalanceSignificance " << significance);
251 if (combinedPerigee->covariance() && indetPerigee->covariance()) {
252 const double dpOverP2 =
Amg::error(*combinedPerigee->covariance(),
Trk::qOverP) * combinedPerigee->momentum().mag2();
253 if (dpOverP2 < 1.
E-6) {
255 ATH_MSG_DEBUG(
"combinedTrackQualityCheck: fail with unphysical momentum covariance");
263 ATH_MSG_DEBUG(
"combinedTrackQualityCheck: fail with momentum pull above cut: "
264 <<
pull <<
" pid " << 1. / indetPerigee->parameters()[
Trk::qOverP] <<
" pcb "
265 << 1. / combinedPerigee->parameters()[
Trk::qOverP] <<
" 1./sigma " << 1. /
sigma);
282 if (
tag.muonCandidate().extrapolatedTrack()) {
283 std::pair<int, std::pair<double, double> > aTriad =
284 m_matchQuality->innerMatchAll(idTrack, *
tag.muonCandidate().extrapolatedTrack(), ctx);
285 const int matchDoF = aTriad.first;
286 const double matchChi2 = aTriad.second.first;
287 const double matchProb = aTriad.second.second;
289 tag.innerMatch(matchChi2, matchDoF, matchProb);
290 ATH_MSG_DEBUG(
" extrapolatedTrack innerMatch " << matchChi2);
294 std::unique_ptr<Trk::Track> refittedExtrapolatedTrack;
308 fieldCondObj->getInitializedCache(fieldCache);
309 if (!fieldCache.
toroidOn()) dorefit =
false;
316 if (vertices.isValid()) {
318 for (
const auto& tpLink : vx->trackParticleLinks()) {
319 if (*tpLink == &idTrackParticle) {
324 if (matchedVertex)
break;
329 origin =
Amg::Vector3D{matchedVertex->x(), matchedVertex->y(), matchedVertex->z()};
335 origin[
Amg::z] = idTrackParticle.
z0() + idTrackParticle.
vz();
336 ATH_MSG_DEBUG(
" NO matched vertex take track perigee " << origin);
346 unsigned numberPseudo =
347 tag.muonCandidate().extrapolatedTrack() ?
m_trackQuery->numberPseudoMeasurements(*
tag.muonCandidate().extrapolatedTrack()) : 1;
350 if (refittedExtrapolatedTrack) {
351 std::pair<int, std::pair<double, double> > aTriad =
m_matchQuality->innerMatchAll(idTrack, *refittedExtrapolatedTrack, ctx);
352 const int matchDoF = aTriad.first;
353 const double matchChi2 = aTriad.second.first;
354 const double matchProb = aTriad.second.second;
357 tag.innerMatch(matchChi2, matchDoF, matchProb);
358 ATH_MSG_DEBUG(
" refittedExtrapolatedTrack innerMatch " << matchChi2);
361 if (
tag.muonCandidate().extrapolatedTrack()) {
362 double oldmatchChi2 =
m_matchQuality->innerMatchChi2(idTrack, *
tag.muonCandidate().extrapolatedTrack(), ctx);
364 ATH_MSG_VERBOSE(
"evaluateMatchProperties: chi2 re-evaluated from " << oldmatchChi2 <<
" to " << matchChi2);
366 if (matchChi2 > 1.1 * oldmatchChi2)
367 ATH_MSG_DEBUG(
"evaluateMatchProperties: chi2 got worse: from " << oldmatchChi2 <<
" to " << matchChi2);
369 ATH_MSG_VERBOSE(
"evaluateMatchProperties: added new extrapolated track with chi2 " << matchChi2);
371 }
else if (!numberPseudo) {
373 ATH_MSG_DEBUG(
"evaluateMatchProperties: fail re-evaluation of match chi2");
375 return refittedExtrapolatedTrack;
380 if (!inTrack)
return;
395 double Eloss{0.}, idEloss{0.}, caloEloss{0.}, msEloss{0.}, deltaP{0.},
396 pcalo{0.}, pstart{0.},
eta{0.}, pMuonEntry{0.};
399 if (
m->trackParameters()) pMuonEntry =
m->trackParameters()->momentum().mag();
407 if (pstart == 0 &&
m->trackParameters()) {
408 pstart =
m->trackParameters()->momentum().mag();
409 eta =
m->trackParameters()->momentum().eta();
410 ATH_MSG_DEBUG(
"Start pars found eta " <<
eta <<
" r " << (
m->trackParameters())->position().perp() <<
" z "
411 << (
m->trackParameters())->position().z() <<
" pstart " << pstart);
413 if (
m->materialEffectsOnTrack()) {
420 pcalo =
m->trackParameters()->momentum().mag();
424 <<
" deltaTheta " << scatAngles->
deltaTheta() <<
" pull "
430 ATH_MSG_DEBUG(
"Eloss found r " << (
m->trackParameters())->position().perp() <<
" z "
431 << (
m->trackParameters())->position().z() <<
" value " << energyLoss->
deltaE()
432 <<
" Eloss " << Eloss);
435 caloEloss = std::abs(energyLoss->
deltaE());
437 deltaP =
m->trackParameters()->momentum().mag() - pcalo;
440 ATH_MSG_DEBUG(
txt <<
" Calorimeter delta p " << deltaP <<
" deltaE " << caloEloss
441 <<
" delta pID = pcaloEntry-pstart " << pcalo - pstart);
443 Eloss += std::abs(energyLoss->
deltaE());
450 Eloss = idEloss + caloEloss + msEloss;
451 ATH_MSG_DEBUG(
txt <<
" eta " <<
eta <<
" pstart " << pstart / 1000. <<
" Eloss on TSOS idEloss " << idEloss <<
" caloEloss "
452 << caloEloss <<
" msEloss " << msEloss <<
" Total " << Eloss <<
" pstart - pMuonEntry " << pstart - pMuonEntry);
457 if (!extrTrack)
return true;
458 if (!
m_trackQuery->isCaloAssociated(*extrTrack, ctx))
return true;
471 if (!caloEnergyCombined || !caloEnergyExtrapolated) {
473 ATH_MSG_VERBOSE(
"extrapolatedNeedsRefit: no refit for combined track without CaloEnergy");
476 double deltaE = caloEnergyExtrapolated->
deltaE() - caloEnergyCombined->
deltaE();
477 if (std::abs(deltaE) > 0.3 * caloEnergyExtrapolated->
sigmaDeltaE()) {
478 ATH_MSG_VERBOSE(
"extrapolatedNeedsRefit: caloEnergy difference " << deltaE <<
" sigma "
479 << caloEnergyExtrapolated->
sigmaDeltaE() <<
" ratio "
480 << deltaE / caloEnergyExtrapolated->
sigmaDeltaE());
490 if ((**o).measurementOnTrack() && (**o).trackParameters()) {
497 ((**o).trackParameters()->associatedSurface().center() - (**c).trackParameters()->associatedSurface().center()).
mag();
498 if (std::abs(separation) > 1. *
CLHEP::mm) {
500 <<
" separation " << separation <<
" extrap " << (**o).trackParameters()->associatedSurface().center()
501 <<
" comb " << (**c).trackParameters()->associatedSurface().center());
508 ATH_MSG_VERBOSE(
"extrapolatedNeedsRefit: outlier only on combined track ");
510 ATH_MSG_VERBOSE(
"extrapolatedNeedsRefit: outlier only on extrapolated track ");
544 const double matchChiSq1 = curTag.
matchChi2();
545 const double matchChiSq2 = bestTag.
matchChi2();
548 ATH_MSG_VERBOSE(
"bestMatchChooser: matchChiSq " << matchChiSq1 <<
" " << matchChiSq2);
549 if (summary1 && summary2) {
550 ATH_MSG_VERBOSE(
"bestMatchChooser: matchChiSq " << matchChiSq1 <<
" " << matchChiSq2 <<
" numTRTHits "
554 << bestTag.
fieldIntegral().betweenInDetMeasurements() <<
" MS "
555 << curTag.
fieldIntegral().betweenSpectrometerMeasurements() <<
" "
556 << bestTag.
fieldIntegral().betweenSpectrometerMeasurements());
558 ATH_MSG_VERBOSE(
"bestMatchChooser: matchChiSq " << matchChiSq1 <<
" " << matchChiSq2);
566 ATH_MSG_VERBOSE(
"bestMatchChooser: fitChiSq " << fitChiSq1 <<
" " << fitChiSq2);
570 ATH_MSG_DEBUG(
"bestMatchChooser: choose worse, but acceptable, matchChiSq as better fitChiSq. "
571 <<
" matchChiSq 1,2 " << matchChiSq1 <<
", " << matchChiSq2 <<
" fitChiSq/DoF 1,2 " << fitChiSq1
572 <<
"/" << numberDoF1 <<
", " << fitChiSq2 <<
"/" << numberDoF2);
578 ATH_MSG_DEBUG(
"bestMatchChooser: choose worse, but acceptable, matchChiSq as better fitChiSq. "
579 <<
" matchChiSq 1,2 " << matchChiSq1 <<
", " << matchChiSq2 <<
" fitChiSq/DoF 1,2 " << fitChiSq1
580 <<
"/" << numberDoF1 <<
", " << fitChiSq2 <<
"/" << numberDoF2);
601 double cutRatio{1.5}, integral1{0.}, integral2{0.};
608 double significanceCut = 2.0;
611 if (std::abs(significance1 - significance2) > significanceCut) {
612 if (significance1 < significanceCut) {
615 ATH_MSG_DEBUG(
"bestMatchChooser: choose worse, but acceptable, matchChiSq as better momentum balance. "
616 <<
" matchChiSq 1,2 " << matchChiSq1 <<
", " << matchChiSq2
622 if (significance2 < significanceCut) {
625 ATH_MSG_DEBUG(
"bestMatchChooser: choose worse, but acceptable, matchChiSq as better momentum balance. "
626 <<
" matchChiSq 1,2 " << matchChiSq1 <<
", " << matchChiSq2
636 ATH_MSG_VERBOSE(
"bestMatchChooser: spectrometer field integral ratio ");
637 integral1 = std::abs(curTag.
fieldIntegral().betweenSpectrometerMeasurements());
638 integral2 = std::abs(bestTag.
fieldIntegral().betweenSpectrometerMeasurements());
639 if (integral1 > cutRatio * integral2)
return true;
640 if (integral2 > cutRatio * integral1)
return false;
644 integral1 = std::abs(curTag.
fieldIntegral().betweenInDetMeasurements());
645 integral2 = std::abs(bestTag.
fieldIntegral().betweenInDetMeasurements());
646 if (integral1 > cutRatio * integral2)
return true;
647 if (integral2 > cutRatio * integral1)
return false;
652 if (std::abs(fitChiSq1 - fitChiSq2) > 0.5 *
m_badFitChi2) {
656 ATH_MSG_DEBUG(
"bestMatchChooser: choose worse, but acceptable, matchChiSq according to overall quality. "
657 <<
" matchChiSq 1,2 " << matchChiSq1 <<
", " << matchChiSq2 <<
" fitChiSq/DoF 1,2 " << fitChiSq1
658 <<
"/" << numberDoF1 <<
", " << fitChiSq2 <<
"/" << numberDoF2);
665 ATH_MSG_DEBUG(
"bestMatchChooser: choose worse, but acceptable, matchChiSq according to overall quality. "
666 <<
" matchChiSq 1,2 " << matchChiSq1 <<
", " << matchChiSq2 <<
" fitChiSq/DoF 1,2 " << fitChiSq1
667 <<
"/" << numberDoF1 <<
", " << fitChiSq2 <<
"/" << numberDoF2);
694 return fitChiSq1 < fitChiSq2;
697 return matchChiSq1 < matchChiSq2;