25 using MuonSegmentVec = std::vector<std::unique_ptr<Muon::MuonSegment>>;
47 std::stringstream sstr{};
52 constexpr
double minEtaNSW = 1.2;
53 constexpr
double maxEtaNSW = 2.8;
105 m_dir{
cl->detectorElement()->transform(
cl->identify()).linear() * Amg::Vector3D::UnitY()} {}
108 const std::array<double,2>& lengths) :
110 m_pos{seed[0].pos() + lengths[0] * seed[0].dir()} {
112 const Amg::Vector3D un_dir = (seed[1].pos() + lengths[1] *seed[1].dir() - m_pos);
113 m_dir = un_dir.unit()*(un_dir.z() * seed[0].pos().z() > 0 ? 1 : -1);
119 for (
const SeedMeasurement&
cl : seed) {
123 m_width /= std::sqrt(3);
127 m_parent{
parent}, m_pos{_leftM.pos()} {
135 m_parent{
parent}, m_pos{seg.globalPosition()},
m_dir{seg.globalDirection()} {
142 m_width /= std::sqrt(
size());
152 const double BdotD = B.dot(D);
155 if (std::abs(
divisor) < std::numeric_limits<double>::epsilon())
return diff.mag();
158 return (
beta * B - delta * D -
diff).mag();
161 if (!
size() || !meas)
return false;
162 if (
find(meas))
return true;
178 if (!prd)
return false;
180 if (!design)
return false;
182 const double dist = std::hypot(padDist.x(), padDist.y());
198 unsigned int only_th{0}, only_oth{0};
206 if (!
other.m_measurements[
m]) ++only_th;
207 if (!
other.m_phiMeasurements[
m]) ++only_th;
215 meas.reserve(
size());
222 return std::abs(a->globalPosition().z()) < std::abs(b->globalPosition().z());
229 return insert(std::move(meas));
235 if (!seed || meas.
distance() < seed.distance()) {
246 return m_calibClust.emplace(std::move(new_clust)).first->get();
258 declareInterface<IMuonNSWSegmentFinderTool>(
this);
273 ATH_MSG_FATAL(
"The muon should come from the IP && horizontally from the Calo..."<<
274 "We need to place a very good basball player at the calo exit to deflect the muon horizontally.");
275 return StatusCode::FAILURE;
278 return StatusCode::SUCCESS;
285 std::vector<const Muon::MuonClusterOnTrack*> muonClusters{};
286 muonClusters.reserve(cache.
inputClust.size());
288 [](
const std::unique_ptr<const MuonClusterOnTrack>&
cl){return cl.get();});
289 ATH_MSG_DEBUG(
"Entering MuonNSWSegmentFinderTool with " << muonClusters.size() <<
" clusters to be fit");
291 MuonSegmentVec out_segments{};
294 out_segments.insert(out_segments.end(), std::make_move_iterator(stereoSegs.begin()),
295 std::make_move_iterator(stereoSegs.end()));
298 auto dump_output = [&]() {
300 for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
309 std::vector<const Muon::MuonClusterOnTrack*> clustPostStereo{};
311 std::array<std::set<Identifier>, 16> masked_segs{};
312 for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
319 if (!out_segments.empty()) {
320 clustPostStereo.reserve(muonClusters.size());
325 const std::vector<const Muon::MuonClusterOnTrack*>& segmentInput = !out_segments.empty() ? clustPostStereo : muonClusters;
330 MuonSegmentVec precSegs =
find3DSegments(ctx, segmentInput, etaSegs);
331 out_segments.insert(out_segments.end(),
332 std::make_move_iterator(precSegs.begin()),
333 std::make_move_iterator(precSegs.end()));
343 for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
344 std::vector<const MuonClusterOnTrack*> seg_hits{};
345 seg_hits.reserve(seg->containedMeasurements().size());
348 if (clus) seg_hits.push_back(clus);
351 for (
int iWedge{1}; iWedge<=4 ; ++iWedge) {
354 if ( quad_hits.size () < 2 || ((iWedge == 2 || iWedge == 3) && quad_hits.size() < 4))
continue;
355 std::vector<const Trk::MeasurementBase*> fit_meas{};
356 std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{
ipConstraint(ctx)};
357 if (pseudoVtx) fit_meas.push_back(pseudoVtx.get());
358 std::copy(quad_hits.begin(), quad_hits.end(), std::back_inserter(fit_meas));
360 const Trk::Surface& surf = quad_hits.front()->associatedSurface();
365 if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
368 std::unique_ptr<Trk::Track> segtrack =
fit(ctx, fit_meas, startpar);
369 if (!segtrack)
continue;
374 <<
"position: "<<
to_string(seg->globalPosition())<< std::endl
375 <<
"direction: "<<
to_string(seg->globalDirection())<< std::endl
376 <<
m_printer->print(seg->containedMeasurements()));
378 cache.
quadSegs.emplace_back(std::move(seg));
385 const std::vector<const Muon::MuonClusterOnTrack*>& allClusts,
386 int singleWedge)
const {
393 for (
MeasVec& hitsInLayer : orderedClust) hitsInLayer =
vetoBursts(std::move(hitsInLayer));
394 orderedClust.erase(std::remove_if(orderedClust.begin(), orderedClust.end(),
395 [](
const MeasVec&
vec) { return vec.empty(); }),
397 if (orderedClust.empty())
return {};
401 if (seeds.empty())
return {};
407 std::vector<const Trk::MeasurementBase*> fit_meas{};
409 std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{
ipConstraint(ctx)};
410 if (pseudoVtx) fit_meas.push_back(pseudoVtx.get());
412 std::copy(calib_clust.begin(), calib_clust.end(), std::back_inserter(fit_meas));
414 const Trk::Surface& surf = calib_clust.front()->associatedSurface();
420 if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
425 std::unique_ptr<Trk::Track> segtrack =
fit(ctx, fit_meas, startpar);
426 if (segtrack) trackSegs.push_back(std::move(segtrack));
432 const std::vector<const Trk::MeasurementBase*>& fit_meas,
435 to_string(perigee.
momentum())<<
". Contained measurements in candidate: " << std::endl
443 std::unique_ptr<Trk::Track> cleanedTrack =
m_trackCleaner->clean(*segtrack, ctx);
463 const std::vector<const Muon::MuonClusterOnTrack*>& muonClusters,
464 int singleWedge)
const {
472 if (orderedClusters.size() < 4)
return {};
482 if (seed.size() < 4)
continue;
484 etaHitVec = seed.measurements();
502 if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
503 const auto startpar =
Trk::Perigee(perpos, gdir_seg, 0, perpos);
504 ATH_MSG_VERBOSE(
" start parameter " << perpos <<
" pp " << startpar.position() <<
" gd " << gdir_seg.unit() <<
" pp "
505 << startpar.momentum().unit());
508 hitsToTrack(ctx, etaHitVec, phiHitVec, startpar, segTrkColl);
525 MuonSegmentVec segments{};
526 std::unique_ptr<const TrackCollection> resolvedTracks(
m_ambiTool->process(&segTrkColl));
527 ATH_MSG_DEBUG(
"Resolved track candidates: old size " << segTrkColl.
size() <<
" new size " << resolvedTracks->
size());
530 for (
const Trk::Track* trk : *resolvedTracks) {
531 const auto* measurements = trk->measurementsOnTrack();
532 const bool has_eta = std::find_if(measurements->begin(), measurements->end(),
534 Identifier id = m_edmHelperSvc->getIdentifier(*meas);
535 return id.is_valid() && !m_idHelperSvc->measuresPhi(id);
536 }) != trk->measurementsOnTrack()->end();
537 if (!has_eta)
continue;
542 segments.emplace_back(std::move(seg));
551 const std::vector<const Muon::MuonClusterOnTrack*>& muonClusters,
552 MuonSegmentVec& etaSegs,
553 int singleWedge)
const {
554 MuonSegmentVec segments{};
557 ATH_MSG_DEBUG(
"After hit cleaning, there are " << phiClusters.size() <<
" phi clusters to be fit");
561 if (orderedWireClusters.size() + orderedPadClusters.size() < 2) {
562 ATH_MSG_DEBUG(
"Not enough phi hits present, cannot perform the 3D fit!");
563 segments.insert(segments.end(), std::make_move_iterator(etaSegs.begin()), std::make_move_iterator(etaSegs.end()));
572 bool triedWireSeed{
false};
573 std::vector<NSWSeed> seeds_WiresSTGC;
576 for (std::unique_ptr<Muon::MuonSegment>& etaSeg : etaSegs) {
581 std::vector<NSWSeed> seeds;
584 if (std::abs(etaSeg->globalPosition().eta()) < 2.4) {
585 if (!triedWireSeed) {
587 triedWireSeed =
true;
591 if (!seeds_WiresSTGC.empty()) {
592 seeds = seeds_WiresSTGC;
606 double etaSegLocX = etaSeg->localParameters()[
Trk::locX];
607 double etaSegLocXZ = etaSeg->localDirection().angleXZ();
627 if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
628 const Trk::Perigee startpar{perpos, gdir_seg, 0, perpos};
630 NSWSeed seed3D{
this, perpos, gdir_seg};
635 if (nPhiHits < 2)
continue;
637 MeasVec phiHitVec = seed3D.measurements();
642 if (
hitsToTrack(ctx, etaHitsCalibrated, phiHitVec, startpar, segTrkColl)) {
644 ATH_MSG_VERBOSE(
"Segment successfully fitted for wedge "<<singleWedge<<std::endl<<
651 if (!is3Dseg) { segments.push_back(std::move(etaSeg)); }
654 segments.insert(segments.end(), std::make_move_iterator(new_segs.begin()), std::make_move_iterator(new_segs.end()));
662 covVtx.setIdentity();
663 covVtx = errVtx * errVtx * covVtx;
679 covVtx(0, 0) = errVtx * errVtx;
704 std::vector<const Trk::MeasurementBase*> vecFitPts;
705 unsigned int nHitsEta = etaHitVec.size();
706 unsigned int nHitsPhi = phiHitVec.size();
709 std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{
ipConstraint(ctx)},
711 pseudoPhi1{
nullptr}, pseudoPhi2{
nullptr};
713 if (pseudoVtx) { vecFitPts.push_back(pseudoVtx.get()); }
714 if (pseudoVtxCalo) { vecFitPts.push_back(pseudoVtxCalo.get()); }
719 const unsigned int nMM = std::count_if(etaHitVec.begin(), etaHitVec.end(),
721 return m_idHelperSvc->isMM(hit->identify());
723 double errPos = (nMM) ? 1000. : 0.1;
725 cov(0, 0) = errPos * errPos;
727 pseudoPhi1 = std::make_unique<Trk::PseudoMeasurementOnTrack>(
Trk::LocalParameters(loc_pseudopars),
729 etaHitVec.front()->associatedSurface());
730 pseudoPhi2 = std::make_unique<Trk::PseudoMeasurementOnTrack>(
Trk::LocalParameters(loc_pseudopars),
732 etaHitVec.back()->associatedSurface());
735 vecFitPts.push_back(pseudoPhi1.get());
736 std::copy(etaHitVec.begin(), etaHitVec.end(), std::back_inserter(vecFitPts));
737 vecFitPts.push_back(pseudoPhi2.get());
738 ATH_MSG_VERBOSE(
"Fitting a 2D-segment track with " << nHitsEta <<
" Eta hits");
742 std::merge(phiHitVec.begin(), phiHitVec.end(), etaHitVec.begin(), etaHitVec.end(), std::back_inserter(vecFitPts),
744 double z1 = std::abs(c1->detectorElement()->center(c1->identify()).z());
745 double z2 = std::abs(c2->detectorElement()->center(c2->identify()).z());
748 ATH_MSG_VERBOSE(
"Fitting a 3D-segment track with " << nHitsEta <<
" Eta hits and " << nHitsPhi <<
" Phi hits");
752 std::unique_ptr<Trk::Track> segtrack =
fit(ctx, vecFitPts, startpar);
753 if (!segtrack)
return false;
754 segTrkColl.
push_back(std::move(segtrack));
760 const std::vector<const Muon::MuonClusterOnTrack*>& muonClusters,
int hit_sel,
int singleWedge )
const {
764 clusters.reserve(muonClusters.size());
766 if (!cluster)
continue;
767 if (singleWedge && singleWedge !=
wedgeNumber(cluster))
continue;
784 std::array<std::set<Identifier>,16> used_hits{};
794 const int channelType =
m_idHelperSvc->stgcIdHelper().channelType(
id);
799 std::set<Identifier>& lay_hits = used_hits[iorder];
800 if (lay_hits.count(
id))
continue;
802 orderedClusters[iorder].emplace_back(hit);
804 if (
nBad)
ATH_MSG_WARNING(
"Unable to classify " <<
nBad <<
" clusters by their layer since they are neither MM nor sTGC");
807 orderedClusters.erase(std::remove_if(orderedClusters.begin(), orderedClusters.end(),
808 [](
const MeasVec&
vec) { return vec.empty(); }),
809 orderedClusters.end());
812 for(
MeasVec& lays: orderedClusters){
814 return channel(a) < channel(b);
822 return orderedClusters;
828 std::vector<NSWSeed> seeds;
832 if (orderedClusters.size() < 4)
return seeds;
838 int seedingLayersL{0};
839 for (
unsigned int ilayerL{0}; (ilayerL < orderedClusters.size() && seedingLayersL <
m_nOfSeedLayers); ++ilayerL) {
840 bool usedLayerL{
false};
843 if (usePhi !=
m_idHelperSvc->measuresPhi(hitL->identify()))
continue;
848 int seedingLayersR{0};
849 for (
unsigned int ilayerR = orderedClusters.size() - 1; (ilayerR > ilayerL && seedingLayersR <
m_nOfSeedLayers);
851 bool usedLayerR{
false};
853 if (usePhi !=
m_idHelperSvc->measuresPhi(hitR->identify()))
continue;
857 const double eta = seed.dir().perp() > std::numeric_limits<float>::epsilon() ? std::abs(seed.dir().eta()): FLT_MAX;
858 if (eta < minEtaNSW || eta > maxEtaNSW) {
865 seeds.emplace_back(std::move(seed));
868 if (usedLayerR) ++seedingLayersR;
871 if (usedLayerL) ++seedingLayersL;
904 ATH_MSG_VERBOSE(
" getClustersOnSegment: layers " << orderedclusters.size());
906 for (
const MeasVec& surfHits : orderedclusters) {
911 ATH_MSG_VERBOSE(
" getClustersOnSegment: returning " << nHitsAdded <<
" hits ");
918 std::vector<NSWSeed> seeds;
920 if (orderedClusters.empty())
return seeds;
922 std::vector<std::vector<const Muon::sTgcPrepData*>> sTgcIP(4);
923 std::vector<std::vector<const Muon::sTgcPrepData*>> sTgcHO(4);
926 for (
int iml : {1, 2}) {
927 int il = (iml == 1) ? 0 : orderedClusters.size() - 1;
928 int iend = (iml == 1) ? orderedClusters.size() : -1;
929 int idir = (iml == 1) ? 1 : -1;
930 unsigned int nLayersWithHitMatch{0};
933 for (;
il != iend;
il += idir) {
934 double lastDistance{1000.};
935 if (nLayersWithHitMatch >= sTgcIP.size()) {
936 sTgcIP.resize(nLayersWithHitMatch + 1);
937 sTgcHO.resize(nLayersWithHitMatch + 1);
939 std::vector<const Muon::sTgcPrepData*>& matchedHits =
940 (iml == 1) ? sTgcIP.at(nLayersWithHitMatch) : sTgcHO.at(nLayersWithHitMatch);
945 if (!padHit)
continue;
951 if (!design)
continue;
963 double etaDistance = std::abs(padHit->
localPosition().y() - segLocPosOnSurf[1]);
964 if (etaDistance > 0.5 * chWidth)
continue;
965 ATH_MSG_DEBUG(
" etaDistance " << etaDistance <<
" between pad center and position on the pad.");
967 if (matchedHits.empty()) {
969 matchedHits.push_back(padHit);
971 }
else if (std::abs(etaDistance - lastDistance) < 0.001) {
973 matchedHits.push_back(padHit);
974 ATH_MSG_DEBUG(
" added etaDistance: " << etaDistance <<
" size " << matchedHits.size());
975 }
else if (etaDistance < lastDistance) {
978 matchedHits.push_back(padHit);
979 ATH_MSG_DEBUG(
" replacing best etaDistance with: " << etaDistance);
983 lastDistance = etaDistance;
986 if (!matchedHits.empty()) ++nLayersWithHitMatch;
991 if (!nLayersWithHitMatch)
return seeds;
996 std::vector<std::pair<double, double>> sTgcIP_phiRanges =
getPadPhiOverlap(sTgcIP);
997 std::vector<std::pair<double, double>> sTgcHO_phiRanges =
getPadPhiOverlap(sTgcHO);
1006 for (
const std::pair<double, double>& range1 : sTgcIP_phiRanges) {
1007 double midPhi1 = 0.5 * (range1.first + range1.second);
1010 surfPrdL1.localToGlobal(lp1, gpL1, gpL1);
1012 for (
const std::pair<double, double>& range2 : sTgcHO_phiRanges) {
1013 double midPhi2 = 0.5 * (range2.first + range2.second);
1016 surfPrdL2.localToGlobal(lp2, gpL2, gpL2);
1020 seeds.emplace_back(
this, gpL1, gDir);
1024 ATH_MSG_DEBUG(
" segmentSeedFromPads: seeds.size() " << seeds.size());
1031 std::vector<NSWSeed> seeds;
1032 std::array<unsigned int, 4>
layers{};
1033 unsigned int trials{0}, used_layers{0};
1035 constexpr
size_t lastMMLay = 11;
1036 std::vector<NSWSeed> laySeeds;
1039 std::stringstream sstr{};
1040 for (
int e4 =
std::min(lastMMLay, orderedClusters.size() -1);
e4 >= 3 ; --
e4) {
1042 for (
int e3 =
e4 -1 ;
e3 >= 2; --
e3) {
1048 const unsigned int old_trials = trials;
1050 if (old_trials == trials)
continue;
1052 used_layers += !laySeeds.empty();
1053 seeds.insert(seeds.end(), std::make_move_iterator(laySeeds.begin()),
1054 std::make_move_iterator(laySeeds.end()));
1057 sstr<<
" Attempts thus far "<<old_trials<<
" attempts now "<<trials<<
" --- "<<
e1<<
","<<
e2<<
","<<
e3<<
","<<
e4<<std::endl;
1059 sstr<<
"Layer: "<<lay<<
" number of measurements "<<orderedClusters[lay].size()<<std::endl;
1061 sstr<<
" **** "<<
print(meas)<<std::endl;
1063 sstr<<std::endl<<std::endl<<std::endl;
1070 if (trials > 100000) {
1073 ATH_MSG_VERBOSE(
"Out of "<<trials<<
" possible seeds, "<<seeds.size()<<
" were finally built. Used in total "<<used_layers<<
" layers");
1077 #if defined(FLATTEN)
1081 std::array<unsigned int,4> selLayers,
1082 unsigned int& trial_counter)
const {
1083 std::vector<NSWSeed> seeds{};
1085 std::array<unsigned int, 4> lay_ord{};
1086 for (
size_t s = 0;
s < selLayers.size(); ++
s) {
1087 unsigned int lay = selLayers[
s];
1095 else lay_ord[
s] = 3;
1097 auto swap_strips = [&selLayers, &lay_ord] (
unsigned int i,
unsigned j){
1102 if (lay_ord[0] == lay_ord[1]){
1103 if (lay_ord[1] != lay_ord[2]) swap_strips(1,2);
1104 else if (lay_ord[1] != lay_ord[3]) swap_strips(1,3);
1111 if (lay_ord[2] == lay_ord[3]) {
1114 if (lay_ord[3] != lay_ord[0] && lay_ord[3] != lay_ord[1]) swap_strips(3,0);
1116 ATH_MSG_VERBOSE(
"No way to rearrange the strips such that the latter two strips cross.");
1121 std::array<SeedMeasurement, 4> base_seed{};
1122 for (
size_t s = 0;
s < selLayers.size(); ++
s) {
1123 unsigned int lay = selLayers[
s];
1124 base_seed[
s] = orderedClusters[lay].front();
1127 const double A = (base_seed[1].pos().z() - base_seed[0].pos().z());
1128 const double G = (base_seed[2].pos().z() - base_seed[0].pos().z());
1129 const double K = (base_seed[3].pos().z() - base_seed[0].pos().z());
1132 diamond.block<2, 1>(0, 1) = ((
A -
G) * base_seed[3].dirDot(base_seed[1]) * base_seed[1].dir() +
G * base_seed[3].dirDot(base_seed[0]) * base_seed[0].dir() -
A * base_seed[3].dir()).block<2, 1>(0, 0);
1133 diamond.block<2, 1>(0, 0) = ((K -
A) * base_seed[2].dirDot(base_seed[1]) * base_seed[1].dir() - K * base_seed[2].dirDot(base_seed[0]) * base_seed[0].dir() +
A * base_seed[2].dir()).block<2, 1>(0, 0);
1135 if (std::abs(diamond.determinant()) < std::numeric_limits<float>::epsilon()) {
1137 << diamond << std::endl
1138 <<
" is singular " << diamond.determinant() <<
" with rank "
1139 << (Eigen::FullPivLU<
AmgSymMatrix(2)>{diamond}.rank()));
1144 << diamond << std::endl
1145 <<
"May give a couple of stereo seeds " << diamond.determinant());
1148 const AmgSymMatrix(2) seed_builder = diamond.inverse();
1150 const double KmG = K-
G;
1151 const double KmA = K-
A;
1152 const double AmG =
A-
G;
1154 const double TwoDotZero = base_seed[2].dirDot(base_seed[0]);
1155 const double ThreeDotZero = base_seed[3].dirDot(base_seed[0]);
1156 const double ThreeDotOne = base_seed[3].dirDot(base_seed[1]);
1157 const double TwoDotOne = base_seed[2].dirDot(base_seed[1]);
1159 auto estimate_muon = [&] () -> std::optional<std::array<double,2>> {
1160 const Amg::Vector3D Y0 = K * base_seed[2].pos() -
G * base_seed[3].pos() - KmG * base_seed[0].pos();
1161 const Amg::Vector3D Y1 = AmG * base_seed[3].pos() - KmG * base_seed[1].pos() + KmA * base_seed[2].pos();
1162 const double Y0dotE0 = base_seed[0].dirDot(Y0);
1163 const double Y1dotE1 = base_seed[1].dirDot(Y1);
1165 const AmgVector(2) centers = (KmG * (base_seed[0].pos() - base_seed[1].pos()) +
1166 Y0dotE0 * base_seed[0].
dir() +
1167 A * (base_seed[3].pos() - base_seed[2].pos()) -
1168 Y1dotE1 * base_seed[1].
dir())
1171 const AmgVector(2) sol_pars = seed_builder * centers;
1172 const std::array<double, 4> lengths{(Y0dotE0 + K * sol_pars[0] * TwoDotZero -
G * sol_pars[1] * ThreeDotZero) / KmG,
1173 (Y1dotE1 + AmG * sol_pars[1] *ThreeDotOne + KmA * sol_pars[0] * TwoDotOne) / KmG, sol_pars[0], sol_pars[1]};
1177 std::optional<Amg::Vector3D> seg_pos{std::nullopt}, seg_dir{std::nullopt};
1178 for (
unsigned int i = 0;
i < base_seed.size(); ++
i) {
1184 seg_pos = std::make_optional<Amg::Vector3D>(base_seed[0].
pos() +
1185 lengths[0] * base_seed[0].
dir());
1189 seg_dir = std::make_optional<Amg::Vector3D>((base_seed[1].
pos() +
1190 lengths[1] *base_seed[1].
dir() - (*seg_pos)).
unit());
1193 std::optional<double> mu_crossing = Amg::intersect<3>(*seg_pos, *seg_dir, base_seed[
i].
pos(),base_seed[
i].
dir());
1195 <<
" ("<< std::string( halfLength > std::abs(lengths[
i]) ?
"inside" :
"outside")<<
" wedge) "
1196 << halfLength <<
" vs. "<<std::abs(lengths[
i])<<
" crossing point: "<<std::abs(*mu_crossing));
1197 }
else if (!
accept)
return std::nullopt;
1199 if (!
accept)
return std::nullopt;
1200 return std::make_optional<std::array<double,2>>({lengths[0], lengths[1]});
1205 MeasVec::const_iterator begin2{orderedClusters[selLayers[1]].begin()};
1206 MeasVec::const_iterator begin3{orderedClusters[selLayers[2]].begin()};
1207 MeasVec::const_iterator begin4{orderedClusters[selLayers[3]].begin()};
1209 const MeasVec::const_iterator end2{orderedClusters[selLayers[1]].end()};
1210 const MeasVec::const_iterator end3{orderedClusters[selLayers[2]].end()};
1211 const MeasVec::const_iterator end4{orderedClusters[selLayers[3]].end()};
1214 base_seed[0] = lay1;
1215 for (MeasVec::const_iterator lay2 = begin2; lay2 != end2; ++lay2) {
1217 base_seed[1] = *lay2;
1230 for (MeasVec::const_iterator lay3 = begin3; lay3 != end3; ++lay3) {
1239 base_seed[2] = *lay3;
1241 for (MeasVec::const_iterator lay4 = begin4 ; lay4 != end4; ++lay4) {
1250 base_seed[3] = (*lay4);
1251 std::optional<std::array<double, 2>> isects = estimate_muon();
1253 if (!isects)
continue;
1254 NSWSeed seed{
this, base_seed, *isects};
1256 if (seed.size() < 4)
continue;
1258 const double eta = std::abs(seed.dir().eta());
1259 if (eta < minEtaNSW || eta > maxEtaNSW) {
1262 if (seed.dir().block<2,1>(0,0).dot(seed.pos().block<2,1>(0,0)) < 0.)
continue;
1265 const double deltaPhi = std::abs(seed.dir().deltaPhi(seed.pos()));
1266 if (
deltaPhi > sector_mapping.sectorWidth(
m_idHelperSvc->sector(base_seed[0]->identify())))
continue;
1268 getClustersOnSegment(orderedClusters, seed, {selLayers[0], selLayers[1],selLayers[2], selLayers[3]});
1269 seeds.emplace_back(std::move(seed));
1288 static const double minTanTheta = 0.75 / std::sinh(maxEtaNSW);
1289 static const double maxTanTheta = 1.25 / std::sinh(minEtaNSW);
1291 const double minDR = minTanTheta * std::abs(dZ);
1292 const double maxDR = maxTanTheta * std::abs(dZ);
1294 const std::pair<double, double> rad1 =
coveredRadii(meas1);
1295 const std::pair<double, double> rad2 =
coveredRadii(meas2);
1297 const double dlR = rad2.first - rad1.first;
1298 const double drR = rad2.second - rad1.second;
1301 <<std::endl<<
". Separation in dR (left/right) "<<dlR<<
"/"<<drR<<
", dZ "<<dZ
1302 <<
" --> dR has to be in "<<minDR<<
" "<<maxDR);
1303 if ((std::abs(dlR) < minDR && std::abs(drR) < minDR) ||
1304 (dZ > 0 && dlR <0 && drR <0) || (dZ < 0 && dlR >0 && drR > 0)) {
1306 }
if (std::abs(dlR) > maxDR && std::abs(drR) > maxDR && dlR * drR > 0.){
1313 const int chNum =
channel(meas);
1319 return std::make_pair(radLeft, radRight);
1322 std::vector<NSWSeed> seeds;
1323 seeds.reserve(unresolved.size());
1324 std::sort(unresolved.begin(), unresolved.end(),[](
const NSWSeed&
a,
const NSWSeed&
b){
1325 return a.chi2() < b.chi2();
1327 for (
NSWSeed& seed : unresolved) {
1328 bool add_seed{
true};
1340 if (add_seed) seeds.push_back(std::move(seed));
1342 ATH_MSG_VERBOSE(seeds.size()<<
" out of "<<unresolved.size()<<
" passed the overlap removal");
1348 const std::vector<std::vector<const Muon::sTgcPrepData*>>& pads)
const {
1353 std::vector<std::vector<double>> padsPhiL, padsPhiR;
1354 std::vector<double> padsPhiC;
1357 for (
const std::vector<const Muon::sTgcPrepData*>& surfHits : pads) {
1359 std::vector<double> surfPadsPhiL, surfPadsPhiR;
1374 bool samePhi = std::find_if(padsPhiC.begin(), padsPhiC.end(), [&hitPadX, &halfWidthX](
const double prevPadPhi) {
1375 return std::abs(hitPadX - prevPadPhi) < 0.9 * halfWidthX;
1376 }) != padsPhiC.end();
1378 if (samePhi)
continue;
1381 surfPadsPhiL.push_back(hitPadX - halfWidthX);
1382 surfPadsPhiR.push_back(hitPadX + halfWidthX);
1383 padsPhiC.push_back(hitPadX);
1387 padsPhiL.push_back(std::move(surfPadsPhiL));
1388 padsPhiR.push_back(std::move(surfPadsPhiR));
1391 unsigned int nSurf = padsPhiR.size();
1395 unsigned int nCombos{1};
1396 for (
const std::vector<double>& surfPadsPhiR : padsPhiR) {
1397 if (!surfPadsPhiR.empty()) nCombos *= surfPadsPhiR.size();
1400 std::vector<std::pair<double, double>> phiOverlap;
1401 phiOverlap.reserve(nCombos);
1403 if (nCombos <= 100) {
1404 unsigned int N{nCombos};
1405 for (
unsigned int isurf{0}; isurf < nSurf; ++isurf) {
1406 if (padsPhiR[isurf].
empty())
continue;
1407 unsigned int nSurfHits = padsPhiR[isurf].size();
1410 for (
unsigned int icombo{0}; icombo < nCombos; ++icombo) {
1412 unsigned int padIdx = (icombo /
N) % nSurfHits;
1415 phiOverlap.emplace_back(padsPhiL[isurf][padIdx], padsPhiR[isurf][padIdx]);
1418 phiOverlap[icombo].first =
std::max(padsPhiL[isurf][padIdx], phiOverlap[icombo].
first);
1419 phiOverlap[icombo].second =
std::min(padsPhiR[isurf][padIdx], phiOverlap[icombo].
second);
1425 phiOverlap.erase(std::remove_if(phiOverlap.begin(), phiOverlap.end(),
1426 [](std::pair<double, double>&
range) { return range.first >= range.second; }),
1428 ATH_MSG_DEBUG(
"Pad seeding - #combinations initial: " << nCombos
1429 <<
", after cleaning for non overlapping pads: " << phiOverlap.size());
1433 for (
unsigned int isurf{0}; isurf < nSurf; ++isurf) {
1434 unsigned int nSurfHits = padsPhiR[isurf].size();
1435 for (
unsigned int ihit{0}; ihit < nSurfHits; ++ihit) {
1436 phiOverlap.emplace_back(padsPhiL[isurf][ihit], padsPhiR[isurf][ihit]);
1439 ATH_MSG_DEBUG(
"Pad seeding - #combinations: " << nCombos <<
" is too large. Seeding from" << phiOverlap.size()
1440 <<
" individual pads.");
1454 std::unique_ptr<const Muon::MuonClusterOnTrack> newClus;
1464 calibratedClusters.emplace_back(seed.newCalibClust(std::move(newClus)));
1468 calibratedClusters.emplace_back(seed.newCalibClust(std::move(newClus)));
1472 return calibratedClusters;
1478 std::stringstream sstr{};
1486 std::stringstream sstr{};
1488 <<
" pointing to (" <<
to_string(
cl.dir())<<
" cluster size: "<<clusterSize(
cl);
1493 std::stringstream sstr{};
1495 sstr<<
" *** "<<
print(
cl)<<std::endl;
1500 std::stringstream sstr{};
1501 unsigned int lay{0};
1502 for (
const MeasVec& clusts: sortedVec){
1503 sstr<<
"Clusters in Layer: "<<(lay+1)<<std::endl;
1504 sstr<<
"#################################################"<<std::endl;
1505 sstr<<
print(clusts);
1519 prunedMeas.reserve(clustInLay.size());
1520 const unsigned int firstCh =
channel(clustInLay[0]);
1521 const unsigned int lastCh =
channel(clustInLay[clustInLay.size() -1]);
1523 const unsigned int deltaCh = lastCh - firstCh;
1526 firstCh<<
", highest channel: "<<lastCh<<
" bin width: "<<
m_ocupMmBinWidth<<
" number of bins"<<
nBins);
1529 occupancyHisto.resize(
nBins);
1531 bin.reserve(clustInLay.size());
1537 occupancyHisto[
bin].push_back(std::move(meas));
1547 for (
unsigned int i = 0;
i < occupancyHisto.size() -1; ++
i) {
1549 ATH_MSG_VERBOSE(
"The two neighbouring bins "<<
i<<
"&"<<(
i+1)<<
" have too many clusters "<<std::endl<<
1550 print(occupancyHisto[
i])<<std::endl<<
print(occupancyHisto[
i+1]));
1551 occupancyHisto[
i].clear();
1552 occupancyHisto[
i+1].clear();
1558 std::make_move_iterator(
bin.end()),
1559 std::back_inserter(prunedMeas));
1562 ATH_MSG_VERBOSE(
"Number of measurements before pruning "<<clustInLay.size()<<
" number of measurments survived the pruning "<<prunedMeas.size());