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 ATH_MSG_VERBOSE(
"Found " << stereoSegs.size() <<
" MMG stereo seeded segments");
295 out_segments.insert(out_segments.end(), std::make_move_iterator(stereoSegs.begin()),
296 std::make_move_iterator(stereoSegs.end()));
299 auto dump_output = [&]() {
301 for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
310 std::vector<const Muon::MuonClusterOnTrack*> clustPostStereo{};
312 std::array<std::set<Identifier>, 16> masked_segs{};
313 for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
320 if (!out_segments.empty()) {
321 clustPostStereo.reserve(muonClusters.size());
326 const std::vector<const Muon::MuonClusterOnTrack*>& segmentInput = !out_segments.empty() ? clustPostStereo : muonClusters;
331 ATH_MSG_VERBOSE(
"Found " << etaSegs.size() <<
" stgc seeded eta segments");
332 MuonSegmentVec precSegs =
find3DSegments(ctx, segmentInput, etaSegs);
334 out_segments.insert(out_segments.end(),
335 std::make_move_iterator(precSegs.begin()),
336 std::make_move_iterator(precSegs.end()));
346 for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
347 std::vector<const MuonClusterOnTrack*> seg_hits{};
348 seg_hits.reserve(seg->containedMeasurements().size());
351 if (clus) seg_hits.push_back(clus);
354 for (
int iWedge{1}; iWedge<=4 ; ++iWedge) {
357 if ( quad_hits.size () < 2 || ((iWedge == 2 || iWedge == 3) && quad_hits.size() < 4))
continue;
358 std::vector<const Trk::MeasurementBase*> fit_meas{};
359 std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{
ipConstraint(ctx)};
360 if (pseudoVtx) fit_meas.push_back(pseudoVtx.get());
361 std::copy(quad_hits.begin(), quad_hits.end(), std::back_inserter(fit_meas));
363 const Trk::Surface& surf = quad_hits.front()->associatedSurface();
368 if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
371 std::unique_ptr<Trk::Track> segtrack =
fit(ctx, fit_meas, startpar);
372 if (!segtrack)
continue;
377 <<
"position: "<<
to_string(seg->globalPosition())<< std::endl
378 <<
"direction: "<<
to_string(seg->globalDirection())<< std::endl
379 <<
m_printer->print(seg->containedMeasurements()));
381 cache.
quadSegs.emplace_back(std::move(seg));
388 const std::vector<const Muon::MuonClusterOnTrack*>& allClusts,
389 int singleWedge)
const {
401 for (
MeasVec& hitsInLayer : orderedClust) hitsInLayer =
vetoBursts(std::move(hitsInLayer));
402 orderedClust.erase(std::remove_if(orderedClust.begin(), orderedClust.end(),
403 [](
const MeasVec&
vec) { return vec.empty(); }),
405 if (orderedClust.empty())
return {};
409 ATH_MSG_VERBOSE(
"Retrieved " << seeds.size() <<
" seeds in the MMStereoAlg after the ambiguity resolution" );
411 if (seeds.empty())
return {};
417 std::vector<const Trk::MeasurementBase*> fit_meas{};
419 std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{
ipConstraint(ctx)};
420 if (pseudoVtx) fit_meas.push_back(pseudoVtx.get());
422 std::copy(calib_clust.begin(), calib_clust.end(), std::back_inserter(fit_meas));
424 const Trk::Surface& surf = calib_clust.front()->associatedSurface();
430 if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
435 std::unique_ptr<Trk::Track> segtrack =
fit(ctx, fit_meas, startpar);
436 if (segtrack) trackSegs.push_back(std::move(segtrack));
442 const std::vector<const Trk::MeasurementBase*>& fit_meas,
445 to_string(perigee.
momentum())<<
". Contained measurements in candidate: " << std::endl
453 std::unique_ptr<Trk::Track> cleanedTrack =
m_trackCleaner->clean(*segtrack, ctx);
473 const std::vector<const Muon::MuonClusterOnTrack*>& muonClusters,
474 int singleWedge)
const {
487 ATH_MSG_DEBUG(
"Cleaning eta clusters in stgc seeded 2D segments ");
494 if (orderedClusters.size() < 4)
return {};
504 if (seed.size() < 4){
505 ATH_MSG_VERBOSE(__func__<<
" :"<<__LINE__<<
" - Seed size: " << seed.size() <<
" is below the cut (4)");
509 etaHitVec = seed.measurements();
527 if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
528 const auto startpar =
Trk::Perigee(perpos, gdir_seg, 0, perpos);
529 ATH_MSG_VERBOSE(
" start parameter " << perpos <<
" pp " << startpar.position() <<
" gd " << gdir_seg.unit() <<
" pp "
530 << startpar.momentum().unit());
533 hitsToTrack(ctx, etaHitVec, phiHitVec, startpar, segTrkColl);
550 MuonSegmentVec segments{};
551 std::unique_ptr<const TrackCollection> resolvedTracks(
m_ambiTool->process(&segTrkColl));
552 ATH_MSG_DEBUG(
"Resolved track candidates: old size " << segTrkColl.
size() <<
" new size " << resolvedTracks->
size());
555 for (
const Trk::Track* trk : *resolvedTracks) {
556 const auto* measurements = trk->measurementsOnTrack();
557 const bool has_eta = std::find_if(measurements->begin(), measurements->end(),
559 Identifier id = m_edmHelperSvc->getIdentifier(*meas);
560 return id.is_valid() && !m_idHelperSvc->measuresPhi(id);
561 }) != trk->measurementsOnTrack()->end();
562 if (!has_eta)
continue;
567 segments.emplace_back(std::move(seg));
576 const std::vector<const Muon::MuonClusterOnTrack*>& muonClusters,
577 MuonSegmentVec& etaSegs,
578 int singleWedge)
const {
579 MuonSegmentVec segments{};
582 ATH_MSG_DEBUG(
"Cleaning phi clusters in stgc seeded 3D segments ");
584 ATH_MSG_DEBUG(
"After hit cleaning, there are " << phiClusters.size() <<
" phi clusters to be fit");
590 if (orderedWireClusters.size() + orderedPadClusters.size() < 2) {
591 ATH_MSG_DEBUG(
"Not enough phi hits present, cannot perform the 3D fit!");
592 segments.insert(segments.end(), std::make_move_iterator(etaSegs.begin()), std::make_move_iterator(etaSegs.end()));
597 ATH_MSG_DEBUG(
"Cleaning eta clusters in stgc seeded 3D segments ");
602 bool triedWireSeed{
false};
603 std::vector<NSWSeed> seeds_WiresSTGC;
606 for (std::unique_ptr<Muon::MuonSegment>& etaSeg : etaSegs) {
611 std::vector<NSWSeed> seeds;
614 if (std::abs(etaSeg->globalPosition().eta()) < 2.4) {
615 if (!triedWireSeed) {
617 triedWireSeed =
true;
621 if (!seeds_WiresSTGC.empty()) {
622 seeds = seeds_WiresSTGC;
636 double etaSegLocX = etaSeg->localParameters()[
Trk::locX];
637 double etaSegLocXZ = etaSeg->localDirection().angleXZ();
657 if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
658 const Trk::Perigee startpar{perpos, gdir_seg, 0, perpos};
660 NSWSeed seed3D{
this, perpos, gdir_seg};
665 if (nPhiHits < 2)
continue;
667 MeasVec phiHitVec = seed3D.measurements();
672 if (
hitsToTrack(ctx, etaHitsCalibrated, phiHitVec, startpar, segTrkColl)) {
674 ATH_MSG_VERBOSE(
"Segment successfully fitted for wedge "<<singleWedge<<std::endl<<
681 if (!is3Dseg) { segments.push_back(std::move(etaSeg)); }
684 segments.insert(segments.end(), std::make_move_iterator(new_segs.begin()), std::make_move_iterator(new_segs.end()));
692 covVtx.setIdentity();
693 covVtx = errVtx * errVtx * covVtx;
709 covVtx(0, 0) = errVtx * errVtx;
734 std::vector<const Trk::MeasurementBase*> vecFitPts;
735 unsigned int nHitsEta = etaHitVec.size();
736 unsigned int nHitsPhi = phiHitVec.size();
739 std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{
ipConstraint(ctx)},
741 pseudoPhi1{
nullptr}, pseudoPhi2{
nullptr};
743 if (pseudoVtx) { vecFitPts.push_back(pseudoVtx.get()); }
744 if (pseudoVtxCalo) { vecFitPts.push_back(pseudoVtxCalo.get()); }
752 cov(0, 0) = pseudoPrecision;
754 pseudoPhi1 = std::make_unique<Trk::PseudoMeasurementOnTrack>(
Trk::LocalParameters(loc_pseudopars),
756 etaHitVec.front()->associatedSurface());
757 pseudoPhi2 = std::make_unique<Trk::PseudoMeasurementOnTrack>(
Trk::LocalParameters(loc_pseudopars),
759 etaHitVec.back()->associatedSurface());
762 vecFitPts.push_back(pseudoPhi1.get());
763 std::copy(etaHitVec.begin(), etaHitVec.end(), std::back_inserter(vecFitPts));
764 vecFitPts.push_back(pseudoPhi2.get());
765 ATH_MSG_VERBOSE(
"Fitting a 2D-segment track with " << nHitsEta <<
" Eta hits");
769 std::merge(phiHitVec.begin(), phiHitVec.end(), etaHitVec.begin(), etaHitVec.end(), std::back_inserter(vecFitPts),
771 double z1 = std::abs(c1->detectorElement()->center(c1->identify()).z());
772 double z2 = std::abs(c2->detectorElement()->center(c2->identify()).z());
775 ATH_MSG_VERBOSE(
"Fitting a 3D-segment track with " << nHitsEta <<
" Eta hits and " << nHitsPhi <<
" Phi hits");
779 std::unique_ptr<Trk::Track> segtrack =
fit(ctx, vecFitPts, startpar);
780 if (!segtrack)
return false;
781 segTrkColl.
push_back(std::move(segtrack));
787 const std::vector<const Muon::MuonClusterOnTrack*>& muonClusters,
int hit_sel,
int singleWedge )
const {
791 clusters.reserve(muonClusters.size());
793 if (!cluster)
continue;
794 if (singleWedge && singleWedge !=
wedgeNumber(cluster))
continue;
813 std::array<std::set<Identifier>,16> used_hits{};
823 const int channelType =
m_idHelperSvc->stgcIdHelper().channelType(
id);
828 std::set<Identifier>& lay_hits = used_hits[iorder];
829 if (lay_hits.count(
id))
continue;
831 orderedClusters[iorder].emplace_back(hit);
833 if (
nBad)
ATH_MSG_WARNING(
"Unable to classify " <<
nBad <<
" clusters by their layer since they are neither MM nor sTGC");
836 orderedClusters.erase(std::remove_if(orderedClusters.begin(), orderedClusters.end(),
837 [](
const MeasVec&
vec) { return vec.empty(); }),
838 orderedClusters.end());
841 for(
MeasVec& lays: orderedClusters){
843 return channel(a) < channel(b);
851 return orderedClusters;
857 std::vector<NSWSeed> seeds;
861 if (orderedClusters.size() < 4)
return seeds;
867 int seedingLayersL{0};
868 for (
unsigned int ilayerL{0}; (ilayerL < orderedClusters.size() && seedingLayersL <
m_nOfSeedLayers); ++ilayerL) {
869 bool usedLayerL{
false};
872 if (usePhi !=
m_idHelperSvc->measuresPhi(hitL->identify()))
continue;
877 int seedingLayersR{0};
878 for (
unsigned int ilayerR = orderedClusters.size() - 1; (ilayerR > ilayerL && seedingLayersR <
m_nOfSeedLayers);
880 bool usedLayerR{
false};
882 if (usePhi !=
m_idHelperSvc->measuresPhi(hitR->identify()))
continue;
886 const double eta = seed.dir().perp() > std::numeric_limits<float>::epsilon() ? std::abs(seed.dir().eta()): FLT_MAX;
887 if (eta < minEtaNSW || eta > maxEtaNSW) {
894 seeds.emplace_back(std::move(seed));
897 if (usedLayerR) ++seedingLayersR;
900 if (usedLayerL) ++seedingLayersL;
909 return m_idHelperSvc->mmIdHelper().multilayer(cluster->identify()) + 1;
911 return 3 * (
m_idHelperSvc->stgcIdHelper().multilayer(cluster->identify()) - 1) + 1;
932 NSWSeed& seed,
const std::set<unsigned int>&
exclude,
bool useStereo)
const {
933 ATH_MSG_VERBOSE(
" getClustersOnSegment: layers " << orderedclusters.size());
936 for (
const MeasVec& surfHits : orderedclusters) {
951 ATH_MSG_VERBOSE(
" getClustersOnSegment: returning " << nHitsAdded <<
" hits ");
958 std::vector<NSWSeed> seeds;
960 if (orderedClusters.empty())
return seeds;
962 std::vector<std::vector<const Muon::sTgcPrepData*>> sTgcIP(4);
963 std::vector<std::vector<const Muon::sTgcPrepData*>> sTgcHO(4);
966 for (
int iml : {1, 2}) {
967 int il = (iml == 1) ? 0 : orderedClusters.size() - 1;
968 int iend = (iml == 1) ? orderedClusters.size() : -1;
969 int idir = (iml == 1) ? 1 : -1;
970 unsigned int nLayersWithHitMatch{0};
973 for (;
il != iend;
il += idir) {
974 double lastDistance{1000.};
975 if (nLayersWithHitMatch >= sTgcIP.size()) {
976 sTgcIP.resize(nLayersWithHitMatch + 1);
977 sTgcHO.resize(nLayersWithHitMatch + 1);
979 std::vector<const Muon::sTgcPrepData*>& matchedHits =
980 (iml == 1) ? sTgcIP.at(nLayersWithHitMatch) : sTgcHO.at(nLayersWithHitMatch);
985 if (!padHit)
continue;
991 if (!design)
continue;
1003 double etaDistance = std::abs(padHit->
localPosition().y() - segLocPosOnSurf[1]);
1004 if (etaDistance > 0.5 * chWidth)
continue;
1005 ATH_MSG_DEBUG(
" etaDistance " << etaDistance <<
" between pad center and position on the pad.");
1007 if (matchedHits.empty()) {
1009 matchedHits.push_back(padHit);
1011 }
else if (std::abs(etaDistance - lastDistance) < 0.001) {
1013 matchedHits.push_back(padHit);
1014 ATH_MSG_DEBUG(
" added etaDistance: " << etaDistance <<
" size " << matchedHits.size());
1015 }
else if (etaDistance < lastDistance) {
1017 matchedHits.clear();
1018 matchedHits.push_back(padHit);
1019 ATH_MSG_DEBUG(
" replacing best etaDistance with: " << etaDistance);
1023 lastDistance = etaDistance;
1026 if (!matchedHits.empty()) ++nLayersWithHitMatch;
1031 if (!nLayersWithHitMatch)
return seeds;
1036 std::vector<std::pair<double, double>> sTgcIP_phiRanges =
getPadPhiOverlap(sTgcIP);
1037 std::vector<std::pair<double, double>> sTgcHO_phiRanges =
getPadPhiOverlap(sTgcHO);
1046 for (
const std::pair<double, double>& range1 : sTgcIP_phiRanges) {
1047 double midPhi1 = 0.5 * (range1.first + range1.second);
1050 surfPrdL1.localToGlobal(lp1, gpL1, gpL1);
1052 for (
const std::pair<double, double>& range2 : sTgcHO_phiRanges) {
1053 double midPhi2 = 0.5 * (range2.first + range2.second);
1056 surfPrdL2.localToGlobal(lp2, gpL2, gpL2);
1060 seeds.emplace_back(
this, gpL1, gDir);
1064 ATH_MSG_DEBUG(
" segmentSeedFromPads: seeds.size() " << seeds.size());
1071 std::vector<NSWSeed> seeds;
1072 std::array<unsigned int, 4>
layers{};
1073 unsigned int trials{0}, used_layers{0};
1075 constexpr
size_t lastMMLay = 11;
1076 std::vector<NSWSeed> laySeeds;
1079 std::stringstream sstr{};
1080 for (
int e4 =
std::min(lastMMLay, orderedClusters.size() -1);
e4 >= 3 ; --
e4) {
1082 for (
int e3 =
e4 -1 ;
e3 >= 2; --
e3) {
1088 const unsigned int old_trials = trials;
1090 if (old_trials == trials)
continue;
1092 used_layers += !laySeeds.empty();
1093 seeds.insert(seeds.end(), std::make_move_iterator(laySeeds.begin()),
1094 std::make_move_iterator(laySeeds.end()));
1097 sstr<<
" Attempts thus far "<<old_trials<<
" attempts now "<<trials<<
" --- "<<
e1<<
","<<
e2<<
","<<
e3<<
","<<
e4<<std::endl;
1099 sstr<<
"Layer: "<<lay<<
" number of measurements "<<orderedClusters[lay].size()<<std::endl;
1101 sstr<<
" **** "<<
print(meas)<<std::endl;
1103 sstr<<std::endl<<std::endl<<std::endl;
1110 if (trials > 100000) {
1113 ATH_MSG_VERBOSE(
"Out of "<<trials<<
" possible seeds, "<<seeds.size()<<
" were finally built. Used in total "<<used_layers<<
" layers");
1117 #if defined(FLATTEN)
1121 std::array<unsigned int,4> selLayers,
1122 unsigned int& trial_counter)
const {
1123 std::vector<NSWSeed> seeds{};
1125 std::array<unsigned int, 4> lay_ord{};
1126 for (
size_t s = 0;
s < selLayers.size(); ++
s) {
1127 unsigned int lay = selLayers[
s];
1135 else lay_ord[
s] = 3;
1137 auto swap_strips = [&selLayers, &lay_ord] (
unsigned int i,
unsigned j){
1142 if (lay_ord[0] == lay_ord[1]){
1143 if (lay_ord[1] != lay_ord[2]) swap_strips(1,2);
1144 else if (lay_ord[1] != lay_ord[3]) swap_strips(1,3);
1151 if (lay_ord[2] == lay_ord[3]) {
1154 if (lay_ord[3] != lay_ord[0] && lay_ord[3] != lay_ord[1]) swap_strips(3,0);
1156 ATH_MSG_VERBOSE(
"No way to rearrange the strips such that the latter two strips cross.");
1161 std::array<SeedMeasurement, 4> base_seed{};
1162 for (
size_t s = 0;
s < selLayers.size(); ++
s) {
1163 unsigned int lay = selLayers[
s];
1164 base_seed[
s] = orderedClusters[lay].front();
1167 const double A = (base_seed[1].pos().z() - base_seed[0].pos().z());
1168 const double G = (base_seed[2].pos().z() - base_seed[0].pos().z());
1169 const double K = (base_seed[3].pos().z() - base_seed[0].pos().z());
1172 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);
1173 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);
1175 if (std::abs(diamond.determinant()) < std::numeric_limits<float>::epsilon()) {
1177 << diamond << std::endl
1178 <<
" is singular " << diamond.determinant() <<
" with rank "
1179 << (Eigen::FullPivLU<
AmgSymMatrix(2)>{diamond}.rank()));
1184 << diamond << std::endl
1185 <<
"May give a couple of stereo seeds " << diamond.determinant());
1188 const AmgSymMatrix(2) seed_builder = diamond.inverse();
1190 const double KmG = K-
G;
1191 const double KmA = K-
A;
1192 const double AmG =
A-
G;
1194 const double TwoDotZero = base_seed[2].dirDot(base_seed[0]);
1195 const double ThreeDotZero = base_seed[3].dirDot(base_seed[0]);
1196 const double ThreeDotOne = base_seed[3].dirDot(base_seed[1]);
1197 const double TwoDotOne = base_seed[2].dirDot(base_seed[1]);
1199 auto estimate_muon = [&] () -> std::optional<std::array<double,2>> {
1200 const Amg::Vector3D Y0 = K * base_seed[2].pos() -
G * base_seed[3].pos() - KmG * base_seed[0].pos();
1201 const Amg::Vector3D Y1 = AmG * base_seed[3].pos() - KmG * base_seed[1].pos() + KmA * base_seed[2].pos();
1202 const double Y0dotE0 = base_seed[0].dirDot(Y0);
1203 const double Y1dotE1 = base_seed[1].dirDot(Y1);
1205 const AmgVector(2) centers = (KmG * (base_seed[0].pos() - base_seed[1].pos()) +
1206 Y0dotE0 * base_seed[0].
dir() +
1207 A * (base_seed[3].pos() - base_seed[2].pos()) -
1208 Y1dotE1 * base_seed[1].
dir())
1211 const AmgVector(2) sol_pars = seed_builder * centers;
1212 const std::array<double, 4> lengths{(Y0dotE0 + K * sol_pars[0] * TwoDotZero -
G * sol_pars[1] * ThreeDotZero) / KmG,
1213 (Y1dotE1 + AmG * sol_pars[1] *ThreeDotOne + KmA * sol_pars[0] * TwoDotOne) / KmG, sol_pars[0], sol_pars[1]};
1217 std::optional<Amg::Vector3D> seg_pos{std::nullopt}, seg_dir{std::nullopt};
1218 for (
unsigned int i = 0;
i < base_seed.size(); ++
i) {
1224 seg_pos = std::make_optional<Amg::Vector3D>(base_seed[0].
pos() +
1225 lengths[0] * base_seed[0].
dir());
1229 seg_dir = std::make_optional<Amg::Vector3D>((base_seed[1].
pos() +
1230 lengths[1] *base_seed[1].
dir() - (*seg_pos)).
unit());
1233 std::optional<double> mu_crossing = Amg::intersect<3>(*seg_pos, *seg_dir, base_seed[
i].
pos(),base_seed[
i].
dir());
1235 <<
" ("<< std::string( halfLength > std::abs(lengths[
i]) ?
"inside" :
"outside")<<
" wedge) "
1236 << halfLength <<
" vs. "<<std::abs(lengths[
i])<<
" crossing point: "<<std::abs(*mu_crossing));
1237 }
else if (!
accept)
return std::nullopt;
1239 if (!
accept)
return std::nullopt;
1240 return std::make_optional<std::array<double,2>>({lengths[0], lengths[1]});
1245 MeasVec::const_iterator begin2{orderedClusters[selLayers[1]].begin()};
1246 MeasVec::const_iterator begin3{orderedClusters[selLayers[2]].begin()};
1247 MeasVec::const_iterator begin4{orderedClusters[selLayers[3]].begin()};
1249 const MeasVec::const_iterator end2{orderedClusters[selLayers[1]].end()};
1250 const MeasVec::const_iterator end3{orderedClusters[selLayers[2]].end()};
1251 const MeasVec::const_iterator end4{orderedClusters[selLayers[3]].end()};
1254 base_seed[0] = lay1;
1255 for (MeasVec::const_iterator lay2 = begin2; lay2 != end2; ++lay2) {
1257 base_seed[1] = *lay2;
1270 for (MeasVec::const_iterator lay3 = begin3; lay3 != end3; ++lay3) {
1279 base_seed[2] = *lay3;
1281 for (MeasVec::const_iterator lay4 = begin4 ; lay4 != end4; ++lay4) {
1290 base_seed[3] = (*lay4);
1291 std::optional<std::array<double, 2>> isects = estimate_muon();
1293 if (!isects)
continue;
1294 NSWSeed seed{
this, base_seed, *isects};
1296 if (seed.size() < 4)
continue;
1298 const double eta = std::abs(seed.dir().eta());
1299 if (eta < minEtaNSW || eta > maxEtaNSW) {
1302 if (seed.dir().block<2,1>(0,0).dot(seed.pos().block<2,1>(0,0)) < 0.)
continue;
1305 const double deltaPhi = std::abs(seed.dir().deltaPhi(seed.pos()));
1306 if (
deltaPhi > sector_mapping.sectorWidth(
m_idHelperSvc->sector(base_seed[0]->identify())))
continue;
1308 getClustersOnSegment(orderedClusters, seed, {selLayers[0], selLayers[1],selLayers[2], selLayers[3]});
1309 seeds.emplace_back(std::move(seed));
1328 static const double minTanTheta = 0.75 / std::sinh(maxEtaNSW);
1329 static const double maxTanTheta = 1.25 / std::sinh(minEtaNSW);
1331 const double minDR = minTanTheta * std::abs(dZ);
1332 const double maxDR = maxTanTheta * std::abs(dZ);
1334 const std::pair<double, double> rad1 =
coveredRadii(meas1);
1335 const std::pair<double, double> rad2 =
coveredRadii(meas2);
1337 const double dlR = rad2.first - rad1.first;
1338 const double drR = rad2.second - rad1.second;
1341 <<std::endl<<
". Separation in dR (left/right) "<<dlR<<
"/"<<drR<<
", dZ "<<dZ
1342 <<
" --> dR has to be in "<<minDR<<
" "<<maxDR);
1343 if ((std::abs(dlR) < minDR && std::abs(drR) < minDR) ||
1344 (dZ > 0 && dlR <0 && drR <0) || (dZ < 0 && dlR >0 && drR > 0)) {
1346 }
if (std::abs(dlR) > maxDR && std::abs(drR) > maxDR && dlR * drR > 0.){
1353 const int chNum =
channel(meas);
1359 return std::make_pair(radLeft, radRight);
1362 std::vector<NSWSeed> seeds;
1363 seeds.reserve(unresolved.size());
1364 std::sort(unresolved.begin(), unresolved.end(),[](
const NSWSeed&
a,
const NSWSeed&
b){
1365 return a.chi2() < b.chi2();
1367 for (
NSWSeed& seed : unresolved) {
1368 bool add_seed{
true};
1380 if (add_seed) seeds.push_back(std::move(seed));
1382 ATH_MSG_VERBOSE(seeds.size()<<
" out of "<<unresolved.size()<<
" passed the overlap removal");
1388 const std::vector<std::vector<const Muon::sTgcPrepData*>>& pads)
const {
1393 std::vector<std::vector<double>> padsPhiL, padsPhiR;
1394 std::vector<double> padsPhiC;
1397 for (
const std::vector<const Muon::sTgcPrepData*>& surfHits : pads) {
1399 std::vector<double> surfPadsPhiL, surfPadsPhiR;
1414 bool samePhi = std::find_if(padsPhiC.begin(), padsPhiC.end(), [&hitPadX, &halfWidthX](
const double prevPadPhi) {
1415 return std::abs(hitPadX - prevPadPhi) < 0.9 * halfWidthX;
1416 }) != padsPhiC.end();
1418 if (samePhi)
continue;
1421 surfPadsPhiL.push_back(hitPadX - halfWidthX);
1422 surfPadsPhiR.push_back(hitPadX + halfWidthX);
1423 padsPhiC.push_back(hitPadX);
1427 padsPhiL.push_back(std::move(surfPadsPhiL));
1428 padsPhiR.push_back(std::move(surfPadsPhiR));
1431 unsigned int nSurf = padsPhiR.size();
1435 unsigned int nCombos{1};
1436 for (
const std::vector<double>& surfPadsPhiR : padsPhiR) {
1437 if (!surfPadsPhiR.empty()) nCombos *= surfPadsPhiR.size();
1440 std::vector<std::pair<double, double>> phiOverlap;
1441 phiOverlap.reserve(nCombos);
1443 if (nCombos <= 100) {
1444 unsigned int N{nCombos};
1445 for (
unsigned int isurf{0}; isurf < nSurf; ++isurf) {
1446 if (padsPhiR[isurf].empty())
continue;
1447 unsigned int nSurfHits = padsPhiR[isurf].size();
1450 for (
unsigned int icombo{0}; icombo < nCombos; ++icombo) {
1452 unsigned int padIdx = (icombo /
N) % nSurfHits;
1455 phiOverlap.emplace_back(padsPhiL[isurf][padIdx], padsPhiR[isurf][padIdx]);
1458 phiOverlap[icombo].first =
std::max(padsPhiL[isurf][padIdx], phiOverlap[icombo].
first);
1459 phiOverlap[icombo].second =
std::min(padsPhiR[isurf][padIdx], phiOverlap[icombo].
second);
1465 phiOverlap.erase(std::remove_if(phiOverlap.begin(), phiOverlap.end(),
1466 [](std::pair<double, double>&
range) { return range.first >= range.second; }),
1468 ATH_MSG_DEBUG(
"Pad seeding - #combinations initial: " << nCombos
1469 <<
", after cleaning for non overlapping pads: " << phiOverlap.size());
1473 for (
unsigned int isurf{0}; isurf < nSurf; ++isurf) {
1474 unsigned int nSurfHits = padsPhiR[isurf].size();
1475 for (
unsigned int ihit{0}; ihit < nSurfHits; ++ihit) {
1476 phiOverlap.emplace_back(padsPhiL[isurf][ihit], padsPhiR[isurf][ihit]);
1479 ATH_MSG_DEBUG(
"Pad seeding - #combinations: " << nCombos <<
" is too large. Seeding from" << phiOverlap.size()
1480 <<
" individual pads.");
1494 std::unique_ptr<const Muon::MuonClusterOnTrack> newClus;
1504 calibratedClusters.emplace_back(seed.newCalibClust(std::move(newClus)));
1508 calibratedClusters.emplace_back(seed.newCalibClust(std::move(newClus)));
1512 return calibratedClusters;
1518 std::stringstream sstr{};
1526 std::stringstream sstr{};
1528 <<
" pointing to (" <<
to_string(
cl.dir())<<
" cluster size: "<<clusterSize(
cl);
1533 std::stringstream sstr{};
1535 sstr<<
" *** "<<
print(
cl)<<std::endl;
1540 std::stringstream sstr{};
1541 unsigned int lay{0};
1542 for (
const MeasVec& clusts: sortedVec){
1543 sstr<<
"Clusters in Layer: "<<(lay+1)<<std::endl;
1544 sstr<<
"#################################################"<<std::endl;
1545 sstr<<
print(clusts);
1559 prunedMeas.reserve(clustInLay.size());
1560 const unsigned int firstCh =
channel(clustInLay[0]);
1561 const unsigned int lastCh =
channel(clustInLay[clustInLay.size() -1]);
1563 const unsigned int deltaCh = lastCh - firstCh;
1566 firstCh<<
", highest channel: "<<lastCh<<
" bin width: "<<
m_ocupMmBinWidth<<
" number of bins"<<
nBins);
1569 occupancyHisto.resize(
nBins);
1571 bin.reserve(clustInLay.size());
1577 occupancyHisto[
bin].push_back(std::move(meas));
1587 for (
unsigned int i = 0;
i < occupancyHisto.size() -1; ++
i) {
1589 ATH_MSG_VERBOSE(
"The two neighbouring bins "<<
i<<
"&"<<(
i+1)<<
" have too many clusters "<<std::endl<<
1590 print(occupancyHisto[
i])<<std::endl<<
print(occupancyHisto[
i+1]));
1591 occupancyHisto[
i].clear();
1592 occupancyHisto[
i+1].clear();
1598 std::make_move_iterator(
bin.end()),
1599 std::back_inserter(prunedMeas));
1602 ATH_MSG_VERBOSE(
"Number of measurements before pruning "<<clustInLay.size()<<
" number of measurments survived the pruning "<<prunedMeas.size());