20 #include "Acts/Seeding/CombinatorialSeedSolver.hpp"
25 using namespace Acts::Experimental::CombinatorialSeedSolver;
33 const auto*
re = prd->readoutElement();
34 switch(prd->channelType()) {
36 return re->stripDesign(prd->measurementHash());
38 return re->wireDesign(prd->measurementHash());
40 return re->padDesign(prd->measurementHash());
46 const auto& design = getDesign(sp);
49 return 0.5* design.stripLength(prd->channelNumber());
57 using namespace SegmentFit;
64 ATH_CHECK(m_writeSegmentKey.initialize());
65 ATH_CHECK(m_writeSegmentSeedKey.initialize());
68 ATH_CHECK(m_visionTool.retrieve(DisableTool{m_visionTool.empty()}));
70 if (!(m_idHelperSvc->hasMM() || m_idHelperSvc->hasSTGC())) {
71 ATH_MSG_ERROR(
"MM or STGC not part of initialized detector layout");
72 return StatusCode::FAILURE;
77 fitCfg.visionTool = m_visionTool.get();
78 fitCfg.idHelperSvc = m_idHelperSvc.get();
80 m_lineFitter = std::make_unique<SegmentFit::SegmentLineFitter>(
name(), std::move(fitCfg));
82 if(m_dumpSeedStatistics){
84 m_seedCounter = std::make_unique<SeedStatistics>();
87 return StatusCode::SUCCESS;
91 NswSegmentFinderAlg::emptyBookKeeper(
const HitLayVec& sortedSp)
const{
93 for (std::size_t
l = 0;
l < sortedSp.size(); ++
l) {
94 emptyKeeper[
l].resize(sortedSp[
l].
size(), 0);
100 NswSegmentFinderAlg::classifyStrip(
const SpacePoint& sp)
const{
103 const auto& design = getDesign(sp);
104 if (!design.hasStereoAngle()) {
107 return design.stereoAngle() > 0. ? StripOrient::U : StripOrient::V;
120 NswSegmentFinderAlg::hitFromIPCorridor(
const SpacePoint& testHit,
125 const Amg::Vector3D estPlaneArrivalUp = SeedingAux::extrapolateToPlane(beamSpotPos, dirEstUp, testHit);
126 const Amg::Vector3D estPlaneArrivalDn = SeedingAux::extrapolateToPlane(beamSpotPos, dirEstDn, testHit);
128 bool below{
true}, above{
true};
129 switch (classifyStrip(testHit)) {
133 const double halfLength = 0.5* stripHalfLength(testHit);
139 below = estPlaneArrivalDn.y() >
std::max(leftEdge.y(), rightEdge.y());
141 above = estPlaneArrivalUp.y() <
std::min(leftEdge.y(), rightEdge.y());
147 below = estPlaneArrivalDn.y() > hY;
149 above = estPlaneArrivalUp.y() < hY;
161 << (below || above ?
" is outside the window" :
" is inside the window"));
163 return HitWindow::tooLow;
166 return HitWindow::tooHigh;
172 #define TEST_HIT_CORRIDOR(LAYER, HIT_ITER, START_LAYER) \
174 const SpacePoint* testMe = combinatoricLayers[LAYER].get()[HIT_ITER]; \
175 if (usedHits[LAYER].get()[HIT_ITER] > m_maxUsed) { \
176 ATH_MSG_VERBOSE(__func__<<":"<<__LINE__<<" - " \
177 <<m_idHelperSvc->toString(testMe->identify()) \
178 <<" already used in good seed." ); \
181 const HitWindow inWindow = hitFromIPCorridor(*testMe, beamSpot, dirEstUp, dirEstDn); \
182 if(inWindow == HitWindow::tooHigh) { \
183 ATH_MSG_VERBOSE(__func__<<":"<<__LINE__<<" - Hit " \
184 <<m_idHelperSvc->toString(testMe->identify()) \
185 <<" is beyond the corridor. Break loop"); \
187 } else if (inWindow == HitWindow::tooLow) { \
188 START_LAYER = HIT_ITER + 1; \
189 ATH_MSG_VERBOSE(__func__<<":"<<__LINE__<<" - Hit " \
190 <<m_idHelperSvc->toString(testMe->identify()) \
191 <<" is still below the corridor. Update start to " \
202 seedHitsFromLayers.clear();
203 std::size_t maxSize{1};
204 for (
const HitVec& hitVec : combinatoricLayers) {
205 maxSize = maxSize * hitVec.size();
207 seedHitsFromLayers.reserve(maxSize);
210 unsigned int iterLay0{0}, iterLay1{0}, iterLay2{0}, iterLay3{0};
211 unsigned int startLay1{0}, startLay2{0}, startLay3{0};
213 for( ; iterLay0 < combinatoricLayers[0].get().
size() ; ++iterLay0){
215 if (usedHits[0].
get()[iterLay0] > m_maxUsed) {
218 const SpacePoint* hit0 = combinatoricLayers[0].get()[iterLay0];
229 for( iterLay1 = startLay1; iterLay1 < combinatoricLayers[1].get().
size() ; ++iterLay1){
231 for( iterLay2 = startLay2; iterLay2 < combinatoricLayers[2].get().
size() ; ++iterLay2){
233 for( iterLay3 = startLay3; iterLay3 < combinatoricLayers[3].get().
size(); ++iterLay3){
235 seedHitsFromLayers.emplace_back(
std::array{hit0, combinatoricLayers[1].get()[iterLay1],
236 combinatoricLayers[2].
get()[iterLay2],
237 combinatoricLayers[3].
get()[iterLay3]});
243 #undef TEST_HIT_CORRIDOR
255 for (std::size_t
i = 0;
i < extensionLayers.size(); ++
i) {
257 const Amg::Vector3D extrapPos = SeedingAux::extrapolateToPlane(startPos, direction, *
layer.front());
259 unsigned int indexOfHit =
layer.size() + 1;
260 unsigned int triedHit{0};
264 for (
unsigned int j = 0; j <
layer.size(); ++j) {
265 if (usedHits[
i].
get().at(j) > m_maxUsed) {
268 auto hit =
layer.at(j);
269 const double pull = std::sqrt(SeedingAux::chi2Term(extrapPos, direction, *hit));
270 ATH_MSG_VERBOSE(
"Trying extension with hit " << m_idHelperSvc->toString(hit->identify()));
273 if (
pull > minPull) {
287 if (minPull < m_minPullThreshold) {
288 const auto* bestCand =
layer.at(indexOfHit);
289 ATH_MSG_VERBOSE(
"Extension successfull - hit" << m_idHelperSvc->toString(bestCand->identify())
291 <<
", dir: "<<
Amg::toString(bestCand->sensorDirection())<<
" found with pull "<<minPull);
292 combinatoricHits.push_back(bestCand);
295 return combinatoricHits;
298 std::unique_ptr<SegmentSeed>
307 bool allValid = std::all_of(initialSeed.begin(), initialSeed.end(), [
this](
const auto& hit){
309 if (hit->type() == xAOD::UncalibMeasType::MMClusterType) {
310 const auto* mmClust = static_cast<const xAOD::MMCluster*>(hit->primaryMeasurement());
311 return mmClust->stripNumbers().size() >= m_minClusSize;
318 ATH_MSG_VERBOSE(
"Seed rejection: Not all clusters meet minimum strip size");
323 std::array<double, 4>
params = defineParameters(bMatrix, initialSeed);
325 const auto [segPos, direction] = seedSolution(initialSeed,
params);
329 for (std::size_t
i = 0;
i < 4; ++
i) {
330 const double halfLength = stripHalfLength(*initialSeed[
i]);
332 if (std::abs(
params[
i]) > halfLength) {
333 ATH_MSG_VERBOSE(
"Seed Rejection: Invalid seed - outside of the strip's length");
340 double interceptX = segPos.x();
341 double interceptY = segPos.y();
345 auto extendedHits = extendHits(segPos, direction, extensionLayers, usedHits);
346 HitVec hits{initialSeed.begin(),initialSeed.end()};
347 hits.insert(
hits.end(), extendedHits.begin(), extendedHits.end());
350 return std::make_unique<SegmentSeed>(tanBeta, interceptY, tanAlpha,
351 interceptX,
hits.size(),
352 std::move(
hits),
max.parentBucket());
356 std::unique_ptr<Segment> NswSegmentFinderAlg::fitSegmentSeed(
const EventContext& ctx,
368 auto segment = m_lineFitter->fitSegment(ctx, patternSeed, patternSeed->
parameters(),
369 locToGlob, std::move(calibratedHits));
375 std::pair<std::vector<std::unique_ptr<SegmentSeed>>, std::vector<std::unique_ptr<Segment>>>
380 const HitLayVec& stripHitsLayers{hitLayers.stripHits()};
381 const std::size_t layerSize = stripHitsLayers.size();
384 std::vector<std::unique_ptr<SegmentSeed>> seeds{};
385 std::vector<std::unique_ptr<Segment>> segments{};
388 unsigned int nSeeds{0}, nExtSeeds{0}, nSegments{0};
393 return std::make_pair(std::move(seeds),std::move(segments));
397 if (m_visionTool.isEnabled()) {
400 constexpr
double legX{0.2};
412 const double pull = std::sqrt(SeedingAux::chi2Term(hitPos, hitDir, *sp));
413 const double pull2 = (mmClust->localPosition<1>().
x() - simHit->
localPosition().x()) / std::sqrt(mmClust->localCovariance<1>().x());
418 m_visionTool->visualizeBucket(ctx, *
max.parentBucket(),
419 "truth", std::move(primitives));
426 std::array<const SpacePoint*, 4> seedHits{};
430 for (std::size_t
i = 0;
i < layerSize - 3; ++
i) {
431 seedHits[0] = stripHitsLayers[
i].front();
432 for (std::size_t j =
i + 1; j < layerSize - 2; ++j) {
433 seedHits[1] = stripHitsLayers[j].front();
434 for (std::size_t
k = j + 1;
k < layerSize - 1; ++
k) {
435 seedHits[2] = stripHitsLayers[
k].front();
436 for (std::size_t
l =
k + 1;
l < layerSize; ++
l) {
437 seedHits[3] = stripHitsLayers[
l].front();
439 const HitLaySpan_t layers{stripHitsLayers[
i], stripHitsLayers[j], stripHitsLayers[
k], stripHitsLayers[
l]};
443 [
this](
const auto&
layer) {
444 return layer.get().size() > m_maxClustersInLayer;
450 if (std::abs(bMatrix.determinant()) < 1.e-6) {
459 UsedHitSpan_t usedHits{allUsedHits[
i], allUsedHits[j], allUsedHits[
k], allUsedHits[
l]};
461 constructPrelimnarySeeds(globToLocal.translation(),
layers, usedHits, preLimSeeds);
466 usedExtensionHits.reserve(stripHitsLayers.size());
467 extensionLayers.reserve(stripHitsLayers.size());
468 for (std::size_t
e = 0 ;
e < stripHitsLayers.size(); ++
e) {
469 if (!(
e ==
i ||
e == j ||
e ==
k ||
e ==
l)){
470 extensionLayers.emplace_back(stripHitsLayers[
e]);
471 usedExtensionHits.emplace_back(allUsedHits[
e]);
476 for (
auto &combinatoricHits : preLimSeeds) {
477 auto seed = buildSegmentSeed(combinatoricHits, bMatrix,
max, extensionLayers, usedExtensionHits);
481 if(seed->getHitsInMax().size() < m_minSeedHits){
487 std::unique_ptr<Segment> segment = fitSegmentSeed(ctx, gctx, seed.get());
488 seeds.push_back(std::move(seed));
493 if(m_markHitsFromSeed){
495 markHitsAsUsed(seeds.back()->getHitsInMax(), stripHitsLayers, allUsedHits, 1,
false);
503 segMeasSP.reserve(segment->measurements().size());
505 segment->measurements().end(),
506 std::back_inserter(segMeasSP),
507 [](
const auto&
m) { return m->spacePoint(); });
509 markHitsAsUsed(segMeasSP, stripHitsLayers, allUsedHits, 10,
true);
510 segments.push_back(std::move(segment));
519 if(m_dumpSeedStatistics){
520 m_seedCounter->addToStat(
max.msSector(), nSeeds, nExtSeeds, nSegments);
523 return std::make_pair(std::move(seeds),std::move(segments));
531 bool markNeighborHits)
const {
546 for (std::size_t lIdx = 0; !
found && lIdx < allSortHits.size(); ++lIdx) {
547 const HitVec& hVec{allSortHits[lIdx]};
549 unsigned int hitLayer = layerSorter.sectorLayerNum(*hVec.front());
550 if(hitLayer != measLayer){
551 ATH_MSG_VERBOSE(
"Not in the same layer since measLayer = "<< measLayer <<
" and "<<hitLayer);
555 for (std::size_t hIdx = 0 ; hIdx < hVec.size(); ++hIdx) {
558 auto testHit = hVec[hIdx];
561 usedHitMarker[lIdx][hIdx] += incr;
563 if(!markNeighborHits){
569 double deltaX = std::abs(testHit->primaryMeasurement()->localPosition<1>().x() - spPosX);
570 if(
deltaX < m_maxdYWindow){
571 usedHitMarker[lIdx][hIdx] += incr;
591 ATH_CHECK(writeSegments.record(std::make_unique<SegmentContainer>()));
594 ATH_CHECK(writeSegmentSeeds.record(std::make_unique<SegmentSeedContainer>()));
600 auto [seeds, segments] = findSegmentsFromMaximum(*
max, *gctx, ctx);
603 for(
const auto& hitMax :
max->getHitsInMax()){
604 ATH_MSG_VERBOSE(
"Hit "<<m_idHelperSvc->toString(hitMax->identify())<<
", "
610 for(
auto& seed: seeds){
613 std::stringstream sstr{};
614 sstr<<
"Seed tanBeta = "<<seed->tanBeta()<<
", y0 = "<<seed->interceptY()
615 <<
", tanAlpha = "<<seed->tanAlpha()<<
", x0 = "<<seed->interceptX()<<
", hits in the seed "
616 <<seed->getHitsInMax().size()<<std::endl;
618 for(
const auto& hit : seed->getHitsInMax()){
619 sstr<<
" *** Hit "<<m_idHelperSvc->toString(hit->identify())<<
", "
624 if (m_visionTool.isEnabled()) {
625 m_visionTool->visualizeSeed(ctx, *seed,
"#phi-combinatorialSeed");
628 writeSegmentSeeds->push_back(std::move(seed));
632 for (
auto &seg : segments) {
638 if (m_visionTool.isEnabled()) {
639 m_visionTool->visualizeSegment(ctx, *seg,
"#phi-segment");
642 writeSegments->push_back(std::move(seg));
647 return StatusCode::SUCCESS;
652 if(m_dumpSeedStatistics){
653 m_seedCounter->printTableSeedStats(msgStream());
655 return StatusCode::SUCCESS;
658 void NswSegmentFinderAlg::SeedStatistics::addToStat(
const MuonGMR4::SpectrometerSector* msSector,
unsigned int seeds,
unsigned int extSeeds,
unsigned int segments){
659 std::unique_lock guard{m_mutex};
663 key.eta = msSector->
chambers().front()->stationEta();
667 entry.nSeeds += seeds;
668 entry.nExtSeeds += extSeeds;
669 entry.nSegments += segments;
672 void NswSegmentFinderAlg::SeedStatistics::printTableSeedStats(MsgStream&
msg)
const{
682 for (
const auto&
entry : m_seedStat) {
683 const auto& sector =
entry.first;
687 msg<<
MSG::ALWAYS <<
"| " << std::setw(3) << (sector.chIdx == ChIndex::EIL ?
"EIL" :
"EIS")
688 <<
" | " << std::setw(2) << sector.phi
689 <<
" | " << std::setw(3) << sector.eta
690 <<
" | " << std::setw(4) << (sector.side > 0 ?
"A" :
"C")
691 <<
" | " << std::setw(7) <<
stats.nSeeds
692 <<
" | " << std::setw(8) <<
stats.nExtSeeds
693 <<
" | " << std::setw(8) <<
stats.nSegments