15 return angle / Gaudi::Units::deg;
20using namespace Acts::UnitLiterals;
23 std::unique_ptr<const Acts::Logger>
logger) :
26 static_assert(std::is_move_assignable_v<PatternState>);
27 static_assert(std::is_move_constructible_v<PatternState>);
28 static_assert(std::is_copy_assignable_v<PatternState>);
29 static_assert(std::is_copy_constructible_v<PatternState>);
30 static_assert(std::is_nothrow_move_constructible_v<PatternState>);
31 static_assert(std::is_nothrow_move_assignable_v<PatternState>);
35std::vector<GlobalPattern>
37 std::span<const SpacePointContainer*> spacepoints)
const {
43 auto visualInfo {
m_cfg.visionTool ? std::make_unique<std::vector<PatHitVisual>>() :
nullptr};
56 m_cfg.visionTool->plotPatternBuckets(Gaudi::Hive::currentContext(),
"GlobPatFind_", std::move(*visualInfo));
63 std::vector<PatHitVisual>* visualInfo)
const {
68 std::vector<CandidateHit> candidateHits{};
69 candidateHits.reserve(100);
73 startPatternBuff.reserve(10);
74 endPatternBuff.reserve(10);
80 outPatterns.reserve(10);
87 const SearchTree_t::coordinate_t& coords) -> uint8_t {
89 if (std::abs(pattern.patTheta - coords[thetaIdx]) > 2.*
m_cfg.thetaSearchWindow ||
90 !pattern.expSect.isNeighbour(
94 return pattern.isInPattern(
hit);
98 for (
const auto seedingLayer :
m_cfg.layerSeedings) {
100 for (
const auto& [seedCoords, seedPtr] : orderedSpacepoints) {
105 if (seedLayer != seedingLayer || (seed->isStraw() && !
m_cfg.seedFromMdt)) {
108 ACTS_VERBOSE(__func__<<
"() New seed hit "<<*seed<<
", coordinates ["<<seedCoords[0]<<
", "<<seedCoords[1]<<
"]");
110 uint8_t nExistingPatterns {countPatterns(outPatterns, seed, seedCoords)};
111 if (nExistingPatterns >=
m_cfg.maxSeedAttempts) {
114 nExistingPatterns = countPatterns(outPatterns,seed, seedCoords);
115 if (nExistingPatterns >=
m_cfg.maxSeedAttempts) {
116 ACTS_VERBOSE(__func__<<
"() Seed has already been used in "
117 <<
static_cast<int>(nExistingPatterns)
118 <<
" patterns, which is above the limit - skip this seed.");
123 SearchTree_t::range_t selectRange{};
125 selectRange[sectorIdx].shrink(seedCoords[sectorIdx] - 0.1, seedCoords[sectorIdx] + 0.1);
129 const double thetaHalfWindow {(seedLayer == LayerIndex::Inner || seedLayer == LayerIndex::Outer)
130 ?
m_cfg.thetaSearchWindow : 0.5*
m_cfg.thetaSearchWindow};
131 selectRange[thetaIdx].shrink(seedCoords[thetaIdx] - thetaHalfWindow, seedCoords[thetaIdx] + thetaHalfWindow);
133 candidateHits.clear();
134 orderedSpacepoints.rangeSearchMapDiscard(selectRange, [&](
const SearchTree_t::coordinate_t& ,
136 candidateHits.emplace_back(
hit, 0u);
138 if (candidateHits.size() <
m_cfg.minTriggerLayers +
m_cfg.minPrecisionLayers) {
139 ACTS_VERBOSE(__func__<<
"() Found "<<candidateHits.size()<<
" candidate hits, below minimum required - skip seed.");
143 if (std::ranges::none_of(candidateHits, [
this, seedLayer](
const CandidateHit& c){
144 return m_cfg.idHelperSvc->layerIndex(c.sp()->identify()) != seedLayer; }) ) {
145 ACTS_VERBOSE(__func__<<
"() All candidates in same station layer, and we need at least two - skip seed.");
153 return c1.sp()->localPosition().y() < c2.sp()->localPosition().y();
158 for (std::size_t i {1}; i < candidateHits.size(); ++i) {
159 candidateHits[i].globLayer = candidateHits[i - 1].globLayer +
162 if (candidateHits.back().globLayer + 1u < (
m_cfg.minTriggerLayers +
m_cfg.minPrecisionLayers)) {
163 ACTS_VERBOSE(__func__<<
"() Found "<<candidateHits.size()<<
" candidate hits on "
164 <<
static_cast<int>(candidateHits.back().globLayer + 1u)
165 <<
" layers, below the minimum required - skip this seed.");
168 if (
m_logger->level() <= Acts::Logging::Level::VERBOSE) {
169 ACTS_VERBOSE(__func__<<
"() Found "<< candidateHits.size()<<
" candidate hits: ");
170 for (
const auto& c : candidateHits) {
171 ACTS_VERBOSE(__func__<<
"() \t**"<<c);
176 const auto seedItr {std::ranges::find_if(candidateHits,
178 assert(seedItr != candidateHits.end());
183 patternSeed.
visualInfo = std::make_unique<PatHitVisual>(
184 seed.spacePoint, seedCoords[thetaIdx] - thetaHalfWindow, seedCoords[thetaIdx] + thetaHalfWindow);
195 auto processHitRange = [&](
const auto begin,
198 startPatternBuff.clear();
199 startPatternBuff.push_back(std::move(toExtend));
201 for (
auto testItr = begin; testItr != end; ++testItr) {
206 extendPatterns(gctx, startPatternBuff, endPatternBuff, testHit, beamSpot, visualInfo);
208 std::swap(startPatternBuff, endPatternBuff);
210 return startPatternBuff.size() > 1
216 PatternStateVec forwardExtended {processHitRange(std::next(seedItr), candidateHits.end(), std::move(patternSeed))};
219 ACTS_VERBOSE(__func__<<
"() Finished forward search, found "<<forwardExtended.size()<<
" forward patterns, start backward search.");
221 backwardExtended.reserve(2*forwardExtended.size());
224 ACTS_VERBOSE(__func__<<
"() Start backward search for pattern "<<
detailed(pat));
225 pat.moveLineAnchorHit(seedCand);
226 pat.lastInsertedHit = seedCand;
230 processHitRange(std::reverse_iterator(seedItr), candidateHits.rend(), std::move(pat)),
231 std::back_inserter(backwardExtended)
235 if (backwardExtended.size() > 1) {
240 pat.meanNormResidual2 /= pat.nBendingLayers();
245 ACTS_VERBOSE(__func__<<
"() Add new pattern "<<
detailed(pat));
246 pat.isFinalized =
true;
247 outPatterns.push_back(std::move(pat));
251 ACTS_VERBOSE(__func__<<
"() Found in total "<<outPatterns.size()<<
" patterns in eta before overlap removal");
259 std::vector<PatHitVisual>* visualInfo)
const {
261 ACTS_VERBOSE(__func__<<
"() *** Test "<<testHit<<
" against " << startPatterns.size() <<
" active patterns.");
265 auto missedLayers = [&testHit](
const PatternState& pat) ->
unsigned {
266 return std::abs(pat.lastInsertedHit.globLayer - testHit.
globLayer);
269 unsigned minMissedLayers {std::numeric_limits<unsigned>::max()};
270 std::ranges::for_each(startPatterns, [&missedLayers, &minMissedLayers](
const PatternState& pat){
271 minMissedLayers = std::min(minMissedLayers, missedLayers(pat));
274 const bool shouldPrune {startPatterns.size() > 1 &&
275 std::ranges::any_of(startPatterns, [](
const PatternState& p){
276 return p.nBendingLayers() > 2; })};
278 for (
auto [i, pat] : Acts::enumerate(startPatterns)) {
284 if (pat.lastInsertedHit->station == testHit->
station &&
285 missedLayers(pat) > std::max(
m_cfg.maxMissLayersInStation, minMissedLayers)) {
286 ACTS_VERBOSE(__func__<<
"() Pattern " <<
detailed(pat) <<
"\nhas missed " << (
int)missedLayers(pat)
287 <<
" layer hits, above the max allowed - abort pattern.");
294 if (shouldPrune && pat.lastInsertedHit.globLayer != testHit.
globLayer &&
295 std::ranges::find_if(std::next(startPatterns.begin(), i + 1), startPatterns.end(), [&](
PatternState& p){
296 if (p.lastInsertedHit != pat.lastInsertedHit || p.isOverlap) return false;
298 if (isBetter(pat, p)) {
299 ACTS_VERBOSE(
"extendPatterns() Pruning: "<<detailed(pat)<<
"\nis BETTER than "<<detailed(p));
303 ACTS_VERBOSE(
"extendPatterns() Pruning: "<<
detailed(p)<<
"\nis BETTER than "<<
detailed(pat));
304 return true; }) != startPatterns.end()) {
309 const auto [residual, resSigma, result] {pat.checkLineComp(gctx,testHit, beamSpot)};
313 const bool lowConfidenceRes {resSigma >
m_cfg.lowConfidenceResSigma &&
314 residual / resSigma > 2.};
315 if (lowConfidenceRes) {
316 ACTS_VERBOSE(__func__<<
"() Low-confidence hit: residual pull "<<residual / resSigma);
320 if (std::ranges::any_of(endPatterns, [&testHit, &pat](
const PatternState& p) {
321 return p.lastInsertedHit == testHit &&
322 (p.prevLayerHit == pat.lastInsertedHit || p.nBendingLayers() > (pat.nBendingLayers() + 1u)); })) {
323 ACTS_VERBOSE(__func__<<
"() Forking leads to existing pattern - reject.");
327 endPatterns.push_back(pat);
328 endPatterns.back().addHit(testHit, residual, resSigma);
331 pat.visualInfo->discardedHits.push_back(testHit.
sp());
335 ACTS_VERBOSE(__func__<<
"() Hit compatible - add to pattern. Residual pull "<<residual / resSigma);
336 pat.addHit(testHit, residual, resSigma);
341 if (std::ranges::any_of(endPatterns, [&testHit, &pat](
const PatternState& p) {
342 return p.lastInsertedHit == testHit && p.prevLayerHit == pat.prevLayerHit; })) {
343 ACTS_VERBOSE(__func__<<
"() Hit compatible & on same layer of last added hit - branched pattern already exists.");
347 ACTS_VERBOSE(__func__<<
"() Hit compatible & on same layer of last added hit - branch pattern.");
348 endPatterns.push_back(pat);
349 endPatterns.back().overWriteHit(testHit, residual, resSigma);
353 pat.visualInfo->discardedHits.push_back(testHit.
sp());
358 ACTS_VERBOSE(__func__<<
"() Hit is not compatible with the pattern - reject hit.");
360 pat.visualInfo->discardedHits.push_back(testHit.
sp());
365 endPatterns.push_back(std::move(pat));
367 startPatterns.clear();
371 if (pat.nTriggerLayers <
m_cfg.minTriggerLayers ||
372 pat.nPrecisionLayers <
m_cfg.minPrecisionLayers ||
373 std::ranges::count_if(pat.hitsPerStation,
374 [
this](
const auto& hits) { return hits.size() >= m_cfg.minStationLayers; }) < 2) {
375 ACTS_VERBOSE(__func__<<
"() Pattern " <<
detailed(pat) <<
"\ndoes not meet minimum layer requirements - reject.");
379 if (pat.meanNormResidual2 >
m_cfg.meanNormRes2Cut) {
380 ACTS_VERBOSE(__func__<<
"() Pattern " <<
detailed(pat) <<
"\ndoes not meet the mean norm residual2 cut - reject.");
387 std::vector<PatHitVisual>* visualInfo)
const {
388 ACTS_VERBOSE(__func__<<
"() Resolving overlaps among "<<toResolve.size()<<
" patterns.");
390 outputPatterns.reserve(toResolve.size());
394 if(!
a.expSect.isNeighbour(b.expSect)) {
398 if (std::abs(
a.patTheta - b.patTheta) > 2.*
m_cfg.thetaSearchWindow) {
401 if (
a.nPhiLayers > 0 && b.nPhiLayers > 0) {
405 }
else if (
a.nPhiLayers > 0) {
406 if (!sectorMap.insideSector(b.expSect.msSector(),
a.patPhi) ||
407 !sectorMap.insideSector(b.expSect.adjacentMsSector(),
a.patPhi)) {
410 }
else if (b.nPhiLayers > 0) {
411 if (!sectorMap.insideSector(
a.expSect.msSector(), b.patPhi) ||
412 !sectorMap.insideSector(
a.expSect.adjacentMsSector(), b.patPhi)) {
417 std::size_t nSharedHits{0}, nSharedStations{0};
419 const auto& hitsA {
a.hitsPerStation[st]};
420 const auto& hitsB {b.hitsPerStation[st]};
421 if (hitsA.empty() || hitsB.empty()) {
424 const std::size_t nSharedInStation = std::ranges::count_if(hitsA, [&](
const CandidateHit& hitA){
425 return std::ranges::any_of(hitsB, [&hitA](
const CandidateHit& hitB) {
429 nSharedHits += nSharedInStation;
430 if (nSharedInStation >=
m_cfg.minStationLayers) {
435 const std::size_t minHits {std::min(
a.nBendingLayers(), b.nBendingLayers())};
436 const std::size_t minStations {std::min(
a.nStations(
true), b.nStations(
true))};
437 return nSharedHits >= 0.5 *minHits && nSharedStations >= std::min(2ul, minStations);
441 const int nGoodStationDiff {
a.nStations(
true) - b.nStations(
true)};
442 if (nGoodStationDiff != 0) {
443 return nGoodStationDiff > 0;
448 for (
auto it = toResolve.begin(); it != toResolve.end(); ++it) {
454 for (
auto jt = std::next(it); jt != toResolve.end(); ++jt) {
455 if (jt->isOverlap || !areOverlapping(*it, *jt)) {
458 if (isBetterOverlap(*it, *jt)) {
459 ACTS_VERBOSE(__func__<<
"() Pattern "<<
detailed(*it)<<
"\nis BETTER than "<<
detailed(*jt));
460 jt->isOverlap =
true;
462 it->isOverlap =
true;
463 ACTS_VERBOSE(__func__<<
"() Pattern "<<
detailed(*jt)<<
"\nis BETTER than "<<
detailed(*it));
467 if (!it->isOverlap) {
468 outputPatterns.push_back( std::move(*it));
474 ACTS_VERBOSE(__func__<<
"() Patterns surviving overlap removal: "<< outputPatterns.size());
475 return outputPatterns;
479 auto computePatternLineInStation = [&](
PatternState& pat,
480 const StIndex station) ->
bool {
481 const std::vector<CandidateHit>& stationHits {
482 pat.hitsPerStation[Acts::toUnderlying(station)]};
483 if(stationHits.empty()) {
488 pat.useBeamspot =
true;
490 if (stationHits.size() > 1) {
492 const auto [minIt, maxIt] {std::ranges::minmax_element(stationHits, {},
494 pat.lineAnchorHit = *minIt;
495 pat.lastInsertedHit = *maxIt;
496 pat.updateLineParameters(gctx.
context(), Amg::Vector3D::Zero());
498 if (pat.useBeamspot) {
501 pat.moveLineAnchorHit(stationHits.front());
502 pat.lastInsertedHit = *std::ranges::max_element(stationHits, {},
504 return (pat.projToPhiPlane(gctx.
context(), *c) -
505 pat.projToPhiPlane(gctx.
context(), *pat.lineAnchorHit)).mag(); });
506 pat.updateLineParameters(gctx.
context(), Amg::Vector3D::Zero());
508 return !pat.useBeamspot;
512 survivingPatterns.reserve(
patterns.size());
515 ACTS_VERBOSE(__func__<<
"() Search for phi-only hits for pattern: " <<
brief(pat));
517 std::optional<StIndex> patterLineStation{std::nullopt};
520 return pos - pos.dot(pat.bendPlaneNorm) * pat.bendPlaneNorm;
525 const Acts::Transform3& localToGlobal {bucket->msSector()->localToGlobalTransform(gctx)};
526 const StIndex station {
m_cfg.idHelperSvc->stationIndex(bucket->front()->identify())};
528 for (
const auto&
hit : *bucket) {
530 if (
hit->measuresEta()){
533 ACTS_VERBOSE(__func__<<
"() *** Test phi-only hit "<<*
hit);
537 const std::vector<CandidateHit>& stationHits {
538 pat.hitsPerStation[Acts::toUnderlying(station)]};
539 assert(!stationHits.empty());
540 if (std::ranges::any_of(stationHits, [&](
const CandidateHit&
h){
541 return h.sp()->measuresPhi() &&
542 hit->msSector() ==
h.sp()->msSector() &&
545 std::ranges::any_of(pat.phiOnlyHits, [&](
const HitPayload&
h){
546 return station == h.station &&
547 hit->msSector() == h->msSector() &&
548 newHit.locLayer == h.locLayer;
550 ACTS_VERBOSE(__func__<<
"() The pattern already has a phi hit in the same layer - skip hit.");
554 if (!pat.isPhiCompatible(newHit)) {
555 ACTS_VERBOSE(__func__<<
"() Phi-only hit not compatible");
559 if (!patterLineStation || *patterLineStation != station) {
560 if (!computePatternLineInStation(pat, station)) {
561 ACTS_VERBOSE(__func__<<
"() Invalid projection model for station "<<station<<
" - skip hit.");
564 patterLineStation = station;
567 const double stripHalfLength {
571 projOntoPhiPlane(newHit.
position - stripHalfLength * sensorDir)};
573 projOntoPhiPlane(newHit.
position + stripHalfLength * sensorDir)};
576 const double stripIntersect {Acts::detail::LineHelper::lineIntersect<3>(
577 pat.linePos, pat.lineDir, stripLow, stripDirOnPlane).pathLength()};
578 const double stripProjLength {(stripHigh - stripLow).
mag()};
580 ACTS_VERBOSE(__func__<<
"() Intersect distance from lower strip edge: "
581 <<stripIntersect<<
", proj strip length: "<< (stripHigh - stripLow).
mag());
583 constexpr double margin {10 * Gaudi::Units::mm};
584 if (stripIntersect < -margin || stripIntersect > (stripProjLength + margin)) {
585 ACTS_VERBOSE(__func__<<
"() The pattern falls outside the test hit strip in eta - skip hit.");
588 pat.phiOnlyHits.push_back(std::move(newHit));
590 pat.updatePatternPhi();
593 if (pat.nPhiLayers <
m_cfg.minPhiLayers) {
594 ACTS_VERBOSE(__func__<<
"() Pattern "<<
detailed(pat)
595 <<
" has only "<<
static_cast<int>(pat.nPhiLayers)
596 <<
" phi layers, below the minimum required - reject this pattern.");
599 survivingPatterns.push_back(std::move(pat));
605 std::vector<const SpacePointBucket*> parentBuckets{};
608 const auto& hits {cache.hitsPerStation[st]};
609 if (hits.empty())
continue;
611 auto& outHits {hitPerStation[
static_cast<StIndex>(st)]};
612 outHits.reserve(hits.size());
614 std::ranges::for_each(hits, [&outHits, &parentBuckets](
const CandidateHit&
h){
615 outHits.push_back(
h.sp());
616 if (std::ranges::find(parentBuckets,
h->bucket) == parentBuckets.end()) {
617 parentBuckets.push_back(
h->bucket);
624 hitPerStation[
static_cast<StIndex>(
hit.station)].push_back(
hit.spacePoint);
626 GlobalPattern pattern{std::move(hitPerStation), std::move(parentBuckets)};
627 pattern.setTheta(cache.patTheta);
628 pattern.setPhi(cache.patPhi);
630 pattern.setSector(cache.expSect.sector());
632 pattern.setNPrecisionLayers(cache.nPrecisionLayers);
633 pattern.setNTriggerLayers(cache.nTriggerLayers);
634 pattern.setNPhiLayers(cache.nPhiLayers);
635 pattern.setMeanNormResidual2(cache.getMeanResidual2());
639std::vector<GlobalPattern>
641 std::vector<GlobalPattern>
patterns{};
643 std::transform(cache.begin(), cache.end(), std::back_inserter(
patterns),
645 return convertToPattern(cacheEntry);
652 std::span<const SpacePointContainer*> spacepoints)
const {
654 std::vector<HitPayload> hitPayloads{};
656 using enum SectorProjector;
658 size_t totalHits = 0;
661 totalHits += bucket->size();
664 hitPayloads.reserve(totalHits);
669 const Acts::Transform3& localToGlobal {bucket->msSector()->localToGlobalTransform(gctx)};
671 for (
const auto&
hit : *bucket) {
673 if (!
hit->measuresEta() || (!
m_cfg.useMdtHits &&
hit->isStraw())) {
677 hitPayloads.emplace_back(gctx.
context(),
hit.get(), bucket, localToGlobal);
679 if (
m_logger->level() <= Acts::Logging::Level::VERBOSE) {
680 const HitPayload& newHit {hitPayloads.back()};
681 std::ostringstream oss{};
682 oss<<__func__<<
"() Building hit from "<<*
hit<<std::endl<<
"PhiCov: "<<newHit.
phiCov
689 ACTS_VERBOSE(oss.str());
695 SearchTree_t::vector_t treeData{};
696 treeData.reserve(3 * hitPayloads.size());
698 uint8_t msSector = hitPayloads.front()->msSector()->sector();
701 ACTS_VERBOSE(__func__<<
"() Spacepoint: " << *
hit);
704 if (
hit.bucket != currentBucket) {
705 currentBucket =
hit.bucket;
706 msSector =
hit->msSector()->sector();
711 for (
const SectorProjector proj : {leftOverlap, center, rightOverlap}) {
714 if (proj != SectorProjector::center &&
hit->measuresPhi() && expSect != hitExpSector) {
715 ACTS_VERBOSE(
"addHitToTree() Hit with "<<hitExpSector<<
" is not compatible with "<<expSect);
722 const double projR {
hit->measuresPhi()
724 : (pos - pos.dot(planeNormal) * planeNormal).perp()};
726 std::array<double, 2> coords{};
730 ACTS_VERBOSE(
"addHitToTree() Add hit: Z: " << pos.z() <<
", R: " << pos.perp()
731 <<
", ProjR: "<<projR<<
", Phi: "<<
inDeg(pos.phi())
732 <<
", SectorPhi: "<<
inDeg(expSect.
phi())<<
" and coordinates ["
733 <<coords[0]<<
", "<<coords[1]<<
"] to search tree");
734 treeData.emplace_back(std::move(coords), &
hit);
737 ACTS_VERBOSE(__func__<<
"() Create a new tree with "<<treeData.size()
738 <<
" entries and "<<hitPayloads.size()<<
" hits.");
742 const double resA {
a.getMeanResidual2()};
743 const double resB {b.getMeanResidual2()};
744 const double resDiff {
745 std::abs(resA - resB) / std::max(resA, resB)
747 const int nLayerDiff {
a.nBendingLayers() - b.nBendingLayers()};
748 const int nPrecLayDiff {
a.nPrecisionLayers - b.nPrecisionLayers};
753 if ((nLayerDiff == 0 && nPrecLayDiff == 0) ||
754 (std::abs(nLayerDiff) < 3 && resDiff > 0.1)) {
757 if (nLayerDiff == 0) {
758 return nPrecLayDiff > 0;
760 return nLayerDiff > 0;
766 auto getLayerOrdering = [](
const bool isLayer1Lower) {
787 if (std::abs(delta) <= Acts::s_epsilon) {
790 return getLayerOrdering(delta < 0.);
794 if (layer1 == layer2) {
796 if (layer1 == LayerIndex::Middle) {
798 return getLayerOrdering(st1 == StIndex::BM);
800 if (layer1 == LayerIndex::Inner) {
804 throw std::runtime_error(
"Unexpected to have two pattern-compatible hits one in BO and the other in EO.");
806 if (layer1 == LayerIndex::Inner || layer2 == LayerIndex::Inner) {
808 return getLayerOrdering(layer1 == LayerIndex::Inner);
810 if (layer1 == LayerIndex::Outer || layer2 == LayerIndex::Outer) {
812 return getLayerOrdering(layer2 == LayerIndex::Outer);
814 if (layer1 == LayerIndex::BarrelExtended || layer2 == LayerIndex::BarrelExtended) {
816 return getLayerOrdering(layer1 == LayerIndex::BarrelExtended);
819 if (layer1 == LayerIndex::Extended) {
820 return getLayerOrdering(st2 == StIndex::EM);
822 return getLayerOrdering(st1 == StIndex::BM);
826 std::vector<PatHitVisual>* visualInfo)
const {
831 std::vector<const SpacePointBucket*> buckets{cache.getParentBuckets()};
835 if (
auto it =std::ranges::find_if(*visualInfo, [&pattern](
const auto& v){
836 return v.patternCopy && *v.patternCopy == pattern; }); it != visualInfo->end()) {
840 visualInfo->push_back(*cache.visualInfo);
842 std::ranges::copy(buckets, std::back_inserter(visualInfo->back().parentBuckets));
844 visualInfo->back().patternCopy = std::make_unique<GlobalPattern>(std::move(pattern));
845 visualInfo->back().status = status;
Scalar mag() const
mag method
detray::unit< scalar_t > unit
double angle(const GeoTrf::Vector2D &a, const GeoTrf::Vector2D &b)
constexpr float inDeg(const float rad)
Acts::GeometryContext context() const
Header file for AthHistogramAlgorithm.
double phi() const
Returns the phi angle of the expanded sector.
Amg::Vector3D normalDir() const
Returns the vector that is normal to the plane spanned by the expanded sector.
SectorProjector
Enumeration to select the sector projection of the regular MS sector.
std::int8_t sector() const
Returns the expanded sector number.
static LayerOrdering checkLayerOrdering(const HitPayload &hit1, const HitPayload &hit2)
Method to check the logical layer ordering of two hits.
const Acts::Logger & logger() const
Acts::KDTree< 2, const HitPayload *, double, std::array, 50 > SearchTree_t
Definition of the search tree class.
Config m_cfg
Global Pattern Recognition configuration.
static PatternPrintView brief(const PatternState &p)
Print the pattern state with brief information.
PatternStateVec resolveOverlaps(PatternStateVec &toResolve, std::vector< PatHitVisual > *visualInfo=nullptr) const
Method to remove overlapping patterns.
static bool isBetter(const PatternState &a, const PatternState &b)
Method to compare two patterns and define which one is better.
std::unique_ptr< const Acts::Logger > m_logger
Logger for the Global Pattern Finder.
void addVisualInfo(const PatternState &candidate, PatHitVisual::PatternStatus status, std::vector< PatHitVisual > *visualInfo) const
Helper function to add visual information of a given pattern (which is usually going to be destroyed)...
bool passPatternCuts(const PatternState &pat) const
Method to check if a pattern passes the quality cuts.
SearchTreeData constructTree(const ActsTrk::GeometryContext &gctx, std::span< const SpacePointContainer * > spacepoints) const
Construct the search tree from the given spacepoint containers.
GlobalPatternFinder(Config &&config, std::unique_ptr< const Acts::Logger > logger=Acts::getDefaultLogger("GlobalPatternFinder", Acts::Logging::Level::INFO))
Standard constructor.
Muon::MuonStationIndex::StIndex StIndex
Type alias for the station index.
LayerOrdering
Enum to express the logical measurement layer ordering given two hits.
void addPhiOnlyHits(const ActsTrk::GeometryContext &gctx, PatternStateVec &patterns) const
Method to add phi-only measurements to existing PatternStates.
std::vector< PatternState > PatternStateVec
Type alias for a vector of pattern states.
PatternStateVec findPatternsInEta(const Acts::GeometryContext &gctx, const SearchTree_t &orderedSpacepoints, std::vector< PatHitVisual > *visualInfo=nullptr) const
Method steering the global pattern building in the bending plane.
static const int s_nStations
Number of stations.
SeedCoords
Abrivation of the seed coordinates.
@ eSector
Expanded sector coordinate of the associated spectrometer sector
void extendPatterns(const Acts::GeometryContext &gctx, PatternStateVec &startPatterns, PatternStateVec &endPatterns, const CandidateHit &testHit, const Amg::Vector3D &beamSpot, std::vector< PatHitVisual > *visualInfo=nullptr) const
Main function controlling the development of patterns, including pattern branching when necessary.
GlobalPattern convertToPattern(const PatternState &candidate) const
Method to convert a PatternState into a GlobalPattern object.
std::vector< GlobalPattern > findPatterns(const ActsTrk::GeometryContext &gctx, std::span< const SpacePointContainer * > spacepoints) const
Main methods steering the pattern finding.
static PatternPrintView detailed(const PatternState &p)
Print the pattern state with detailed information.
Muon::MuonStationIndex::LayerIndex LayerIndex
Type alias for the station layer index.
Data class to represent an eta maximum in hough space.
std::unordered_map< StIndex, std::vector< HitType > > HitCollection
: The muon space point bucket represents a collection of points that will bre processed together in t...
bool isStraw() const
Returns whether the measurement is a Mdt.
const MuonGMR4::SpectrometerSector * msSector() const
const xAOD::MuonMeasurement * primaryMeasurement() const
std::vector< std::string > patterns
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, 3, 1 > Vector3D
@ eRejectHit
Test failed, discard the hit.
@ eBranchPattern
Test successfull with multiple pattern hits on same layer, branch the pattern.
@ eAddHit
Test successfull, add hit to pattern.
DataVector< SpacePointBucket > SpacePointContainer
Abrivation of the space point container type.
constexpr float inDeg(const float rad)
bool isBarrel(const ChIndex index)
Returns true if the chamber index points to a barrel chamber.
LayerIndex toLayerIndex(ChIndex index)
convert ChIndex into LayerIndex
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)
Small wrapper for candidate hits used to build patterns.
uint8_t globLayer
Global measurement layer number.
const SpacePoint * sp() const
Configuration object for the patter finder.
Base class for hit struct containing hit information.
Amg::Vector3D position
Global position.
bool nonOrthogonalStrips
Are the strips non-orthogonal.
uint8_t locLayer
Layer number in the sector frame.
double phiCov
Cached angular covariance [rad^2] of the hit in the phi angle.
Amg::Vector3D sensorDir(const Acts::GeometryContext &gctx) const
Sensor direction.
StIndex station
Station index.
double stripAngle
Strip angle when the strips are non-orthogonal.
Pattern state object storing pattern information during construction.
Acts::CloneablePtr< PatHitVisual > visualInfo
Pointer to Visual Information for pattern visualization.
Structure to hold the search tree data.
SearchTree_t tree
The search tree.