38 declareInterface<IMuonTrackCleaner>(
this);
54 return StatusCode::SUCCESS;
58 const EventContext& ctx)
const {
66 std::unique_ptr<Trk::Track> cleanedTrack =
cleanTrack(ctx, &
track, state);
71 std::unique_ptr<Trk::Track> cleanedTrack =
cleanTrack(ctx, &
track, state);
84 unsigned int nstationsInitial = state.
stations.size();
87 std::unique_ptr<Trk::Track> chamberTrack =
chamberCleaning(ctx, std::make_unique<Trk::Track>(*
track), state);
95 unsigned int nstationsChamberCleaning = state.
stations.size();
96 if (nstationsInitial != nstationsChamberCleaning) {
109 std::unique_ptr<Trk::Track> cleanCompTrack =
cleanCompROTs(ctx, std::move(chamberTrack), state);
110 if (!cleanCompTrack) {
117 std::unique_ptr<Trk::Track> flippedTrack =
recoverFlippedMdt(ctx, std::move(cleanCompTrack), state);
124 std::unique_ptr<Trk::Track> hitTrack =
hitCleaning(ctx, std::move(flippedTrack), state);
132 std::unique_ptr<Trk::Track> hitTrackClone = std::make_unique<Trk::Track>(*hitTrack);
135 unsigned int nstationsHitCleaning = state.
stations.size();
136 if (nstationsInitial != nstationsHitCleaning) {
148 std::unique_ptr<Trk::Track> cleanedTrack =
outlierRecovery(ctx, std::move(hitTrack), state);
152 init(ctx, *hitTrackClone, state);
154 ATH_MSG_DEBUG(
"Outlier recovery failure unrecoverable, reject track");
157 ATH_MSG_DEBUG(
"Outlier recovery failed but initial track is recoverable");
158 cleanedTrack = std::move(hitTrackClone);
167 unsigned int nstationsFinal = state.
stations.size();
168 if (nstationsInitial != nstationsFinal) {
190 auto tsos = std::make_unique<Trk::TrackStates>();
191 tsos->reserve(state.
measInfo.size());
193 unsigned int nmeas = 0;
197 for (; hit != hit_end; ++hit) {
199 if (!hit->useInFit) {
207 if (hit->meas) ++nmeas;
209 if (hit->cleanedCompROT) {
214 tsos->push_back(hit->originalState->clone());
225 std::unique_ptr<Trk::Track> cleanedTrack =
226 std::make_unique<Trk::Track>(
track->info(), std::move(tsos),
track->fitQuality() ?
track->fitQuality()->uniqueClone() :
nullptr);
230 std::unique_ptr<Trk::Track> newTrack =
fitTrack(ctx, *cleanedTrack,
track->info().particleHypothesis(), state.
slFit);
233 init(ctx, *newTrack, state);
251 auto tsos = std::make_unique<Trk::TrackStates>();
252 tsos->reserve(state.
measInfo.size());
254 unsigned int nmeas = 0;
258 for (; hit != hit_end; ++hit) {
260 if (!hit->useInFit) {
268 if (hit->meas) ++nmeas;
270 if (hit->flippedMdt) {
275 tsos->push_back(hit->originalState->clone());
286 std::unique_ptr<Trk::Track> cleanedTrack =
287 std::make_unique<Trk::Track>(
track->info(), std::move(tsos),
track->fitQuality() ?
track->fitQuality()->uniqueClone() :
nullptr);
291 std::unique_ptr<Trk::Track> newTrack =
fitTrack(ctx, *cleanedTrack,
track->info().particleHypothesis(), state.
slFit);
294 init(ctx, *newTrack, state);
311 std::unique_ptr<Trk::Track> newTrack;
316 ATH_MSG_DEBUG(
" Too many outliers, cannot perform cleaning ");
322 auto tsos = std::make_unique<Trk::TrackStates>();
323 tsos->reserve(state.
measInfo.size());
326 unsigned int nmeas = 0;
327 unsigned int nremovedPhi = 0;
328 bool hasSmall =
false;
329 bool hasLarge =
false;
332 std::map<MuonStationIndex::StIndex, std::pair<bool, bool> > slCountsPerStationLayer;
336 for (; hit != hit_end; ++hit) {
339 if (!hit->useInFit ||
remove) {
343 if (!hit->id.is_valid() ||
m_idHelperSvc->measuresPhi(hit->id)) ++nremovedPhi;
346 std::string inb = hit->inBounds ?
" inBounds" :
" outBounds";
351 if (hit->cleanedCompROT) {
366 if (!hit->id.is_valid() ||
m_idHelperSvc->measuresPhi(hit->id)) {
376 bool isLarge = !isSmall;
378 std::map<MuonStationIndex::StIndex, std::pair<bool, bool> >
::iterator pos =
379 slCountsPerStationLayer.find(stIndex);
382 if (
pos == slCountsPerStationLayer.end())
383 slCountsPerStationLayer[stIndex] = std::make_pair(isSmall, isLarge);
386 if (isSmall) slCountsPerStationLayer[stIndex].first =
true;
387 if (isLarge) slCountsPerStationLayer[stIndex].second =
true;
391 if (!hit->originalState)
ATH_MSG_DEBUG(
"no original state!");
392 tsos->push_back(hit->originalState->clone());
396 unsigned int noverlaps = 0;
397 for (
auto [
index, slCounts] : slCountsPerStationLayer) {
398 if (!hasSmall && slCounts.first) hasSmall =
true;
399 if (!hasLarge && slCounts.second) hasLarge =
true;
400 if (slCounts.first && slCounts.second) ++noverlaps;
403 if (noverlaps == 0 && hasSmall && hasLarge) ++noverlaps;
410 ATH_MSG_DEBUG(
" nremovedPhi " << nremovedPhi <<
" noverlaps " << noverlaps <<
" nid " << state.
nIdHits);
415 if (nremovedPhi > 0) {
416 bool hasPhiConstraint =
false;
419 hasPhiConstraint =
true;
420 else if (firstPhi && noverlaps > 0)
421 hasPhiConstraint =
true;
422 else if (noverlaps > 1)
423 hasPhiConstraint =
true;
424 else if (firstPhi && lastPhi && firstPhi->
pars && lastPhi->
pars) {
428 if (
distPhi > 450.) hasPhiConstraint =
true;
430 if (!hasPhiConstraint) {
431 ATH_MSG_DEBUG(
"Lost phi constraint during track cleaning, reject track");
437 std::unique_ptr<Trk::Track> cleanedTrack =
438 std::make_unique<Trk::Track>(
track->info(), std::move(tsos),
track->fitQuality() ?
track->fitQuality()->uniqueClone() :
nullptr);
443 newTrack =
fitTrack(ctx, *cleanedTrack,
track->info().particleHypothesis(), state.
slFit);
454 init(ctx, *newTrack, state);
477 for (; chit != chit_end; ++chit) {
480 ATH_MSG_DEBUG(
" only two precision chambers, cannot remove chamber. ");
487 unsigned int foundChambers = 0;
491 for (; chit != chit_end; ++chit) {
499 if (foundChambers > excludedChambers) {
500 ATH_MSG_WARNING(
" Found more excluded chambers than in list, this should not happen ");
502 }
else if (foundChambers == excludedChambers) {
503 ATH_MSG_DEBUG(
" all excluded chambers in removal list, failing cleaning ");
508 std::vector<ChamberRemovalOutput> cleaningResults;
520 for (; chit != chit_end; ++chit) {
532 cleaningResults.push_back(std::move(
result));
540 for (; chit != chit_end; ++chit) {
552 cleaningResults.push_back(std::move(
result));
556 if (cleaningResults.empty())
return nullptr;
558 ATH_MSG_DEBUG(
" chamberCleaning Results nr " << cleaningResults.size());
564 for (
auto* hit : finalResult.
removedHits) hit->useInFit = 0;
571 std::unique_ptr<Trk::Track> finalResultTrackClone = std::make_unique<Trk::Track>(*finalResult.
track);
573 init(ctx, *finalResultTrackClone, state);
577 std::unique_ptr<Trk::Track> recoveredTrack =
outlierRecovery(ctx, std::move(finalResult.
track), state, &removedChamberIndex);
578 if (!recoveredTrack)
return finalResultTrackClone;
579 init(ctx, *recoveredTrack, state);
580 return recoveredTrack;
585 bool removePhi,
bool removeEta,
CleaningState& state)
const {
597 auto tsos = std::make_unique<Trk::TrackStates>();
598 tsos->reserve(state.
measInfo.size());
600 unsigned int nmeas = 0;
602 std::set<Identifier> stations{};
606 bool remove = hit.
chId == chId && ((removePhi && measuresPhi) || (removeEta && !measuresPhi));
636 if (nmeas < 6 || stations.size() < 2) {
637 ATH_MSG_DEBUG(
" too few hits, cannot perform chamberCleaning ");
642 std::unique_ptr<Trk::Track> cleanedTrack =
643 std::make_unique<Trk::Track>(
track->info(), std::move(tsos),
track->fitQuality() ?
track->fitQuality()->uniqueClone() :
nullptr);
650 std::unique_ptr<Trk::Track> newTrack =
fitTrack(ctx, *cleanedTrack,
track->info().particleHypothesis(), state.
slFit);
656 result.track = std::move(newTrack);
678 std::set<MuonStationIndex::ChIndex> recoverableLayers;
683 if (currentIndex && *currentIndex != stationIndex)
continue;
686 unsigned int nhits = statistics.
nhits;
687 unsigned int noutliers = statistics.
noutliers;
690 unsigned int noutBounds = statistics.
noutBounds;
692 if (nrecoverableOutliers > 0) {
693 if (nhits + nrecoverableOutliers > 2 &&
694 ((noutBounds == 0 && noutliers == 0) || (nrecoverableOutliers != 0 && noutliers < 2))) {
695 recoverableLayers.insert(stationIndex);
703 bool addedHits =
false;
704 unsigned int removedOutOfBoundsHits(0);
706 auto tsos = std::make_unique<Trk::TrackStates>();
707 tsos->reserve(state.
measInfo.size());
713 if (recoverableLayers.count(hit.chIndex)) {
717 std::optional<const Trk::ResidualPull> resPull{
720 ATH_MSG_DEBUG(
" calculation of residual/pull failed !!!!! ");
730 if (hit.flippedMdt) {
731 double rDrift = hit.meas->localParameters()[
Trk::locR];
732 double rDriftFlip = hit.flippedMdt->localParameters()[
Trk::locR];
733 double rTrack = hit.pars->parameters()[
Trk::locR];
734 ATH_MSG_DEBUG(
" flipped MDT: r_orig " << rDrift <<
" flip " << rDriftFlip <<
" rTrack " << rTrack);
742 tsos->push_back(hit.originalState->clone());
750 ++removedOutOfBoundsHits;
758 tsos->push_back(hit.originalState->clone());
762 if (!addedHits && removedOutOfBoundsHits == 0) {
767 if (tsos->size() < 6) {
768 ATH_MSG_WARNING(
" too few hits, cannot add hits. This should not happen ");
773 std::unique_ptr<Trk::Track> cleanedTrack =
774 std::make_unique<Trk::Track>(
track->info(), std::move(tsos),
track->fitQuality() ?
track->fitQuality()->uniqueClone() :
nullptr);
777 ATH_MSG_DEBUG(
" only removed out of bound hits, returning track without new fit ");
784 std::unique_ptr<Trk::Track> newTrack =
fitTrack(ctx, *cleanedTrack,
track->info().particleHypothesis(), state.
slFit);
788 init(ctx, *newTrack, state);
833 if (!readHandle.isValid()) {
837 readHandle->getInitializedCache(fieldCache);
853 std::set<int> rpcLayers;
854 std::set<int> tgcLayers;
856 double largestmdtpull = -999;
861 ATH_MSG_DEBUG(tsit->dumpType() <<
", parameters " << *tsit->trackParameters());
895 bool pseudo = !
id.is_valid();
899 ATH_MSG_VERBOSE(
" TSOS is not a muon hit, position: r " <<
pars->position().perp() <<
" z " <<
pars->position().z());
913 bool measuresPhi = pseudo ? true :
m_idHelperSvc->measuresPhi(
id);
921 bool inBounds =
true;
923 double tol2 = 2 * tol1;
934 }
else if (mmClusterOnTrack) {
947 ATH_MSG_DEBUG(
" calculation of residual/pull failed !!!!! ");
950 int pullSize = resPull->pull().size();
951 double residual = resPull->residual().front();
952 double pull = std::abs(resPull->pull().front());
955 if (!pseudo && pullSize != 1) {
964 double rTrackAbs = std::abs(rTrack);
965 double flippedResidual = isMDT ? rDrift + rTrack : 1e10;
966 double flippedPull = isMDT ? std::abs(flippedResidual /
error) : 1e10;
968 bool isNoise =
false;
971 bool flippedIsRecoverable =
973 double innerRadius = 14.6;
979 bool isDelta = isOutlier && isMDT && rTrackAbs < innerRadius && rTrackAbs > std::abs(rDrift);
984 if (rTrackAbs > innerRadius) inBounds =
false;
985 }
else if (
pull > 10.) {
990 std::unique_ptr<MdtDriftCircleOnTrack> mdtRotFlipped;
991 std::unique_ptr<const CompetingMuonClustersOnTrack> updatedCompRot;
992 bool flipSign =
false;
998 isRecoverable =
false;
999 flippedIsRecoverable =
false;
1002 if (flippedIsRecoverable) {
1007 if (!isNoise && flipSign) {
1009 mdtRotFlipped = std::make_unique<MdtDriftCircleOnTrack>(*mdtRot);
1012 double rDriftFlip = mdtRotFlipped->localParameters()[
Trk::locR];
1013 int signRot = rDrift < 0 ? -1 : 1;
1014 int signRotFlip = rDriftFlip < 0 ? -1 : 1;
1015 if (rDrift != 0. && signRot == signRotFlip) {
1016 ATH_MSG_WARNING(
" failed to flip sign of MDT " << rDrift <<
" flip " << rDriftFlip);
1019 ATH_MSG_WARNING(
" failed to dynamic_cast measurement with MDT Identifier to a MdtDriftCircleOnTrack");
1024 largestmdtpull =
pull;
1038 rpcLayers.insert(
layer);
1047 if (stName[1] ==
'1')
1049 else if (stName[1] ==
'2')
1051 else if (stName[1] ==
'3')
1063 tgcLayers.insert(
layer);
1077 double absminres = 0.;
1078 double absmaxres = 0.;
1081 if (!cluster)
continue;
1090 }
else if (absres < absminres) {
1094 }
else if (absres > absmaxres) {
1102 ATH_MSG_DEBUG(
" residuals: min " << minres <<
" max " << maxres <<
" diff " << maxres - minres);
1103 bool splitCompRot =
false;
1104 if (std::abs(maxres - minres) > 100 && absmaxres - absminres > 20 && crot->
numberOfContainedROTs() < 20) {
1106 splitCompRot =
true;
1109 std::list<const Trk::PrepRawData*> prdList;
1113 if (!cluster)
continue;
1123 if (prdList.empty()) {
1124 ATH_MSG_WARNING(
"No clusters selected during comprot cleaning, keeping old cluster");
1134 state.
measInfo.emplace_back(
id, chId, chIndex, inBounds,
residual,
pull, tsit, meas,
pars, std::move(resPull),
nullptr);
1136 if (flipSign) {
info.flippedMdt = std::move(mdtRotFlipped); }
1137 info.isNoise = isNoise;
1138 if (updatedCompRot) {
1140 info.cleanedCompROT = std::move(updatedCompRot);
1142 std::unique_ptr<Trk::TrackParameters> exPars =
m_extrapolator->extrapolate(ctx,
1143 *
pars,
info.cleanedCompROT->associatedSurface(),
1146 ATH_MSG_WARNING(
"Update of comp rot parameters failed, keeping old ones");
1147 info.cleanedCompROT.reset();
1149 info.pars = exPars.get();
1156 chamberStatistics.
chIndex = chIndex;
1161 ATH_MSG_DEBUG(
" r_drift " << rDrift <<
" r_trk " << rTrack <<
" dr " << std::setw(7)
1168 if (flippedIsRecoverable)
1170 else if (isRecoverable)
1179 }
else if (flippedIsRecoverable || isRecoverable)
1192 ++chamberStatistics.
nhits;
1193 if (!pseudo) ++state.
nhits;
1197 std::string idString = pseudo ?
" Pseudomeasurement " :
m_idHelperSvc->toString(
id);
1198 std::string boundCheck = inBounds ?
"inBounds" :
"outBounds";
1205 ATH_MSG_VERBOSE(
" r_drift " << std::setw(8) << rDrift <<
" r_trk " << std::setw(7) << rTrack <<
" dr " << std::setw(7)
1249 ++pullInfoHits.
nhits;
1260 ++pullInfoTrig.
nhits;
1270 unsigned int nphiLayers = rpcLayers.size() + tgcLayers.size();
1272 if (state.
nIdHits > 0) { nphiLayers += 2; }
1275 ATH_MSG_DEBUG(
" Sufficient constraints to clean competing ROTs: trigger layers " << nphiLayers);
1283 state.
slFit =
false;
1303 std::set<Identifier> chambersToBeRemoved, chambersToBeRemovedPhi, goodEtaLayers, goodPhiLayers;
1315 for (; chit != chit_end; ++chit) {
1316 if (!chit->first.is_valid())
continue;
1328 << noutBounds.
neta <<
" phi hits " << nhits.
nphi <<
" outBounds " << noutBounds.
nphi);
1329 if (nhits.
neta != 0 && nhits.
neta == noutBounds.
neta) {
1332 double fakePull = 1000. * nhits.
neta;
1333 if (!chambersToBeRemoved.count(chit->first)) {
1336 chambersToBeRemoved.insert(chit->first);
1341 for (; pIt != pIt_end; ++pIt) {
1342 if (pIt->second == chit->first && pIt->first < fakePull) {
1343 pIt->first = fakePull;
1351 if (isPrec && nhits.
neta > 0) {
1358 if (nhits.
nphi != 0 && nhits.
nphi == noutBounds.
nphi) {
1361 double fakePull = 1000. * nhits.
nphi;
1362 if (!chambersToBeRemovedPhi.count(chit->first)) {
1365 chambersToBeRemovedPhi.insert(chit->first);
1370 for (; pIt != pIt_end; ++pIt) {
1371 if (pIt->second == chit->first) {
1372 pIt->first =
std::max(pIt->first, fakePull);
1379 if (nhits.
nphi > 0) {
1390 double pull_precisionhits = -1.;
1392 double pull_triggerhits = -1.;
1394 double pull_phihits = -1.;
1397 << pull_precisionhits <<
" trigger eta " << pull_triggerhits <<
" phi " << pull_phihits <<
" measurements "
1398 << state.
measInfo.size() << std::endl
1399 <<
" precision chambers " << state.
pullSumPerChamber.size() <<
" hits with large pull "
1406 if (state.
stations.size() == 1 && phiPull > 5.) {
ATH_MSG_DEBUG(
" Single station track with large phi pulls!! "); }
1412 bool usePhi)
const {
1413 bool doCleaning =
false;
1420 if (!pullSumPerChamber.empty())
msg() <<
MSG::DEBUG <<
"Chamber pulls " << pullSumPerChamber.size() <<
":";
1423 double pulltot = 0.;
1424 for (; cit != cit_end; ++cit) {
1425 double avePull = cit->second.pullSum / cit->second.nhits;
1426 pulltot += cit->second.pullSum;
1427 ndof += cit->second.nhits;
1428 double avePullReduced = cit->second.nhits > 1 ? (cit->second.pullSum - cit->second.maxPull) / (cit->second.nhits - 1) : avePull;
1431 <<
" chamber " <<
m_idHelperSvc->toStringChamber(cit->first) <<
" pull sum " << cit->second.pullSum <<
" max pull "
1432 << cit->second.maxPull <<
" nhits " << cit->second.nhits <<
" ave pull " << avePull <<
" reduced ave pull "
1441 if (!chambersToBeRemovedSet.count(cit->first)) {
1442 chambersToBeRemoved.emplace_back(avePull, cit->first);
1443 chambersToBeRemovedSet.insert(cit->first);
1449 bool dropMore =
false;
1450 if (dropMore && pulltot * pulltot > 2. *
ndof *
ndof) {
1456 cit = pullSumPerChamber.begin();
1457 for (; cit != cit_end; ++cit) {
1458 double avePull = cit->second.pullSum / cit->second.nhits;
1459 if (!chambersToBeRemovedSet.count(cit->first)) {
1460 chambersToBeRemoved.emplace_back(avePull, cit->first);
1461 chambersToBeRemovedSet.insert(cit->first);
1466 if (dropMore && doCleaning &&
m_iterate) {
1470 for (; cit != cit_end; ++cit) {
1471 double avePull = cit->second.pullSum / cit->second.nhits;
1472 if (!chambersToBeRemovedSet.count(cit->first)) {
1473 chambersToBeRemoved.emplace_back(avePull, cit->first);
1474 chambersToBeRemovedSet.insert(cit->first);
1483 bool isMdt =
id.is_valid() ?
m_idHelperSvc->isMdt(
id) :
false;
1484 bool measuresPhi =
id.is_valid() ?
m_idHelperSvc->measuresPhi(
id) :
false;
1494 return std::abs(
pull) > cutScaleFactor * pullCut;
1497 return std::abs(
pull) > cutScaleFactor * pullCut;
1502 std::ostringstream sout;
1504 unsigned int nhits = statistics.
nhits;
1505 unsigned int noutliers = statistics.
noutliers;
1506 unsigned int ndeltas = statistics.
ndeltas;
1508 unsigned int noutBounds = statistics.
noutBounds;
1511 << noutliers <<
" deltas " << std::setw(6) << ndeltas <<
" recoverableOutliers " << std::setw(6) << nrecoverableOutliers
1512 <<
" outBounds " << std::setw(6) << noutBounds;
1518 unsigned int nstationsChamberCleaning = state.
stations.size();
1519 ATH_MSG_DEBUG(
" Cleaner removed full station from track: remaining layers " << nstationsChamberCleaning);
1521 if (nstationsChamberCleaning < 2) {
1522 ATH_MSG_DEBUG(
" Cleaner removed all but one station from track!!! ");
1529 unsigned int nstations = state.
stations.size();
1530 if (nstations == 1 ||
1532 ATH_MSG_DEBUG(
" Momentum measurement lost, cleaning given up ");
1548 for (
auto* hit :
result.removedHits) hit->useInFit = 1;