Combines phi and eta pattern collection into a new combined pattern collection.
vector of etapatterns (key) and phipatterns (value), that are candidates for combining. Both etapatterns and phipatterns can occur multiple times
72 {
73 bool myDebug = false;
74
79
80
81
82
83
84
85
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)
93 );
94
95 for (
unsigned int etalevel = 0; etalevel < etaPatternCollection.
size(); etalevel++) {
97 if (etapattern->numberOfContainedPrds() == 0) continue;
98 const Amg::Vector3D etaPatDir = etapattern->globalDirection().unit();
99 const Amg::Vector3D& etaPatPos = etapattern->globalPosition();
100 double theta = etaPatDir.theta();
101 const double phieta = etaPatDir.phi();
102 CxxUtils::sincos scphieta(phieta);
103 CxxUtils::sincos sctheta(
theta);
104 double z0 = etaPatPos.z();
105 double rz0 =
z0 * sctheta.sn;
106
107 double eta_x = etaPatPos.x();
108 double eta_y = etaPatPos.y();
109 double pattern_z0 =
z0 + etaPatPos.perp() * sctheta.cs / sctheta.sn;
110
111
113 const double charge = eta_r0>= 0. ? 1. : -1;
114
115 const double curvature = etapattern->globalDirection().mag();
116 const double invcurvature = curvature > 2 ?
charge / curvature : 0.;
117
118 ATH_MSG_DEBUG(
" eta pattern info level: " << etalevel <<
" phi " << phieta <<
" theta " <<
theta <<
" x0 " << eta_x <<
" y0 "
119 << eta_y << " z0 " << z0 << " hits " << etapattern->numberOfContainedPrds());
120
123 int max_philevel = -1;
124
125 double dotprodbest = -1.;
126 int phibest = -1;
127 bool ismatched = false;
128 for (
unsigned int philevel = 0; philevel < phiPatternCollection.
size(); philevel++) {
129 CandPrdPatPtr phipattern{phiPatternCollection.
at(philevel), Unowned()};
130 if (phipattern->numberOfContainedPrds() == 0) continue;
131 bool useTightAssociation = false;
132
136 ATH_MSG_DEBUG(
" using tight cuts due to phi hits " << phipattern->numberOfContainedPrds() <<
" cut "
139 ATH_MSG_DEBUG(
" using tight cuts due to eta hits " << etapattern->numberOfContainedPrds() <<
" cut "
141 useTightAssociation = true;
142 }
143
144 const Amg::Vector3D phiPatDir = phipattern->globalDirection().unit();
145 const double dotprod = phiPatDir.dot(etaPatDir);
146
147 if (dotprod > dotprodbest) {
148 dotprodbest = dotprod;
149 phibest = philevel;
150 }
151
153 ATH_MSG_DEBUG(
" eta nr " << etalevel <<
" phi nr " << philevel <<
" inproduct " << dotprod <<
" sin angle "
154 << std::sin(std::acos(dotprod)));
155 }
156
157 double r0{0.}, phipattern_x{0.}, phipattern_y{0.},
phi{phiPatDir.phi()};
158 CxxUtils::sincos scphi{
phi};
160
164 rz0 = new_pars[2];
166 scphi = CxxUtils::sincos(
phi);
167 sctheta = CxxUtils::sincos(
theta);
168 phipattern_x =
r0 * scphi.
sn;
169 phipattern_y =
r0 * scphi.
cs;
170 } else {
171 const Amg::Vector3D posphipattern = phipattern->globalPosition();
172 phipattern_x = posphipattern.x();
173 phipattern_y = posphipattern.y();
175 }
176
177
178
179
180
181
182
184
186
187
188 std::map<Identifier, ChamberInfo> infoPerChamber;
189 std::map<Muon::MuonStationIndex::StIndex, ChamberInfo> infoPerStation;
190
191 double average_distance{0};
192 int nhits_in_average{0}, nhits_inside_distance_cut{0};
193
194 double phiPatMin{1e9}, phiPatMax{-1e9};
195
196 for (unsigned int phihitid = 0; phihitid < phipattern->numberOfContainedPrds(); phihitid++) {
197 const Trk::PrepRawData* prd = phipattern->prd(phihitid);
199 double radius_hit = globalposhit.perp();
200 double dotprodradius = sctheta.apply(radius_hit, globalposhit.z());
203
204 double residu_distance_mm{100.*Gaudi::Units::meter};
206 const double perp = scphi.
apply(globalposhit.y(), globalposhit.x());
208 } else {
210 }
211
212 double distancetoline = std::abs(residu_distance_mm);
213
216
218 nhits_inside_distance_cut++;
219 nhits_in_average++;
220 average_distance += distancetoline;
221
222 if (!useTightAssociation) { continue; }
225 ++chInfo.nphi;
226 double hitphi = globalposhit.phi();
227 chInfo.phiMin = std::min(hitphi,chInfo.phiMin);
228 chInfo.phiMax = std::min(hitphi,chInfo.phiMax);
229
232 ++stInfo.nphi;
233 stInfo.phiMin = std::min(hitphi, stInfo.phiMin);
234 stInfo.phiMax = std::max(hitphi, stInfo.phiMax);
235 phiPatMin =std::min(hitphi,phiPatMin);
236 phiPatMax =std::max(hitphi,phiPatMax);
237
238 }
239
240 if (nhits_in_average > 0) average_distance /= nhits_in_average;
241
242 ATH_MSG_DEBUG(
" Result for phi pattern: accepted hits " << nhits_inside_distance_cut <<
" average distance "
243 << average_distance);
244
245 bool etapattern_passed = false;
246 for (unsigned int etahitid = 0; etahitid < etapattern->numberOfContainedPrds(); etahitid++) {
247 const Trk::PrepRawData* prd = etapattern->prd(etahitid);
249 const double etahitx = etaglobalposhit.x();
250 const double etahity = etaglobalposhit.y();
251
253 double etadotprod = scphi.
apply(etahity, etahitx);
254
255 if (etadotprod < 0) continue;
256 }
257
258 const double xdiff = phipattern_x - etahitx;
259 const double ydiff = phipattern_y - etahity;
260 const double etahitr = std::hypot(xdiff, ydiff);
261
262 bool hit_passed = false;
264
266
268
269
270 const double scale = etahitr / 7000.;
272 } else if (2 * etadistancetoline < etahitr) {
273
274 hit_passed = true;
275 }
276
277 if (!hit_passed) { continue; }
278
279 etapattern_passed = true;
280
282
283 if (!useTightAssociation) { continue ;}
285
287 ++chInfo.neta;
291
292 const MuonGM::MdtReadoutElement* mdtDetEl =
293 dynamic_cast<const MuonGM::MdtReadoutElement*
>(prd->
detectorElement());
294 if (!mdtDetEl) continue;
295
296 const Identifier
id = prd->
identify();
297 const Trk::Surface& surf = mdtDetEl->
surface(
id);
300 double halfLength = 0.5 * mdtDetEl->
getWireLength(layer, tube);
303 double phiLeft = gposLeft.phi();
304
307 double phiRight = gposRight.phi();
308 double phiMin = std::min(phiRight, phiLeft);
309 double phiMax = std::max(phiLeft ,phiRight);
310
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);
319
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 << ")");
323 }
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;
328 else
329 rotationFraction = 0.5;
330 } else if (phiMax < 0) {
331 rotationFraction = 1.;
332 }
333 double phiMinR = rotatePhi(phiMin, rotationFraction);
334 double phiMaxR = rotatePhi(phiMax, rotationFraction);
335 phiMin = std::min(phiMinR, phiMaxR);
336 phiMax = std::max(phiMinR, phiMaxR);
337
338 phiMinR = rotatePhi(phiMinPos, rotationFraction);
339 phiMaxR = rotatePhi(phiMaxPos, rotationFraction);
340 phiMinPos = std::min(phiMinR, phiMaxR);
341 phiMaxPos = std::max(phiMinR, phiMaxR);
342
343
344 phiMin = phiMin > 0 ? phiMin - 0.1 : phiMin + 0.1;
345 phiMax = phiMax > 0 ? phiMax + 0.1 : phiMax - 0.1;
346
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);
353
355
356
357 if (phiMinSec > 0 && phiMaxSec > 0) {
358 if (phiMin > phiMaxSec || phiMax < phiMinSec)
inside =
false;
359 } else if (phiMinSec < 0 && phiMaxSec < 0) {
360
362 } else {
363
364 if (phiMax < phiMaxSec)
inside =
false;
365 }
366
367 if (inside) {
368 ++stInfo.ninside;
369 ++chInfo.ninside;
371 } else {
372 ++stInfo.noutside;
373 ++chInfo.noutside;
375 }
376 }
377
378 phiMinR = rotatePhi(phiPatMin, rotationFraction);
379 phiMaxR = rotatePhi(phiPatMax, rotationFraction);
380 double phiMinPat = std::min(phiMinR, phiMaxR);
381 double phiMaxPat = std::max(phiMinR, phiMaxR);
382
383 bool insidePat = true;
384
385 if (phiMinPat > 0 && phiMaxPat > 0) {
386 if (phiMin > phiMaxPat || phiMax < phiMinPat) insidePat = false;
387 } else if (phiMinPat < 0 && phiMaxPat < 0) {
388
389 insidePat = false;
390 } else {
391
392 if (phiMax < phiMaxPat) insidePat = false;
393 }
394
395
396 if (insidePat) {
397 ++stInfo.ninsidePat;
398 ++chInfo.ninsidePat;
400 } else {
401 ++stInfo.noutsidePat;
402 ++chInfo.noutsidePat;
404 }
405 if (myDebug) {
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 << ") ");
413 }
414 ATH_MSG_DEBUG(
" pat range (" << std::setprecision(3) << std::setw(4) << phiMinPat <<
"," << std::setw(4)
417 << mdtDetEl->
getWireLength(layer, tube) <<
" POSL " << tubeL);
418 }
419 }
420 }
421
422 if (!etapattern_passed) continue;
423 unsigned int netaPhiPairs = 0;
424 if (useTightAssociation) {
425
426
427 for ( auto& [chamberId, chamberInfo] : infoPerChamber) {
428
430 << chamberInfo.neta << " phi hits " << chamberInfo.nphi << " ninside "
431 << chamberInfo.ninside << " noutside " << chamberInfo.noutside << " ninside "
432 << chamberInfo.ninsidePat << " noutside " << chamberInfo.noutsidePat);
433
434 netaPhiPairs += (chamberInfo.neta && chamberInfo.nphi);
435 }
436
437 ATH_MSG_DEBUG(
" eta/phi pattern hit overlap " << netaPhiPairs);
438 if (!etapattern_passed) {
ATH_MSG_DEBUG(
" failed eta hit match "); }
439 if (nhits_inside_distance_cut < (phipattern->numberOfContainedPrds() * 0.25)) {
441 }
442 if (netaPhiPairs == 0) {
ATH_MSG_DEBUG(
" Bad match, no overlap "); }
443
444 }
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 "
447 << phipattern->numberOfContainedPrds()
448 <<(useTightAssociation ? " using tight association ": "" ));
449
450
451 if ((!useTightAssociation || netaPhiPairs > 0) && nhits_inside_distance_cut >= (phipattern->numberOfContainedPrds() * 0.25)) {
452 ismatched = true;
453
454
455
456
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) {
465
466
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());
469 for (unsigned int etahitid = 0; etahitid < etapattern->numberOfContainedPrds(); ++etahitid) {
470 const Trk::PrepRawData* prd = etapattern->prd(etahitid);
471 const Identifier
id = prd->
identify();
473 std::map<Identifier, ChamberInfo>::iterator chPos = infoPerChamber.find(chId);
474 if (chPos == infoPerChamber.end()) continue;
475
477 if (chPos->second.ninside == 0 && chPos->second.noutside > 0) continue;
478 if (chPos->second.ninsidePat == 0 && chPos->second.noutsidePat > 0) continue;
479 } else {
480 if (chPos->second.nphi == 0) continue;
481 }
482 etaPat->addPrd(prd);
483 }
484 for (unsigned int phihitid = 0; phihitid < phipattern->numberOfContainedPrds(); ++phihitid) {
485 const Trk::PrepRawData* prd = phipattern->prd(phihitid);
486 const Identifier&
id = prd->
identify();
488 std::map<Identifier, ChamberInfo>::iterator chPos = infoPerChamber.find(chId);
489 if (chPos == infoPerChamber.end()) continue;
490
491 if (chPos->second.neta == 0) continue;
492 phiPat->addPrd(prd);
493 }
494 phipattern = std::move(phiPat);
495 etapattern = std::move(etaPat);
496 }
497
499 addCandidate(etapattern, phipattern, candidates,
false, phiEtaHitAssMap);
500 ATH_MSG_DEBUG(
"Candidate FOUND eta " << etalevel <<
" phi " << philevel <<
" dotprod: " << dotprod);
501 } else {
502 if (average_distance < min_average_distance) {
504 min_average_distance = average_distance;
505 max_phipattern = phipattern;
506 max_philevel = philevel;
507 }
508 ATH_MSG_DEBUG(
" theta pattern " << etapattern->globalDirection().theta() <<
" phi "
509 << phipattern->globalDirection().phi() << "average distance " << average_distance
510 << " number of hits " << nhits_inside_distance_cut << " etalevel: " << etalevel);
511 }
512
513
514 } else if (useTightAssociation && netaPhiPairs == 0 &&
515 nhits_inside_distance_cut >= (phipattern->numberOfContainedPrds() * 0.25)) {
516 ATH_MSG_DEBUG(
" Combination rejected by phi/eta overlap: average distance " << average_distance);
517
518 if (average_distance < min_average_distance) {
520 min_average_distance = average_distance;
521 max_phipattern = phipattern;
522 max_philevel = philevel;
523 }
524 }
525 }
526
527
529 addCandidate(etapattern, max_phipattern, candidates,
true, phiEtaHitAssMap);
530 ATH_MSG_DEBUG(
"Candidate FOUND eta " << etalevel <<
" phi " << max_philevel);
531 }
532
533
534
535
537 std::unique_ptr<Muon::MuonPrdPattern> assphipattern =
makeAssPhiPattern(*etapattern, phiEtaHitAssMap,
true);
538 ATH_MSG_DEBUG(
"No match found, trying to create associated phi pattern ");
539 if (assphipattern) {
540
541
542
543 bool subsetcheck = false;
544
545 std::reverse_iterator<std::vector<CandidatePatPair>::iterator> rit =
548 if ((*rit).first != etapattern) { break; }
549
550 if (
subset(assphipattern.get(), (*rit).second.get())) {
551 subsetcheck = true;
552 break;
553 }
554 }
555 if (subsetcheck) {
556
557 } else {
558
559
560
561 ATH_MSG_DEBUG(
"Candidate FOUND eta " << etalevel <<
" and associated phipattern ");
562
563 ismatched = true;
564
565
567
571 assphipattern = std::move(updatedpatterns.first);
572 etapattern = std::move(updatedpatterns.second);
573 }
574 ATH_MSG_DEBUG(
" adding eta pattern with recalculated associated phi pattern ");
575
576 addCandidate(etapattern, std::move(assphipattern), candidates,
false, phiEtaHitAssMap);
577 }
578 }
579 }
580 if (!ismatched && max_philevel > -1) {
581 addCandidate(etapattern, max_phipattern, candidates,
true, phiEtaHitAssMap);
582 ismatched = true;
583 ATH_MSG_DEBUG(
"No good candidate found, adding best phi pattern " << etalevel <<
" phi " << max_philevel);
584 }
585 if (!ismatched) {
587 ATH_MSG_DEBUG(
"NO COMBINED Candidate FOUND eta " << etalevel <<
" phi " << phibest);
590 }
592 } else {
594 }
595 }
597
598}
Scalar perp() const
perp method - perpendicular length
Scalar mag() const
mag method
const T * at(size_type n) const
Access an element, as an rvalue.
size_type size() const noexcept
Returns the number of elements in the collection.
double getActiveTubeLength(const int tubeLayer, const int tube) const
Amg::Vector3D tubePos(const Identifier &id) const
Returns the global position of the given tube.
Amg::Vector3D ROPos(const int tubelayer, const int tube) const
virtual const Trk::Surface & surface() const override final
Return surface associated with this detector element.
double getWireLength(const int tubeLayer, const int tube) const
static double signedDistanceToLine(double x0, double y0, double r0, double phi)
distance from (x0,y0) to the line (r0,phi), phi in rad
virtual const TrkDetElementBase * detectorElement() const =0
return the detector element corresponding to this PRD The pointer will be zero if the det el is not d...
virtual void localToGlobal(const Amg::Vector2D &locp, const Amg::Vector3D &mom, Amg::Vector3D &glob) const =0
Specified by each surface type: LocalToGlobal method without dynamic memory allocation.
Eigen::Matrix< double, 2, 1 > Vector2D
StIndex
enum to classify the different station layers in the muon spectrometer
double apply(double a, double b) const