78 std::vector<CandidatePatPair> candidates{};
87 <<
" eta patterns: " << etaPatternCollection.
size()
88 <<
" phi patterns: " << phiPatternCollection.
size()
89 <<std::endl<<
"#################################################################################"
90 <<std::endl<<
"Print eta pattern collection "<<std::endl<<
m_printer->print(etaPatternCollection)
91 <<std::endl<<
"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
92 <<std::endl<<
"Print phi pattern collection "<<std::endl<<
m_printer->print(phiPatternCollection)
95 for (
unsigned int etalevel = 0; etalevel < etaPatternCollection.
size(); etalevel++) {
100 double theta = etaPatDir.theta();
101 const double phieta = etaPatDir.phi();
104 double z0 = etaPatPos.z();
105 double rz0 = z0 * sctheta.
sn;
107 double eta_x = etaPatPos.x();
108 double eta_y = etaPatPos.y();
109 double pattern_z0 =z0 + etaPatPos.perp() * sctheta.
cs / sctheta.
sn;
113 const double charge = eta_r0>= 0. ? 1. : -1;
116 const double invcurvature = curvature > 2 ?
charge / curvature : 0.;
118 ATH_MSG_DEBUG(
" eta pattern info level: " << etalevel <<
" phi " << phieta <<
" theta " <<
theta <<
" x0 " << eta_x <<
" y0 "
123 int max_philevel = -1;
125 double dotprodbest = -1.;
127 bool ismatched =
false;
128 for (
unsigned int philevel = 0; philevel < phiPatternCollection.
size(); philevel++) {
129 CandPrdPatPtr phipattern{phiPatternCollection.
at(philevel), Unowned()};
131 bool useTightAssociation =
false;
141 useTightAssociation =
true;
145 const double dotprod = phiPatDir.dot(etaPatDir);
147 if (dotprod > dotprodbest) {
148 dotprodbest = dotprod;
153 ATH_MSG_DEBUG(
" eta nr " << etalevel <<
" phi nr " << philevel <<
" inproduct " << dotprod <<
" sin angle "
154 << std::sin(std::acos(dotprod)));
157 double r0{0.}, phipattern_x{0.}, phipattern_y{0.},
phi{phiPatDir.phi()};
168 phipattern_x = r0 * scphi.
sn;
169 phipattern_y = r0 * scphi.
cs;
172 phipattern_x = posphipattern.x();
173 phipattern_y = posphipattern.y();
188 std::map<Identifier, ChamberInfo> infoPerChamber;
189 std::map<Muon::MuonStationIndex::StIndex, ChamberInfo> infoPerStation;
191 double average_distance{0};
192 int nhits_in_average{0}, nhits_inside_distance_cut{0};
194 double phiPatMin{1e9}, phiPatMax{-1e9};
199 double radius_hit = globalposhit.perp();
200 double dotprodradius = sctheta.
apply(radius_hit, globalposhit.z());
204 double residu_distance_mm{100.*Gaudi::Units::meter};
206 const double perp = scphi.
apply(globalposhit.y(), globalposhit.x());
212 double distancetoline = std::abs(residu_distance_mm);
218 nhits_inside_distance_cut++;
220 average_distance += distancetoline;
222 if (!useTightAssociation) {
continue; }
226 double hitphi = globalposhit.phi();
235 phiPatMin =std::min(hitphi,phiPatMin);
236 phiPatMax =std::max(hitphi,phiPatMax);
240 if (nhits_in_average > 0) average_distance /= nhits_in_average;
242 ATH_MSG_DEBUG(
" Result for phi pattern: accepted hits " << nhits_inside_distance_cut <<
" average distance "
243 << average_distance);
245 bool etapattern_passed =
false;
249 const double etahitx = etaglobalposhit.x();
250 const double etahity = etaglobalposhit.y();
253 double etadotprod = scphi.
apply(etahity, etahitx);
255 if (etadotprod < 0)
continue;
258 const double xdiff = phipattern_x - etahitx;
259 const double ydiff = phipattern_y - etahity;
260 const double etahitr = std::hypot(xdiff, ydiff);
262 bool hit_passed =
false;
270 const double scale = etahitr / 7000.;
272 }
else if (2 * etadistancetoline < etahitr) {
277 if (!hit_passed) {
continue; }
279 etapattern_passed =
true;
283 if (!useTightAssociation) { continue ;}
294 if (!mdtDetEl)
continue;
300 double halfLength = 0.5 * mdtDetEl->
getWireLength(layer, tube);
303 double phiLeft = gposLeft.phi();
307 double phiRight = gposRight.phi();
308 double phiMin = std::min(phiRight, phiLeft);
309 double phiMax = std::max(phiLeft ,phiRight);
314 double tubeL = (HVPos - ROPos).
mag();
315 double phiRO = ROPos.phi();
316 double phiHV = HVPos.phi();
317 double phiMinPos = std::min(phiHV, phiRO);
318 double phiMaxPos = std::max(phiRO, phiHV);
320 if (std::abs(phiMin - phiMinPos) > 0.01 || std::abs(phiMax - phiMaxPos) > 0.01) {
321 ATH_MSG_DEBUG(
" inconsistent Phi!!: from locToGlob (" << phiMin <<
"," << phiMax <<
"), from positions ("
322 << phiMinPos <<
"," << phiMaxPos <<
")");
324 double rotationFraction = 0.;
325 if (phiMin < 0 && phiMax > 0) {
326 if (phiMin < -0.75 * M_PI || phiMax > 0.75 *
M_PI)
327 rotationFraction = 1.5;
329 rotationFraction = 0.5;
330 }
else if (phiMax < 0) {
331 rotationFraction = 1.;
333 double phiMinR = rotatePhi(phiMin, rotationFraction);
334 double phiMaxR = rotatePhi(phiMax, rotationFraction);
335 phiMin = std::min(phiMinR, phiMaxR);
336 phiMax = std::max(phiMinR, phiMaxR);
338 phiMinR = rotatePhi(phiMinPos, rotationFraction);
339 phiMaxR = rotatePhi(phiMaxPos, rotationFraction);
340 phiMinPos = std::min(phiMinR, phiMaxR);
341 phiMaxPos = std::max(phiMinR, phiMaxR);
344 phiMin = phiMin > 0 ? phiMin - 0.1 : phiMin + 0.1;
345 phiMax = phiMax > 0 ? phiMax + 0.1 : phiMax - 0.1;
347 double phiMinSec{1.e9},phiMaxSec{-1.e9};
348 if (stInfo.
nphi > 0 && stInfo.
phiMin < 1000) {
349 phiMinR = rotatePhi(stInfo.
phiMin, rotationFraction);
350 phiMaxR = rotatePhi(stInfo.
phiMax, rotationFraction);
351 phiMinSec = std::min(phiMinR, phiMaxR);
352 phiMaxSec = std::max(phiMinR, phiMaxR);
357 if (phiMinSec > 0 && phiMaxSec > 0) {
358 if (phiMin > phiMaxSec || phiMax < phiMinSec) inside =
false;
359 }
else if (phiMinSec < 0 && phiMaxSec < 0) {
364 if (phiMax < phiMaxSec) inside =
false;
378 phiMinR = rotatePhi(phiPatMin, rotationFraction);
379 phiMaxR = rotatePhi(phiPatMax, rotationFraction);
380 double phiMinPat = std::min(phiMinR, phiMaxR);
381 double phiMaxPat = std::max(phiMinR, phiMaxR);
383 bool insidePat =
true;
385 if (phiMinPat > 0 && phiMaxPat > 0) {
386 if (phiMin > phiMaxPat || phiMax < phiMinPat) insidePat =
false;
387 }
else if (phiMinPat < 0 && phiMaxPat < 0) {
392 if (phiMax < phiMaxPat) insidePat =
false;
407 << std::setprecision(3) << std::setw(4) << phiMin <<
"," << std::setw(4) << phiMax <<
") "
408 <<
" from pos (" << std::setprecision(3) << std::setw(4) << phiMinPos <<
"," << std::setw(4)
409 << phiMaxPos <<
") ");
410 if (stInfo.
nphi > 0 && stInfo.
phiMin < 1000) {
411 ATH_MSG_DEBUG(
" phi range (" << std::setprecision(3) << std::setw(4) << stInfo.
phiMin <<
","
412 << std::setw(4) << stInfo.
phiMax <<
") ");
414 ATH_MSG_DEBUG(
" pat range (" << std::setprecision(3) << std::setw(4) << phiMinPat <<
"," << std::setw(4)
417 << mdtDetEl->
getWireLength(layer, tube) <<
" POSL " << tubeL);
422 if (!etapattern_passed)
continue;
423 unsigned int netaPhiPairs = 0;
424 if (useTightAssociation) {
427 for (
auto& [chamberId, chamberInfo] : infoPerChamber) {
430 << chamberInfo.neta <<
" phi hits " << chamberInfo.nphi <<
" ninside "
431 << chamberInfo.ninside <<
" noutside " << chamberInfo.noutside <<
" ninside "
432 << chamberInfo.ninsidePat <<
" noutside " << chamberInfo.noutsidePat);
434 netaPhiPairs += (chamberInfo.neta && chamberInfo.nphi);
437 ATH_MSG_DEBUG(
" eta/phi pattern hit overlap " << netaPhiPairs);
438 if (!etapattern_passed) {
ATH_MSG_DEBUG(
" failed eta hit match "); }
442 if (netaPhiPairs == 0) {
ATH_MSG_DEBUG(
" Bad match, no overlap "); }
445 ATH_MSG_VERBOSE(
" Eta pattern compatible with phi pattern, eta/phi overlap " << netaPhiPairs <<
" ass phi hits "
446 << nhits_inside_distance_cut <<
" tot phi hits "
448 <<(useTightAssociation ?
" using tight association ":
"" ));
451 if ((!useTightAssociation || netaPhiPairs > 0) && nhits_inside_distance_cut >= (phipattern->
numberOfContainedPrds() * 0.25)) {
458 std::array<double,4> new_pars{r0,
phi, pattern_z0,
theta};
460 phipattern = std::move(updatedpatterns.first);
461 etapattern = std::move(updatedpatterns.second);
462 ATH_MSG_DEBUG(
" Combination accepted with cosmic selection ");
463 }
else if (useTightAssociation) {
467 std::unique_ptr<Muon::MuonPrdPattern> etaPat = std::make_unique<Muon::MuonPrdPattern>(etapattern->
globalPosition(), etapattern->
globalDirection());
468 std::unique_ptr<Muon::MuonPrdPattern> phiPat = std::make_unique<Muon::MuonPrdPattern>(phipattern->
globalPosition(), phipattern->
globalDirection());
473 std::map<Identifier, ChamberInfo>::iterator chPos = infoPerChamber.find(chId);
474 if (chPos == infoPerChamber.end())
continue;
477 if (chPos->second.ninside == 0 && chPos->second.noutside > 0)
continue;
478 if (chPos->second.ninsidePat == 0 && chPos->second.noutsidePat > 0)
continue;
480 if (chPos->second.nphi == 0)
continue;
488 std::map<Identifier, ChamberInfo>::iterator chPos = infoPerChamber.find(chId);
489 if (chPos == infoPerChamber.end())
continue;
491 if (chPos->second.neta == 0)
continue;
494 phipattern = std::move(phiPat);
495 etapattern = std::move(etaPat);
499 addCandidate(etapattern, phipattern, candidates,
false, phiEtaHitAssMap);
500 ATH_MSG_DEBUG(
"Candidate FOUND eta " << etalevel <<
" phi " << philevel <<
" dotprod: " << dotprod);
502 if (average_distance < min_average_distance) {
504 min_average_distance = average_distance;
505 max_phipattern = phipattern;
506 max_philevel = philevel;
509 << phipattern->
globalDirection().phi() <<
"average distance " << average_distance
510 <<
" number of hits " << nhits_inside_distance_cut <<
" etalevel: " << etalevel);
514 }
else if (useTightAssociation && netaPhiPairs == 0 &&
516 ATH_MSG_DEBUG(
" Combination rejected by phi/eta overlap: average distance " << average_distance);
518 if (average_distance < min_average_distance) {
520 min_average_distance = average_distance;
521 max_phipattern = phipattern;
522 max_philevel = philevel;
529 addCandidate(etapattern, max_phipattern, candidates,
true, phiEtaHitAssMap);
530 ATH_MSG_DEBUG(
"Candidate FOUND eta " << etalevel <<
" phi " << max_philevel);
537 std::unique_ptr<Muon::MuonPrdPattern> assphipattern =
makeAssPhiPattern(*etapattern, phiEtaHitAssMap,
true);
538 ATH_MSG_DEBUG(
"No match found, trying to create associated phi pattern ");
543 bool subsetcheck =
false;
545 std::reverse_iterator<std::vector<CandidatePatPair>::iterator> rit =
547 for (; rit != candidates.rend(); ++rit) {
548 if ((*rit).first != etapattern) {
break; }
550 if (
subset(assphipattern.get(), (*rit).second.get())) {
561 ATH_MSG_DEBUG(
"Candidate FOUND eta " << etalevel <<
" and associated phipattern ");
571 assphipattern = std::move(updatedpatterns.first);
572 etapattern = std::move(updatedpatterns.second);
574 ATH_MSG_DEBUG(
" adding eta pattern with recalculated associated phi pattern ");
576 addCandidate(etapattern, std::move(assphipattern), candidates,
false, phiEtaHitAssMap);
580 if (!ismatched && max_philevel > -1) {
581 addCandidate(etapattern, max_phipattern, candidates,
true, phiEtaHitAssMap);
583 ATH_MSG_DEBUG(
"No good candidate found, adding best phi pattern " << etalevel <<
" phi " << max_philevel);
587 ATH_MSG_DEBUG(
"NO COMBINED Candidate FOUND eta " << etalevel <<
" phi " << phibest);
591 candidates.emplace_back(etapattern,
nullptr);
1065 std::array<double,4> old_pars{0};
1068 old_pars[1] = phiglobaldir.phi();
1070 const double theta_orig = etaglobaldir.theta();
1071 old_pars[2] = etaglobalpos.z() * std::sin(theta_orig);
1072 old_pars[3] = theta_orig;
1074 if (phisize + etasize <= 1)
return old_pars;
1077 std::pair<double, double> rphi_start =
calculateR0Phi(phipattern, etapattern);
1079 std::pair<double, double> rphi =
calculateR0Phi(phipattern, etapattern, rphi_start.first);
1081 if (
msgLvl(MSG::DEBUG) && std::abs(std::sin(rphi.first - rphi_start.first)) > 0.15 &&
1082 std::abs(std::sin(etaglobaldir.phi() - phiglobaldir.phi())) < 0.15) {
1084 ATH_MSG_DEBUG(
"phi first: " << rphi_start.first <<
" phi second: " << rphi.first);
1085 ATH_MSG_DEBUG(
"phi etapattern: " << etaglobaldir.phi() <<
" phi phipattern: " << phiglobaldir.phi());
1088 const double phi = rphi.first;
1089 const double r0 = rphi.second;
1096 double av_radii{0.}, av_z{0.};
1098 for (
unsigned int i = 0; i < etasize; ++i) {
1101 av_radii += scphi.
apply(globalposhit.y(), globalposhit.x());
1102 av_z += globalposhit.z();
1106 av_radii /= etasize;
1111 for (
unsigned int i = 0; i < etasize; i++) {
1115 double radius = scphi.
apply(globalposhit.y(), globalposhit.x());
1116 double r_offset = radius - av_radii;
1117 double z_offset = globalposhit.z() - av_z;
1118 double weight = r_offset * r_offset + z_offset * z_offset;
1120 if (r_offset * std::cos(theta_orig) + z_offset * std::sin(theta_orig) < 0) {
sign = -1; }
1121 sumr += weight *
sign * r_offset;
1122 sumz += weight *
sign * z_offset;
1127 ATH_MSG_VERBOSE(
"av_z : " << av_z <<
" av_radii: " << av_radii <<
" sumr: " << sumr <<
" sumz: " << sumz);
1128 if (std::abs(sumr) < 0.000001 || std::abs(sumz) < 0.000001)
return old_pars;
1130 double theta = std::atan2(sumr, sumz);
1140 std::array<double,4> new_pars {r0,
phi,rz0,
theta};
1142 ATH_MSG_VERBOSE(
"updated parameters: r0: " << new_pars[0] <<
" phi: " << new_pars[1] <<
" rz0: " << new_pars[2]
1143 <<
" theta: " << new_pars[3]);
1144 ATH_MSG_VERBOSE(
"old parameters: r0: " << old_pars[0] <<
" phi: " << old_pars[1] <<
" rz0: " << old_pars[2] <<
" theta: " << old_pars[3]);
1146 if (
msgLvl(MSG::VERBOSE)) {
1148 for (
unsigned int i = 0; i < phisize; i++) {
1152 ATH_MSG_VERBOSE(
"distance to updated parameters in xy: " << distance);
1156 for (
unsigned int i = 0; i < etasize; i++) {
1160 ATH_MSG_VERBOSE(
"distance to updated parameters in xy: " << distance);
1164 for (
unsigned int i = 0; i < etasize; ++i) {
1167 double perp = scphi.
apply(globalposhit.y(),
1170 ATH_MSG_VERBOSE(
"distance to updated parameters in Rz: " << distance);
1194 const double phi_etapattern = etaglobaldir.phi();
1199 const double phi_phipattern = phiglobaldir.phi();
1202 const double phi_error_inv = 1. / 20.;
1203 const double phi_error_inv2 = phi_error_inv * phi_error_inv;
1204 const double eta_error_inv = 1. / 400.;
1205 const double eta_error_inv2 = eta_error_inv * eta_error_inv;
1210 double sum_etax{0.}, sum_etay{0.}, sum_phix{0.}, sum_phiy{0.};
1214 for (
unsigned int i = 0; i < etasize; i++) {
1217 sum_etax += globalposhit.x();
1218 sum_etay += globalposhit.y();
1221 for (
unsigned int i = 0; i < phisize; i++) {
1224 sum_phix += globalposhit.x();
1225 sum_phiy += globalposhit.y();
1228 const double av_x = (eta_error_inv2 * sum_etax + phi_error_inv2 * sum_phix) / (eta_error_inv2 * etasize + phi_error_inv2 * phisize);
1229 const double av_y = (eta_error_inv2 * sum_etay + phi_error_inv2 * sum_phiy) / (eta_error_inv2 * etasize + phi_error_inv2 * phisize);
1235 double sumx {0.}, sumy {0.};
1239 double x_min {0.}, x_max {0.}, y_min {0.}, y_max {0.}, lever_min {0.}, lever_max{0.};
1241 for (
unsigned int i = 0; i < etasize; i++) {
1244 double x_offset = globalposhit.x() - av_x;
1245 double y_offset = globalposhit.y() - av_y;
1246 double height_squared = x_offset * x_offset + y_offset * y_offset;
1247 double weight = height_squared * eta_error_inv2;
1249 if (x_offset * scphi_est.
cs + y_offset * scphi_est.
sn < 0) {
sign = -1; }
1250 sumx += weight *
sign * x_offset;
1251 sumy += weight *
sign * y_offset;
1253 if (
sign == 1 && height_squared > lever_max) {
1254 lever_max = height_squared;
1255 x_max = globalposhit.x();
1256 y_max = globalposhit.y();
1257 }
else if (
sign == -1 && height_squared > lever_min) {
1258 lever_min = height_squared;
1259 x_min = globalposhit.x();
1260 y_min = globalposhit.y();
1264 for (
unsigned int i = 0; i < phisize; i++) {
1267 double x_offset = globalposhit.x() - av_x;
1268 double y_offset = globalposhit.y() - av_y;
1269 double height_squared = x_offset * x_offset + y_offset * y_offset;
1270 double weight = height_squared * phi_error_inv2;
1272 if (x_offset * scphi_est.
cs + y_offset * scphi_est.
sn < 0) {
sign = -1; }
1273 sumx += weight *
sign * x_offset;
1274 sumy += weight *
sign * y_offset;
1276 if (
sign == 1 && height_squared > lever_max) {
1277 lever_max = height_squared;
1278 x_max = globalposhit.x();
1279 y_max = globalposhit.y();
1280 }
else if (
sign == -1 && height_squared > lever_min) {
1281 lever_min = height_squared;
1282 x_min = globalposhit.x();
1283 y_min = globalposhit.y();
1287 ATH_MSG_VERBOSE(
"av_x : " << av_x <<
" av_y: " << av_y <<
" sumx: " << sumx <<
" sumy: " << sumy);
1289 if (std::abs(sumx) < 0.000001 || std::abs(sumy) < 0.000001) {
1296 if (std::hypot(x_max - x_min , y_max - y_min) < 2000) {
1297 ATH_MSG_VERBOSE(
"lever arm too small: av_x : " << std::sqrt((x_max - x_min) * (x_max - x_min) + (y_max - y_min) * (y_max - y_min))
1298 <<
" x_max: " << x_max <<
" x_min: " << x_min <<
" y_max: " << y_max
1299 <<
" y_min: " << y_min);
1303 double phi_fit = std::atan2(sumy, sumx);
1304 if (phi_fit > 0) phi_fit -=
M_PI;
1306 const double r0_fit = scphi.
apply(av_x, -av_y);
1308 return std::make_pair(phi_fit, r0_fit);
1592 std::vector<CandidatePatPair>& candidates,
bool add_asspattern,
1595 candidates.emplace_back(etapattern, phipattern);
1599 std::vector<PrdPatternPair> splitpatterns =
splitPatternsCylinder(phipattern.get(), etapattern.get());
1601 if (splitpatterns.empty()) {
1602 candidates.emplace_back(etapattern, phipattern);
1606 for (
auto& [phiPattern, etaPattern] : splitpatterns) {
1609 if (etaPattern->numberOfContainedPrds() == 0) {
1612 candidates.emplace_back(std::move(etaPattern), std::move(phiPattern));
1618 if (!add_asspattern) { return ;}
1619 std::unique_ptr<Muon::MuonPrdPattern> assphipattern =
makeAssPhiPattern(*etapattern, phiEtaHitAssMap,
true);
1621 if (!assphipattern) {
return;}
1624 if (
msgLvl(MSG::VERBOSE)) {
1633 std::unique_ptr<Muon::MuonPrdPattern>& cosmicPhiPattern = updatedpatterns.first;
1634 std::unique_ptr<Muon::MuonPrdPattern>& cosmicEtaPattern = updatedpatterns.second;
1636 std::vector<PrdPatternPair> splitpatterns_ass =
splitPatternsCylinder(cosmicPhiPattern.get(), cosmicEtaPattern.get());
1637 if (splitpatterns_ass.empty()) {
1638 candidates.emplace_back(std::move(cosmicEtaPattern), std::move(cosmicPhiPattern));
1643 for (
auto& [splitPhiPattern, splitEtaPattern] : splitpatterns_ass) {
1644 if (splitPhiPattern->numberOfContainedPrds() == 0 ||
1645 splitEtaPattern->numberOfContainedPrds() == 0) {
1648 candidates.emplace_back(std::move(splitEtaPattern), std::move(splitPhiPattern));