44 const double FiftyOverSqrt12 = 50. / std::sqrt(12);
53 declareInterface<MooTrackFitter>(
this);
75 return StatusCode::SUCCESS;
94 <<
"| extract | phi range | startPars | clean phi | add fake | fit | no perigee | low mom | extract | "
95 "add fake | final fit | passed |"
97 << std::setprecision(2) << std::setw(12) << nfailedExtractInital << std::setw(12) << nfailedMinMaxPhi << std::setw(12)
98 << nfailedParsInital << std::setw(12) << nfailedExtractCleaning << std::setw(12) << nfailedFakeInitial << std::setw(12)
99 << nfailedTubeFit << std::setw(13) << noPerigee << std::setw(12) << nlowMomentum << std::setw(12)
100 << nfailedExtractPrecise << std::setw(12) << nfailedFakePrecise << std::setw(12) << nfailedFitPrecise << std::setw(12)
103 return StatusCode::SUCCESS;
107 if (
entry.hits().size() <
entry.etaHits().size()) {
111 if (
entry.etaHits().size() < 3) {
return (
entry.ncscHitsEta < 2); }
124 if (!
extractData(fitterData,
true))
return nullptr;
128 if (!pp)
return nullptr;
135 std::set<Identifier> excludedChambers;
158 std::set<Identifier> excludedChambers;
176 const PrepVec& externalPhiHits)
const {
190 ATH_MSG_DEBUG(
" Phi range check failed, candidate stations not pointing. Will not fit track");
198 std::unique_ptr<Trk::Perigee>& startPars = fitterData.
startPars;
213 ATH_MSG_DEBUG(
" Failed to extract data after phi hit cleaning");
221 ATH_MSG_DEBUG(
" Failed to add fake phi hits for precise fit");
264 fitterDataRefit.avePhi = fitterData.
avePhi;
265 fitterDataRefit.phiMin = fitterData.
phiMin;
266 fitterDataRefit.phiMax = fitterData.
phiMax;
267 fitterDataRefit.firstEntry = fitterData.
firstEntry;
268 fitterDataRefit.secondEntry = fitterData.
secondEntry;
280 ATH_MSG_DEBUG(
" Failed to add fake phi hits for precise fit");
286 std::unique_ptr<Trk::Track> newTrack =
fit(ctx, *pp, fitterDataRefit.measurements,
Trk::muon,
false);
288 track.swap(newTrack);
293 ATH_MSG_DEBUG(
" Precise fit failed, keep fit with broad errors");
297 fitterData.
garbage.insert(fitterData.
garbage.end(), std::make_move_iterator(fitterDataRefit.garbage.begin()),
298 std::make_move_iterator(fitterDataRefit.garbage.end()));
299 fitterDataRefit.garbage.clear();
304 std::set<Identifier> excludedChambers;
312 if (!excludedChambers.empty()) {
ATH_MSG_DEBUG(
" Using exclusion list for cleaning"); }
330 ATH_MSG_DEBUG(
" corrupt first entry, cannot perform fit: eta hits " << entry1.
etaHits().size());
334 ATH_MSG_DEBUG(
" corrupt second entry, cannot perform fit: eta hits " << entry2.
etaHits().size());
344 bool entry1IsFirst = sortMeasurements(entry1.
hits().front(), entry2.
hits().front());
348 if (distToSecond < 0) entry1IsFirst =
false;
380 <<
" second entry: ";
400 ATH_MSG_DEBUG(
" extracting hits from hit list, using " << (usePreciseHits ?
"precise measurements" :
"broad measurements"));
404 unsigned int nhits = hitList.size();
417 bool currentMeasPhi =
false;
430 <<
") is not a muon Identifier, continuing");
436 fitterData.
stations.insert(stIndex);
439 firstStation = stIndex;
442 const bool measuresPhi = hit->info().measuresPhi;
447 stCount.first += isSmall;
448 stCount.second += !isSmall;
455 const Trk::MeasurementBase* meas = usePreciseHits ? &hit->preciseMeasurement() : &hit->broadMeasurement();
461 fitterData.
phiHits.push_back(meas);
463 fitterData.
etaHits.push_back(meas);
468 if (usePreciseHits &&
m_idHelperSvc->isMdt(
id) && std::abs(rDrift) < 0.01 && rError > 4.) {
478 currentChIndex = chIndex;
479 currentMeasPhi = measuresPhi;
481 }
else if (currentChIndex == chIndex && currentMeasPhi == measuresPhi) {
484 currentChIndex = chIndex;
485 currentMeasPhi = measuresPhi;
502 if (fitterData.
etaHits.size() < 7) {
518 if (nphiConstraints >= 2) {
522 ATH_MSG_VERBOSE(
" Special treatment of the forward region: adding fake at ip ");
529 std::unique_ptr<Amg::Vector3D> overlapPos;
530 std::unique_ptr<const Amg::Vector3D> phiPos;
535 overlapPos = std::make_unique<Amg::Vector3D>(1., 1., 1.);
536 double phi = fitterData.
avePhi;
550 phiPos = std::make_unique<Amg::Vector3D>(fitterData.
startPars->momentum());
552 phiPos = std::make_unique<Amg::Vector3D>(*overlapPos);
557 if (fitterData.
stations.size() == 1)
560 msg(
MSG::VERBOSE) <<
" multi station fit with SL overlap, using overlapPos " << *overlapPos <<
endmsg;
562 msg(
MSG::VERBOSE) <<
" multi station fit, SL overlap not in same station, using overlapPos " << *overlapPos <<
endmsg;
568 if (fitterData.
phiHits.empty()) {
576 ATH_MSG_VERBOSE(
" Special treatment for tracks with one station, a SL overlap and no phi hits ");
581 if (!
result.goodMatch()) {
586 double locx1 =
result.segmentResult1.positionInTube1;
589 Trk::AtaPlane segPars1(locx1, locy1,
result.phiResult.segmentDirection1.phi(),
result.phiResult.segmentDirection1.theta(),
592 std::unique_ptr<Trk::TrackParameters> exPars1 =
m_propagator->propagate(ctx,
597 std::unique_ptr<Trk::MeasurementBase> fake =
600 fitterData.
phiHits.push_back(fake.get());
603 fitterData.
garbage.push_back(std::move(fake));
609 double locx2 =
result.segmentResult2.positionInTube1;
612 Trk::AtaPlane segPars2(locx2, locy2,
result.phiResult.segmentDirection2.phi(),
result.phiResult.segmentDirection2.theta(),
620 std::unique_ptr<Trk::MeasurementBase> fake =
623 fitterData.
phiHits.push_back(fake.get());
626 fitterData.
garbage.push_back(std::move(fake));
632 }
else if (nphiConstraints == 0 || (fitterData.
stations.size() == 1) ||
637 overlapPos.get(), phiPos.get(), 100.);
639 fitterData.
phiHits.push_back(fake.get());
642 fitterData.
garbage.push_back(std::move(fake));
648 overlapPos.get(), phiPos.get(), 100.);
650 fitterData.
phiHits.push_back(fake.get());
653 fitterData.
garbage.push_back(std::move(fake));
659 ATH_MSG_VERBOSE(
" Special treatment for tracks with one SL overlap and no phi hits ");
664 for (;
it != it_end; ++
it) {
665 if (
it->second.first &&
it->second.second) {
666 overlapStation =
it->first;
677 ATH_MSG_WARNING(
" unexpected condition, first measurement has no identifier ");
681 if (overlapStation == firstSt) {
686 overlapPos.get(), phiPos.get(), 100.);
688 fitterData.
phiHits.push_back(fake.get());
691 fitterData.
garbage.push_back(std::move(fake));
697 overlapPos.get(), phiPos.get(), 100.);
699 fitterData.
phiHits.push_back(fake.get());
702 fitterData.
garbage.push_back(std::move(fake));
712 double distFirstEtaPhi =
714 double distLastEtaPhi = (fitterData.
measurements.back()->globalPosition() - fitterData.
phiHits.back()->globalPosition()).
mag();
718 phiPos = std::make_unique<Amg::Vector3D>(fitterData.
phiHits.back()->globalPosition());
719 ATH_MSG_VERBOSE(
" using pointing constraint to calculate fake phi hit ");
723 const Trk::Surface *firstmdtsurf =
nullptr, *lastmdtsurf =
nullptr;
727 for (; hitit != fitterData.
hitList.end(); hitit++) {
728 if ((**hitit).info().measuresPhi)
break;
730 firstmdtsurf = &(**hitit).measurement().associatedSurface();
735 hitit = fitterData.
hitList.end();
737 for (; hitit != fitterData.
hitList.begin(); hitit--) {
738 if ((**hitit).info().measuresPhi)
break;
740 lastmdtsurf = &(**hitit).measurement().associatedSurface();
741 lastmdtpar = &(**hitit).parameters();
749 bool phifromextrapolation =
false;
752 const Trk::Surface *firstphisurf =
nullptr, *lastphisurf =
nullptr;
754 if (!fitterData.
phiHits.empty()) {
755 firstphisurf = &fitterData.
phiHits.front()->associatedSurface();
756 lastphisurf = &fitterData.
phiHits.back()->associatedSurface();
757 firstphinormal = firstphisurf->
normal();
758 lastphinormal = lastphisurf->normal();
759 if (firstphinormal.dot(startpar.
momentum()) < 0) firstphinormal = -firstphinormal;
760 if (lastphinormal.dot(startpar.
momentum()) < 0) lastphinormal = -lastphinormal;
762 if (lastmdtsurf && (!firstphisurf || (lastmdtsurf->center() - lastphisurf->center()).dot(lastphinormal) > 1000)) {
763 ATH_MSG_VERBOSE(
" Adding fake at last hit: dist first phi/first eta " << distFirstEtaPhi <<
" dist last phi/last eta "
765 std::unique_ptr<Trk::MeasurementBase> fake{};
768 std::unique_ptr<Trk::TrackParameters> mdtpar{};
772 mdtpar =
m_propagator->propagateParameters(ctx, startpar, *lastmdtsurf,
778 fake = std::make_unique<Trk::PseudoMeasurementOnTrack>(
781 mdtpar->associatedSurface());
788 fitterData.
phiHits.push_back(fake.get());
791 fitterData.
garbage.push_back(std::move(fake));
795 if (firstmdtsurf && (!firstphisurf || (firstmdtsurf->
center() - firstphisurf->
center()).dot(firstphinormal) < -1000)) {
796 ATH_MSG_VERBOSE(
" Adding fake at first hit: dist first phi/first eta " << distFirstEtaPhi <<
" dist last phi/last eta "
798 std::unique_ptr<Trk::MeasurementBase> fake{};
799 if (phifromextrapolation) {
801 auto mdtpar =
m_propagator->propagateParameters(ctx, startpar,
806 fake = std::make_unique<Trk::PseudoMeasurementOnTrack>(
809 mdtpar->associatedSurface());
815 fitterData.
phiHits.insert(fitterData.
phiHits.begin(), fake.get());
818 fitterData.
garbage.push_back(std::move(fake));
827 double errPos)
const {
831 ATH_MSG_WARNING(
" Cannot create fake phi hit from a measurement without Identifier ");
861 std::optional<Amg::Vector2D> lpos = std::nullopt;
876 <<
" theta " <<
dir.theta() <<
" seed: phi " << phiPos->phi() <<
" theta "
898 double halfLength = ly < 0 ? halfLengthL : halfLengthR;
899 bool shiftedPos =
false;
901 if (std::abs(ly) > halfLength) {
903 ly = ly < 0 ? -halfLength : halfLength;
904 ATH_MSG_DEBUG(
" extrapolated position outside detector, shifting it back: " << lyold <<
" size " << halfLength <<
" new pos "
906 if (phiPos && std::abs(lyold) - halfLength > 1000.) {
922 std::optional<Amg::Vector2D> loverlapPos = surf.
globalToLocal(*overlapPos, 3000.);
926 double lyfake = halfLength - 50.;
927 if (ly < 0.) lyfake *= -1.;
929 errPos = FiftyOverSqrt12;
937 double phi_min = fakePos_min.phi();
938 double phi_plus = fakePos_plus.phi();
939 double phi_overlap = phiPos->phi();
940 ATH_MSG_VERBOSE(
" fake lpos " << lyfake <<
" ch half length " << halfLength <<
" phi+ " << phi_plus <<
" phi- " << phi_min
941 <<
" phi overlap " << phi_overlap <<
" err " << errPos);
946 halfLength = ly < 0 ? halfLengthL : halfLengthR;
947 if (std::abs(ly) > halfLength) { ly = ly < 0 ? -halfLength : halfLength; }
948 ATH_MSG_VERBOSE(
" fake from overlap: lpos " << ly <<
" ch half length " << halfLength <<
" overlapPos " << *overlapPos);
955 cov(0, 0) = errPos * errPos;
956 std::unique_ptr<Trk::PseudoMeasurementOnTrack> fake = std::make_unique<Trk::PseudoMeasurementOnTrack>(std::move(locPars),
957 std::move(
cov), surf);
964 <<
" errpr " << errPos <<
" phi " << fakePos.phi() <<
endmsg;
966 if (!shiftedPos && !overlapPos && phiPos && std::abs(phiPos->phi() - fakePos.phi()) > 0.01) {
969 ATH_MSG_WARNING(
" Problem calculating fake from IP seed: phi fake " << fakePos.phi() <<
" IP phi " << phiPos->phi()
970 <<
" local meas pos " << locMeas);
984 unsigned int nphiConstraints = fitterData.
phiHits.size();
994 double distanceMin = 400.;
997 if (fitterData.
phiHits.size() > 1) {
1001 double distFirstEtaPhi =
1002 (fitterData.
measurements.front()->globalPosition() - fitterData.
phiHits.front()->globalPosition()).
mag();
1003 double distLastEtaPhi = (fitterData.
measurements.back()->globalPosition() - fitterData.
phiHits.back()->globalPosition()).
mag();
1009 distance = fitterData.
hasEndcap ? std::abs(globalDistance.z()) : globalDistance.perp();
1012 if (distance < distanceMin || distFirstEtaPhi > 1000 || distLastEtaPhi > 1000) {
1013 nphiConstraints -= fitterData.
phiHits.size();
1014 nphiConstraints += 1;
1015 ATH_MSG_VERBOSE(
" distance between phi hits too small, updating phi constraints ");
1017 ATH_MSG_VERBOSE(
" distance between phi hits sufficient, no fake hits needed ");
1022 <<
" | nphi hits | distance | SL station overlaps | small ch | large ch | nphiConstraints " << std::endl
1023 << std::setw(12) << fitterData.
phiHits.size() << std::setw(11) << (
int)
distance << std::setw(22)
1028 return nphiConstraints;
1032 std::map<MuonStationIndex::StIndex, StationPhiData> stationDataMap;
1038 if (
summary->muonTrackSummary()) {
1039 muonSummary = *
summary->muonTrackSummary();
1051 std::vector<Trk::MuonTrackSummary::ChamberHitSummary>::const_iterator chit = muonSummary.
chamberHitSummary().begin();
1052 std::vector<Trk::MuonTrackSummary::ChamberHitSummary>::const_iterator chit_end = muonSummary.
chamberHitSummary().end();
1053 for (; chit != chit_end; ++chit) {
1058 if (chit->isMdt()) {
1064 if (chit->phiProjection().nhits) ++stData.
nphiHits;
1068 unsigned int phiConstraints = 0;
1069 unsigned int stationsWithSmall = 0;
1070 unsigned int stationsWithLarge = 0;
1074 for (; sit != sit_end; ++sit) {
1083 ++stationsWithSmall;
1085 ++stationsWithLarge;
1088 if (stationsWithSmall > 0 && stationsWithLarge > 0) { ++phiConstraints; }
1090 return phiConstraints;
1095 if (!mdtDetEl){
return std::make_pair(0., 0.); }
1098 return std::make_pair(halfLength, halfLength);
1102 if (!cscDetEl) {
return std::make_pair(0., 0.);}
1103 const double halfLenghth = 0.5 * cscDetEl->
stripLength(
id);
1104 return std::make_pair(halfLenghth, halfLenghth);
1107 if (!rpcDetEl) {
return std::make_pair(0, 0);}
1108 const double halfLength = 0.5 * rpcDetEl->
StripLength(
false);
1109 return std::make_pair(halfLength, halfLength);
1112 if (!tgcDetEl) {
return std::make_pair(0.,0.);}
1114 return std::make_pair(halfLength, halfLength);
1117 if (!stgcDetEl || !stgcDetEl->
getDesign(
id)) {
return std::make_pair(0.,0.);}
1119 return std::make_pair(halfLength, halfLength);
1128 return std::make_pair(0.,0.);
1131 double phiStart = fitterData.
etaHits.front()->globalPosition().phi();
1132 double phiOffset = 0.;
1134 double phiRange2 = 0.25 *
M_PI;
1136 phiOffset = 2 *
M_PI;
1137 else if (phiStart > -phiRange2 && phiStart < phiRange2)
1140 double phiMin = -999.;
1141 double phiMax = 999.;
1168 double phiLeft = gposLeft.phi();
1172 double phiRight = gposRight.phi();
1174 if (phiOffset > 1.5 *
M_PI) {
1175 if (phiLeft < 0) phiLeft = phiOffset + phiLeft;
1176 if (phiRight < 0) phiRight = phiOffset + phiRight;
1177 }
else if (phiOffset > 0.) {
1178 phiLeft = phiLeft + phiOffset;
1179 phiRight = phiRight + phiOffset;
1182 bool leftSmaller = phiLeft < phiRight;
1184 double phiMinMeas = leftSmaller ? phiLeft : phiRight;
1185 double phiMaxMeas = leftSmaller ? phiRight : phiLeft;
1186 double orgPhiMin = phiMinMeas;
1187 double orgPhiMax = phiMaxMeas;
1189 if (phiOffset > 1.5 *
M_PI) {
1190 if (orgPhiMin >
M_PI) orgPhiMin = orgPhiMin - phiOffset;
1191 if (orgPhiMax >
M_PI) orgPhiMax = orgPhiMax - phiOffset;
1192 }
else if (phiOffset > 0.) {
1193 orgPhiMin = orgPhiMin - phiOffset;
1194 orgPhiMax = orgPhiMax - phiOffset;
1197 if (phiMinMeas > phiMin) { phiMin = phiMinMeas; }
1198 if (phiMaxMeas < phiMax) { phiMax = phiMaxMeas; }
1200 if (phiMin < -998 || phiMax > 998) {
1205 double diffPhi = phiMax - phiMin;
1206 double avePhi = phiMin + 0.5 * diffPhi;
1208 ATH_MSG_VERBOSE(
"Phi ranges: min " << phiMin <<
" max " << phiMax <<
" average phi " << avePhi);
1217 if (!fitterData.
phiHits.empty()) {
1219 const double minPhi =
std::min(phiMin, phiMax);
1220 const double maxPhi =
std::max(phiMin, phiMax);
1222 if (phiOffset > 1.5 *
M_PI) {
1223 if (phiMeas < 0.) phiMeas = phiOffset + phiMeas;
1224 }
else if (phiOffset > 0.) {
1225 phiMeas = phiMeas + phiOffset;
1227 double diffMin = phiMeas - minPhi;
1228 double diffMax = phiMeas - maxPhi;
1229 if (diffMin < 0. || diffMax > 0.) {
1231 ATH_MSG_VERBOSE(
" Phi hits inconsistent with min/max, rejecting track: phi meas " << phiMeas);
1238 if (phiOffset > 1.5 *
M_PI) {
1239 if (phiMax >
M_PI) phiMax = phiMax - phiOffset;
1240 if (phiMin >
M_PI) phiMin = phiMin - phiOffset;
1241 if (avePhi >
M_PI) avePhi = avePhi - phiOffset;
1242 }
else if (phiOffset > 0.) {
1243 phiMax = phiMax - phiOffset;
1244 phiMin = phiMin - phiOffset;
1245 avePhi = avePhi - phiOffset;
1248 fitterData.
avePhi = avePhi;
1249 fitterData.
phiMin = phiMin;
1250 fitterData.
phiMax = phiMax;
1266 return std::shared_ptr<const MuonSegment> {segEntry->
segment, Unowned()};
1273 return entry.entryPars().charge() /
entry.entryPars().momentum().mag();
1287 std::shared_ptr<const MuonSegment> segFirst =
segmentFromEntry(ctx, firstEntry);
1289 ATH_MSG_WARNING(
" failed to get segment for first entry, this should not happen ");
1293 std::shared_ptr<const MuonSegment> segSecond =
segmentFromEntry(ctx, secondEntry);
1295 ATH_MSG_WARNING(
" failed to get segment for second entry, this should not happen ");
1299 std::vector<const MuonSegment*> segments{segFirst.get(), segSecond.get()};
1332 if (!
result.goodMatch()) {
1336 double overlapPhi =
result.phiResult.segmentDirection1.phi();
1345 if (difPos.y() > 0) difPos *= -1.;
1349 if (std::abs(dphi) > 0.2) {
1350 ATH_MSG_DEBUG(
"Large diff between phi of segment direction and of position "
1352 return difPos.phi();
1366 Amg::Vector3D difPos = etaHits.back()->globalPosition() - etaHits.front()->globalPosition();
1367 if (difPos.mag() > 3000) {
1368 ATH_MSG_DEBUG(
"Seeding phi using average phi of eta hits ");
1377 if (phiHits.empty()) {
1380 return fitterData.
avePhi;
1384 if (phiHits.size() == 1) {
return phiHits.front()->globalPosition().phi(); }
1399 MeasCit hit = phiHits.begin();
1400 MeasCit hit_end = phiHits.end();
1402 for (; hit != hit_end; ++hit) avePos += (*hit)->globalPosition();
1403 avePos /= phiHits.size();
1407 Amg::Vector3D difPos = phiHits.back()->globalPosition() - phiHits.front()->globalPosition();
1416 if (etaHits.empty()) {
1423 theta =
entry.entryPars().momentum().theta();
1426 if (etaHits.size() == 1) {
1427 theta = etaHits.front()->globalPosition().theta();
1430 Amg::Vector3D difPos = etaHits.back()->globalPosition() - etaHits.front()->globalPosition();
1431 theta = difPos.theta();
1441 std::unique_ptr<Trk::Perigee> startPars{
nullptr};
1473 if (dir1.dot(point2 - point1) < 0) {
1478 trkEntry1 =
dynamic_cast<const MuPatTrack*
>(entry1);
1479 trkEntry2 =
dynamic_cast<const MuPatTrack*
>(entry2);
1485 double dist1 = -1, dist2 = -1;
1486 MuPatHitPtr firstphi1{
nullptr}, lastphi1{
nullptr}, firstphi2{
nullptr}, lastphi2{
nullptr};
1490 if (!firstphi1) firstphi1 = hit;
1494 for (
const MuPatHitPtr& hit : entry2->hitList()) {
1496 if (!firstphi2) firstphi2 = hit;
1500 if (firstphi1) dist1 = std::abs((firstphi1->measurement().globalPosition() - lastphi1->measurement().globalPosition()).dot(dir1));
1501 if (firstphi2) dist2 = std::abs((firstphi2->measurement().globalPosition() - lastphi2->measurement().globalPosition()).dot(dir2));
1502 if (dist2 > dist1) { bestentry = entry2; }
1533 startPars = std::make_unique<Trk::Perigee>(0, 0, phi, theta,
qOverP, persurf);
1540 fitterData.
startPars = std::move(startPars);
1549 std::unique_ptr<Trk::TrackParameters> garbage;
1559 exPars = garbage.get();
1568 double phi = exPars->
momentum().phi();
1569 double theta = exPars->
momentum().theta();
1580 std::unique_ptr<Trk::Perigee> perigee = std::make_unique<Trk::Perigee>(0, 0, phi, theta, qoverp, persurf);
1582 ATH_MSG_DEBUG( std::setprecision(5) <<
" creating perigee: phi " << phi <<
" theta " << theta <<
" q*mom "
1583 << perigee->charge() * perigee->momentum().mag() <<
" r " << perigee->position().perp() <<
" z "
1584 << perigee->position().z() <<
" input q*mom " << firstPars.
charge() * firstPars.
momentum().mag());
1607 if (
hits.empty())
return nullptr;
1608 std::unique_ptr<Trk::Perigee> perigee{};
1609 ATH_MSG_VERBOSE(std::setprecision(5) <<
" track start parameter: phi " << startPars.momentum().phi() <<
" theta "
1610 << startPars.momentum().theta() <<
" q*mom " << startPars.charge() * startPars.momentum().mag()
1611 <<
" r " << startPars.position().perp() <<
" z " << startPars.position().z() << std::endl
1612 <<
" start par is a perigee "
1613 <<
" partHypo " << partHypo << std::endl
1619 double dist = distAlongPars(startPars, *
hits.front());
1622 ATH_MSG_DEBUG(
" start parameters after first hit, shifting them.... ");
1625 pars = perigee.get();
1635 ATH_MSG_VERBOSE(
"fit: " << (prefit ?
"prefit" :
"fit") <<
"track with hits: " <<
hits.size() << std::endl
1664 double difMom = startPars.momentum().mag() - pp->momentum().mag();
1665 if (std::abs(difMom) > 5000.) {
1666 ATH_MSG_DEBUG(
" absolute difference in momentum too large, refitting track. Dif momentum= " << difMom);
1669 if (refittedTrack) {
1670 track.swap(refittedTrack);
1675 ATH_MSG_DEBUG(
" refitted track fit perigee: r " << pp->position().perp() <<
" z " << pp->position().z());
1687 const std::vector<const Trk::PrepRawData*>& patternPhiHits)
const {
1693 std::vector<const Trk::RIO_OnTrack*> rots;
1694 std::vector<std::unique_ptr<const Trk::RIO_OnTrack>> rotsNSW;
1695 std::set<Identifier>
ids;
1696 std::set<MuonStationIndex::StIndex> stations;
1697 rots.reserve(phiHits.size() + 5);
1706 rots.push_back(rot);
1713 rots.push_back(mit);
1714 ids.insert(mit->identify());
1716 stations.insert(stIndex);
1719 ATH_MSG_WARNING(
" phi hits should be ROTs or competing ROTs! Dropping hit ");
1723 if (rots.empty())
return false;
1726 ATH_MSG_DEBUG(
" too many phi hits, not running cleaning " << rots.size());
1737 std::vector<const Trk::PrepRawData*> roadPhiHits;
1739 return !(ids.count(prd->identify()) ||
1741 m_idHelperSvc->isCsc(prd->identify()) || m_idHelperSvc->issTgc(prd->identify()));
1746 ATH_MSG_VERBOSE(
" too many pattern phi hits, not adding any " << roadPhiHits.size());
1747 roadPhiHits.clear();
1750 if (!roadPhiHits.empty()) {
1752 std::vector<const Trk::PrepRawData*>::const_iterator pit = roadPhiHits.begin();
1753 std::vector<const Trk::PrepRawData*>::const_iterator pit_end = roadPhiHits.end();
1754 for (; pit != pit_end; ++pit) {
1756 if (pit + 1 != pit_end)
1764 std::vector<std::unique_ptr<const Trk::MeasurementBase>> newMeasurements{
m_phiHitSelector->select_rio(
momentum, rots, roadPhiHits)};
1766 newMeasurements.insert(newMeasurements.end(),
1767 std::make_move_iterator(rotsNSW.begin()),
1768 std::make_move_iterator(rotsNSW.end()));
1772 if (newMeasurements.empty()) {
1773 ATH_MSG_DEBUG(
" empty list of phi hits return from phi hit selector: input size " << phiHits.size());
1779 constexpr
double maxDistCut = 800.;
1780 std::vector<const Trk::MeasurementBase*> measurementsToBeAdded{};
1781 measurementsToBeAdded.reserve(newMeasurements.size());
1782 for (std::unique_ptr<const Trk::MeasurementBase>& meas : newMeasurements) {
1784 if (!
id.is_valid()) {
1791 if (fitterData.
hitList.empty()) {
1798 double dist = distAlongPars(fitterData.
hitList.front()->parameters(), *meas);
1799 if (dist < -maxDistCut) {
1800 ATH_MSG_VERBOSE(
" discarded phi hit, distance to first hit too large " << dist);
1806 double distBack = distAlongPars(fitterData.
hitList.back()->parameters(), *meas);
1807 if (distBack > maxDistCut) {
1808 ATH_MSG_VERBOSE(
" discarded phi hit, distance to last hit too large " << distBack);
1812 ATH_MSG_VERBOSE(
" new phi hit, distance from start pars " << dist <<
" distance to last pars " << distBack);
1814 measurementsToBeAdded.push_back(meas.get());
1815 fitterData.
garbage.push_back(std::move(meas));
1827 if (!measurementsToBeAdded.empty()) {
1840 const std::set<Identifier>& excludedChambers)
const {
1848 std::unique_ptr<Trk::Track> cleanTrack;
1849 if (excludedChambers.empty())
1852 ATH_MSG_DEBUG(
" Cleaning with exclusion list " << excludedChambers.size());
1856 ATH_MSG_DEBUG(
" Cleaner returned a zero pointer, reject track ");
1871 const double p =
pars.momentum().mag();
1873 ATH_MSG_DEBUG(
" momentum below threshold: momentum " <<
pars.momentum().mag() <<
" p " <<
pars.momentum().perp());
1882 if (segEntry && segEntry->
segment) {
1883 if (
entry.hasSmallChamber() &&
entry.hasLargeChamber()) {
1884 ATH_MSG_DEBUG(
" Segment with SL overlap, cannot perform cleaning ");
1900 float tubeRadius = 14.6;
1906 if (!mdt) {
continue; }
1936 dcs.push_back(dcOnTrack);
1944 <<
" local parameters " << lpos.y() <<
" " << lpos.z() <<
" phi " << angleYZ <<
" with "
1945 << dcs.size() <<
" hits ");
1953 segment.hitsOnTrack(dcs.size());
1955 <<
" " <<
segment.line().y0() <<
" phi " <<
segment.line().phi());
1957 bool hasDroppedHit =
false;
1958 unsigned int dropDepth = 0;
1960 bool success =
finder.dropHits(
segment, hasDroppedHit, dropDepth);
1966 if (dcs.size() ==
segment.ndof() + 2) {
1968 }
else if (dcs.size() !=
segment.ndof() + 3) {
1969 ATH_MSG_DEBUG(
" more than one hit removed, keeping old segment ");
1978 removedIdentifiers.insert(dcit.rot()->identify());
1985 if (fitterData.
startPars->momentum().mag() < 4000.)
return;
1987 std::set<Identifier> removedIdentifiers;
1991 ATH_MSG_DEBUG(
" removing hits " << removedIdentifiers.size());
1993 for (
const Identifier&
id : removedIdentifiers) {
2003 if (!oldTSOT)
return std::make_pair<std::unique_ptr<Trk::Track>, std::unique_ptr<Trk::Track>>(
nullptr,
nullptr);
2008 bool atIP = std::abs(perigee->position().dot(perigee->momentum().unit())) < 10;
2010 ATH_MSG_DEBUG(
" track extressed at perigee, cannot split it ");
2011 return std::make_pair<std::unique_ptr<Trk::Track>, std::unique_ptr<Trk::Track>>(
nullptr,
nullptr);
2016 unsigned int nperigees(0);
2019 for (;
tit != tit_end; ++
tit) {
2024 if (nperigees != 2) {
2025 ATH_MSG_DEBUG(
" Number of perigees is not one, cannot split it " << nperigees);
2026 return std::make_pair<std::unique_ptr<Trk::Track>, std::unique_ptr<Trk::Track>>(
nullptr,
nullptr);
2029 struct TrackContent {
2030 TrackContent() : firstParameters(
nullptr), tsos(),
track() {}
2032 std::vector<const Trk::TrackStateOnSurface*> tsos;
2033 std::unique_ptr<Trk::Track>
track;
2034 std::set<MuonStationIndex::StIndex> stations;
2038 TrackContent firstTrack;
2039 firstTrack.tsos.reserve(oldTSOT->
size());
2041 TrackContent secondTrack;
2042 secondTrack.tsos.reserve(oldTSOT->
size());
2045 TrackContent* currentTrack = &firstTrack;
2052 tit_end = oldTSOT->
end();
2053 for (;
tit != tit_end; ++
tit) {
2063 if (nperigees == 2) {
2064 ATH_MSG_DEBUG(
" found second perigee, switch to second track");
2065 currentTrack = &secondTrack;
2067 }
else if (nperigees > 2) {
2073 if (nperigees == 1) {
ATH_MSG_VERBOSE(
" state between the two perigees "); }
2076 if (!currentTrack->firstParameters) {
2078 currentTrack->firstParameters =
pars;
2084 currentTrack->tsos.push_back(*
tit);
2092 currentTrack->tsos.push_back(*
tit);
2100 currentTrack->tsos.push_back(*
tit);
2104 if (nperigees == 1)
ATH_MSG_WARNING(
" found muon measurement inbetween the two perigees, this should not happen ");
2111 currentTrack->tsos.push_back(*
tit);
2114 if (firstTrack.firstParameters)
2115 ATH_MSG_DEBUG(
" first track content: states " << firstTrack.tsos.size() <<
" stations " << firstTrack.stations.size() <<
endmsg
2116 <<
" first pars " <<
m_printer->print(*firstTrack.firstParameters));
2118 else if (secondTrack.firstParameters)
2119 ATH_MSG_DEBUG(
" second track content: states " << secondTrack.tsos.size() <<
" stations " << secondTrack.stations.size()
2120 <<
endmsg <<
" first pars " <<
m_printer->print(*secondTrack.firstParameters));
2123 if ((firstTrack.firstParameters && firstTrack.stations.size() > 1) &&
2124 (secondTrack.firstParameters && secondTrack.stations.size() > 1)) {
2125 ATH_MSG_DEBUG(
" track candidate can be split, trying to fit split tracks ");
2127 firstTrack.track =
fitSplitTrack(ctx, *firstTrack.firstParameters, firstTrack.tsos);
2128 if (firstTrack.track) {
2131 secondTrack.track =
fitSplitTrack(ctx, *secondTrack.firstParameters, secondTrack.tsos);
2133 if (secondTrack.track) {
2138 firstTrack.track.reset();
2145 return std::make_pair<std::unique_ptr<Trk::Track>, std::unique_ptr<Trk::Track>>(std::move(firstTrack.track),
2146 std::move(secondTrack.track));
2150 const std::vector<const Trk::TrackStateOnSurface*>& tsos)
const {
2152 double phi = startPars.
momentum().phi();
2153 double theta = startPars.
momentum().theta();
2157 std::unique_ptr<Trk::Perigee> perigee = std::make_unique<Trk::Perigee>(0, 0, phi, theta, qoverp, persurf);
2159 auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
2160 trackStateOnSurfaces->reserve(tsos.size() + 1);
2165 std::unique_ptr<Trk::Track>
track = std::make_unique<Trk::Track>(
trackInfo, std::move(trackStateOnSurfaces),
nullptr);
2170 ATH_MSG_DEBUG(
"Track has sufficient phi constraints, fitting ");
2178 std::vector<const Trk::TrackStateOnSurface*>::const_iterator
tit = tsos.begin();
2179 std::vector<const Trk::TrackStateOnSurface*>::const_iterator tit_end = tsos.end();
2180 for (;
tit != tit_end; ++
tit) {
2182 if (!(*tit)->trackParameters())
continue;
2185 if (!meas)
continue;
2191 if (!firstMeas) firstMeas = *
tit;
2199 ATH_MSG_WARNING(
" failed to find first MDT measurement with track parameters");
2204 ATH_MSG_WARNING(
" failed to find second MDT measurement with track parameters");
2208 if (firstMeas == lastMeas) {
2209 ATH_MSG_WARNING(
" first MDT measurement with track parameters equals to second");
2219 ATH_MSG_DEBUG(
"Track has one phi constraints, adding second: dist to first " << distFirst <<
" dist to second "
2222 if (distFirst < distSecond) {
2223 positionFirstFake = lastMeas;
2225 positionFirstFake = firstMeas;
2229 ATH_MSG_DEBUG(
"Track has no phi constraints, adding one at beginning and one at the end of the track ");
2231 positionFirstFake = firstMeas;
2232 positionSecondFake = lastMeas;
2236 auto uniquePerigee = std::make_unique<Trk::Perigee>(0, 0, phi, theta, qoverp, persurf);
2237 auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
2238 trackStateOnSurfaces->reserve(tsos.size() + 3);
2242 tit_end = tsos.end();
2243 for (;
tit != tit_end; ++
tit) {
2251 trackStateOnSurfaces->push_back((*tit)->clone());
2252 if (*
tit == positionFirstFake) {
2253 double fakeError = 100.;
2260 std::unique_ptr<Trk::MeasurementBase> fake =
2270 if (*
tit == positionSecondFake && positionSecondFake) {
2271 double fakeError = 100.;
2278 std::unique_ptr<Trk::MeasurementBase> fake =
2291 track = std::make_unique<Trk::Track>(
trackInfo, std::move(trackStateOnSurfaces),
nullptr);
2295 std::unique_ptr<Trk::Track> refittedTrack =
refit(ctx, *
track);
2298 return refittedTrack;