ATLAS Offline Software
Loading...
Searching...
No Matches
NswSegmentFinderAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
11
12
14
17
19
20#include "Acts/Seeding/CombinatorialSeedSolver.hpp"
21
22#include <ranges>
23#include <format>
24
25using namespace Acts::Experimental::CombinatorialSeedSolver;
26namespace {
27 inline const MuonGMR4::StripDesign& getDesign(const MuonR4::SpacePoint& sp) {
29 const auto* prd = static_cast<const xAOD::MMCluster*>(sp.primaryMeasurement());
30 return prd->readoutElement()->stripLayer(prd->measurementHash()).design();
31 } else if (sp.type() == xAOD::UncalibMeasType::sTgcStripType) {
32 const auto* prd = static_cast<const xAOD::sTgcMeasurement*>(sp.primaryMeasurement());
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());
41 }
42 }
43 THROW_EXCEPTION("Invalid space point for design retrieval "<<sp.msSector()->idHelperSvc()->toString(sp.identify()));
44 }
45 inline double stripHalfLength(const MuonR4::SpacePoint& sp) {
46 const auto& design = getDesign(sp);
48 const auto* prd = static_cast<const xAOD::MMCluster*>(sp.primaryMeasurement());
49 return 0.5* design.stripLength(prd->channelNumber());
50 }
51 return 0.;
52 }
53 inline std::string sTgcChannelType(const int chType) {
54 return chType == sTgcIdHelper::Strip ? "S" :
55 chType == sTgcIdHelper::Wire ? "W" : "P";
56 }
57}
58
59namespace MuonR4 {
60
61using namespace SegmentFit;
62constexpr unsigned minLayers{4};
64
66 ATH_CHECK(m_geoCtxKey.initialize());
67 ATH_CHECK(m_etaKey.initialize());
68 ATH_CHECK(m_writeSegmentKey.initialize());
69 ATH_CHECK(m_writeSegmentSeedKey.initialize());
70 ATH_CHECK(m_idHelperSvc.retrieve());
71 ATH_CHECK(m_calibTool.retrieve());
72 ATH_CHECK(m_visionTool.retrieve(DisableTool{m_visionTool.empty()}));
73 ATH_CHECK(detStore()->retrieve(m_detMgr));
74
75 if (!(m_idHelperSvc->hasMM() || m_idHelperSvc->hasSTGC())) {
76 ATH_MSG_ERROR("MM or STGC not part of initialized detector layout");
77 return StatusCode::FAILURE;
78 }
79
81 fitCfg.calibrator = m_calibTool.get();
82 fitCfg.visionTool = m_visionTool.get();
83 fitCfg.idHelperSvc = m_idHelperSvc.get();
84 fitCfg.parsToUse = {ParamDefs::x0, ParamDefs::y0, ParamDefs::theta, ParamDefs::phi};
85
86 m_lineFitter = std::make_unique<SegmentFit::SegmentLineFitter>(name(), std::move(fitCfg));
87
89 m_seedCounter = std::make_unique<SeedStatistics>();
90 }
91
92 return StatusCode::SUCCESS;
93}
94
97 UsedHitMarker_t emptyKeeper(sortedSp.size());
98 for (std::size_t l = 0; l < sortedSp.size(); ++l) {
99 emptyKeeper[l].resize(sortedSp[l].size(), 0);
100 }
101 return emptyKeeper;
102}
103
106
108 const auto& design = getDesign(sp);
109 if (!design.hasStereoAngle()) {
110 return StripOrient::X;
111 }
112 return design.stereoAngle() > 0. ? StripOrient::U : StripOrient::V;
113 } else if (sp.type() == xAOD::UncalibMeasType::sTgcStripType) {
114 if (sp.dimension() == 2) {
115 return StripOrient::C;
116 }
117 const auto* prd = static_cast<const xAOD::sTgcMeasurement*>(sp.primaryMeasurement());
118 return prd->channelType() == sTgcIdHelper::Strip ? StripOrient::X : StripOrient::P;
119
120 }
121 ATH_MSG_WARNING("Cannot classify orientation of "<<m_idHelperSvc->toString(sp.identify()));
123}
126 const Amg::Vector3D& beamSpotPos,
127 const Amg::Vector3D& dirEstUp,
128 const Amg::Vector3D& dirEstDn) const{
129
130 const Amg::Vector3D estPlaneArrivalUp = SeedingAux::extrapolateToPlane(beamSpotPos, dirEstUp, testHit);
131 const Amg::Vector3D estPlaneArrivalDn = SeedingAux::extrapolateToPlane(beamSpotPos, dirEstDn, testHit);
132
133 bool below{true}, above{true};
134 switch (classifyStrip(testHit)) {
135 using enum StripOrient;
136 case U:
137 case V:{
138 const double halfLength = 0.5* stripHalfLength(testHit);
140 const Amg::Vector3D leftEdge = testHit.localPosition() - halfLength * testHit.sensorDirection();
141 const Amg::Vector3D rightEdge = testHit.localPosition() + halfLength * testHit.sensorDirection();
142
144 below = estPlaneArrivalDn.y() > std::max(leftEdge.y(), rightEdge.y());
146 above = estPlaneArrivalUp.y() < std::min(leftEdge.y(), rightEdge.y());
147 break;
148 } case X:
149 case C: {
151 const double hY = testHit.localPosition().y();
152 below = estPlaneArrivalDn.y() > hY;
154 above = estPlaneArrivalUp.y() < hY;
155 break;
156 }
157 case P:{
158 break;
159 }
160 case Unknown:{
161 break;
162 }
163
164 }
165 ATH_MSG_VERBOSE("Hit " << m_idHelperSvc->toString(testHit.identify())
166 << (below || above ? " is outside the window" : " is inside the window"));
167 if(below) {
168 return HitWindow::tooLow;
169 }
170 if(above) {
171 return HitWindow::tooHigh;
172 }
173 return HitWindow::inside;
174};
175
177#define TEST_HIT_CORRIDOR(LAYER, HIT_ITER, START_LAYER) \
178{ \
179 const SpacePoint* testMe = combinatoricLayers[LAYER].get()[HIT_ITER]; \
180 if (usedHits[LAYER].get()[HIT_ITER] > m_maxUsed) { \
181 ATH_MSG_VERBOSE(__func__<<":"<<__LINE__<<" - " \
182 <<m_idHelperSvc->toString(testMe->identify()) \
183 <<" already used in good seed." ); \
184 continue; \
185 } \
186 const HitWindow inWindow = hitFromIPCorridor(*testMe, beamSpot, dirEstUp, dirEstDn); \
187 if(inWindow == HitWindow::tooHigh) { \
188 ATH_MSG_VERBOSE(__func__<<":"<<__LINE__<<" - Hit " \
189 <<m_idHelperSvc->toString(testMe->identify()) \
190 <<" is beyond the corridor. Break loop"); \
191 break; \
192 } else if (inWindow == HitWindow::tooLow) { \
193 START_LAYER = HIT_ITER + 1; \
194 ATH_MSG_VERBOSE(__func__<<":"<<__LINE__<<" - Hit " \
195 <<m_idHelperSvc->toString(testMe->identify()) \
196 <<" is still below the corridor. Update start to " \
197 <<START_LAYER); \
198 continue; \
199 } \
200}
201
203 const HitLaySpan_t& combinatoricLayers,
204 const UsedHitSpan_t& usedHits,
205 InitialSeedVec_t& seedHitsFromLayers) const {
207 seedHitsFromLayers.clear();
208 std::size_t maxSize{1};
209 for (const HitVec& hitVec : combinatoricLayers) {
210 maxSize = maxSize * hitVec.size();
211 }
212 seedHitsFromLayers.reserve(maxSize);
213
214
215 unsigned iterLay0{0}, iterLay1{0}, iterLay2{0}, iterLay3{0};
216 unsigned startLay1{0}, startLay2{0}, startLay3{0};
217
218 for( ; iterLay0 < combinatoricLayers[0].get().size() ; ++iterLay0){
220 if (usedHits[0].get()[iterLay0] > m_maxUsed) {
221 continue;
222 }
223 const SpacePoint* hit0 = combinatoricLayers[0].get()[iterLay0];
225 const Amg::Vector3D initSeedDir{(beamSpot - hit0->localPosition()).unit()};
226 const Amg::Vector3D dirEstUp = Amg::dirFromAngles(initSeedDir.phi(), initSeedDir.theta() - m_windowTheta);
227 const Amg::Vector3D dirEstDn = Amg::dirFromAngles(initSeedDir.phi(), initSeedDir.theta() + m_windowTheta);
228
229 ATH_MSG_VERBOSE("Reference hit: "<<m_idHelperSvc->toString(hit0->identify())
230 <<", position: "<<Amg::toString(hit0->localPosition())
231 <<", seed dir: "<<Amg::toString(initSeedDir)
232 <<", seed plane: "<<Amg::toString(SeedingAux::extrapolateToPlane(beamSpot, initSeedDir, *hit0)));
234 for( iterLay1 = startLay1; iterLay1 < combinatoricLayers[1].get().size() ; ++iterLay1){
235 TEST_HIT_CORRIDOR(1, iterLay1, startLay1);
236 for( iterLay2 = startLay2; iterLay2 < combinatoricLayers[2].get().size() ; ++iterLay2){
237 TEST_HIT_CORRIDOR(2, iterLay2, startLay2);
238 for( iterLay3 = startLay3; iterLay3 < combinatoricLayers[3].get().size(); ++iterLay3){
239 TEST_HIT_CORRIDOR(3, iterLay3, startLay3);
240 seedHitsFromLayers.emplace_back(std::array{hit0, combinatoricLayers[1].get()[iterLay1],
241 combinatoricLayers[2].get()[iterLay2],
242 combinatoricLayers[3].get()[iterLay3]});
243 }
244 }
245 }
246 }
247}
248#undef TEST_HIT_CORRIDOR
249
252 const Amg::Vector3D& direction,
253 const HitLaySpan_t& extensionLayers,
254 const UsedHitSpan_t& usedHits) const {
255
256 //the hits we need to return to extend the segment seed
257 HitVec combinatoricHits;
258
259 //the stripHitsLayers are already the unused ones - only use for the extension
260 for (std::size_t i = 0; i < extensionLayers.size(); ++i) {
261 const HitVec& layer{extensionLayers[i].get()};
262 const Amg::Vector3D extrapPos = SeedingAux::extrapolateToPlane(startPos, direction, *layer.front());
263
264 unsigned indexOfHit = layer.size() + 1;
265 unsigned triedHit{0};
266 double minPull{std::numeric_limits<double>::max()};
267
268 // loop over the hits on the same layer
269 for (unsigned j = 0; j < layer.size(); ++j) {
270 if (usedHits[i].get().at(j) > m_maxUsed) {
271 continue;
272 }
273 auto hit = layer.at(j);
274 const double pull = std::sqrt(SeedingAux::chi2Term(extrapPos, direction, *hit));
275 ATH_MSG_VERBOSE("Trying extension with hit " << m_idHelperSvc->toString(hit->identify()));
276
277 //find the hit with the minimum pull (check at least one hit after we have increasing pulls)
278 if (pull > minPull) {
279 triedHit+=1;
280 continue;
281 }
282
283 if(triedHit>1){
284 break;
285 }
286
287 indexOfHit = j;
288 minPull = pull;
289 }
290
291 // complete the seed with the extended hits
292 if (minPull < m_minPullThreshold) {
293 const auto* bestCand = layer.at(indexOfHit);
294 ATH_MSG_VERBOSE("Extension successfull - hit" << m_idHelperSvc->toString(bestCand->identify())
295 <<", pos: "<<Amg::toString(bestCand->localPosition())
296 <<", dir: "<<Amg::toString(bestCand->sensorDirection())<<" found with pull "<<minPull);
297 combinatoricHits.push_back(bestCand);
298 }
299 }
300 return combinatoricHits;
301}
302
303std::unique_ptr<SegmentSeed>
305 const AmgSymMatrix(2)& bMatrix,
306 const HoughMaximum& max,
307 const HitLaySpan_t& extensionLayers,
308 const UsedHitSpan_t& usedHits) const {
309
310
311 //we reject seeds with all clusters' sizes less than min value
312 bool allValid = std::any_of(initialSeed.begin(), initialSeed.end(),
313 [this](const auto& hit){
314 if (hit->type() == xAOD::UncalibMeasType::MMClusterType) {
315 const auto* mmClust = static_cast<const xAOD::MMCluster*>(hit->primaryMeasurement());
316 return mmClust->stripNumbers().size() >= m_minClusSize;
317 }
318 return false;
319 });
320
321 if (!allValid) {
322 ATH_MSG_VERBOSE("Seed rejection: Not all clusters meet minimum strip size");
323 return nullptr;
324 }
325
326
327 std::array<double, 4> params = defineParameters(bMatrix, initialSeed);
328
329 const auto [segPos, direction] = seedSolution(initialSeed, params);
330
331 // check the consistency of the parameters - expected to lay in the strip's
332 // length
333 for (std::size_t i = 0; i < 4; ++i) {
334 const double halfLength = stripHalfLength(*initialSeed[i]);
335
336 if (std::abs(params[i]) > halfLength) {
337 ATH_MSG_VERBOSE("Seed Rejection: Invalid seed - outside of the strip's length");
338 return nullptr;
339 }
340 }
341 double tanAlpha = houghTanAlpha(direction);
342 double tanBeta = houghTanBeta(direction);
343
344 double interceptX = segPos.x();
345 double interceptY = segPos.y();
346
347
348 // extend the seed to the segment -- include hits from the other layers too
349 auto extendedHits = extendHits(segPos, direction, extensionLayers, usedHits);
350 HitVec hits{initialSeed.begin(),initialSeed.end()};
351 hits.insert(hits.end(), extendedHits.begin(), extendedHits.end());
352
353
354 return std::make_unique<SegmentSeed>(tanBeta, interceptY, tanAlpha,
355 interceptX, hits.size(),
356 std::move(hits), max.parentBucket());
357}
358
359
360std::unique_ptr<Segment> NswSegmentFinderAlg::fitSegmentSeed(const EventContext& ctx,
361 const ActsTrk::GeometryContext& gctx,
362 const SegmentSeed* patternSeed) const{
363
364 ATH_MSG_VERBOSE("Fit the SegmentSeed");
365
366 //Calibration of the seed spacepoints
367 CalibSpacePointVec calibratedHits = m_calibTool->calibrate(ctx, patternSeed->getHitsInMax(),
368 patternSeed->localPosition(),
369 patternSeed->localDirection(), 0.);
370
371 const Amg::Transform3D& locToGlob{patternSeed->msSector()->localToGlobalTrans(gctx)};
372
373 return m_lineFitter->fitSegment(ctx, patternSeed, patternSeed->parameters(),
374 locToGlob, std::move(calibratedHits));
375}
376
377std::pair<std::vector<std::unique_ptr<SegmentSeed>>, std::vector<std::unique_ptr<Segment>>>
379 const ActsTrk::GeometryContext &gctx,
380 const EventContext& ctx) const {
381 // first sort the hits per layer from the maximum
382 SpacePointPerLayerSplitter hitLayers{max.getHitsInMax()};
383
384 const HitLayVec& stripHitsLayers{hitLayers.stripHits()};
385 const std::size_t layerSize = stripHitsLayers.size();
386
387 //seeds and segments containers
388 std::vector<std::unique_ptr<SegmentSeed>> seeds{};
389 std::vector<std::unique_ptr<Segment>> segments{};
390
391 //counters for the number of seeds, extented seeds and segments
392 unsigned nSeeds{0}, nExtSeeds{0}, nSegments{0};
393
394
395 if (layerSize < minLayers) {
396 ATH_MSG_VERBOSE("Not enough layers to build a seed");
397 return std::make_pair(std::move(seeds),std::move(segments));
398 }
399
400
401 if (m_visionTool.isEnabled()) {
403 constexpr double legX{0.2};
404 double legY{0.8};
405 for (const SpacePoint* sp : max.getHitsInMax()) {
406 const xAOD::MuonSimHit* simHit = getTruthMatchedHit(*sp->primaryMeasurement());
407 if (!simHit) {
408 continue;
409 }
410
411 const MuonGMR4::MuonReadoutElement* reEle = m_detMgr->getReadoutElement(simHit->identify());
412 const Amg::Transform3D toChamb = reEle->msSector()->globalToLocalTrans(gctx) *
413 reEle->localToGlobalTrans(gctx, sp->identify());
414
415 const Amg::Vector3D hitPos = toChamb * xAOD::toEigen(simHit->localPosition());
416 const Amg::Vector3D hitDir = toChamb.linear() * xAOD::toEigen(simHit->localDirection());
417 const double pull = std::sqrt(SeedingAux::chi2Term(hitPos, hitDir, *sp));
418
420 const auto* mmClust = static_cast<const xAOD::MMCluster*>(sp->primaryMeasurement());
421 const MuonGMR4::MmReadoutElement* mmEle = mmClust->readoutElement();
422 const auto& design = mmEle->stripLayer(mmClust->measurementHash()).design();
423 std::string stereoDesign{!design.hasStereoAngle() ? "X" : design.stereoAngle() >0 ? "U": "V"};
424 primitives.push_back(MuonValR4::drawLabel(std::format("ml: {:1d}, gap: {:1d}, {:}, pull: {:.2f}",
425 mmEle->multilayer(), mmClust->gasGap(),
426 stereoDesign, pull), legX, legY, 14));
427 } else if(sp->type() == xAOD::UncalibMeasType::sTgcStripType) {
428 const auto* sTgcMeas = static_cast<const xAOD::sTgcMeasurement*>(sp->primaryMeasurement());
429 std::string channelString = sp->secondaryMeasurement() == nullptr ?
430 sTgcChannelType(sTgcMeas->channelType()) :
431 std::format("{:}/{:}", sTgcChannelType(sTgcMeas->channelType()),
432 sTgcChannelType(static_cast<const xAOD::sTgcMeasurement*>(sp->secondaryMeasurement())->channelType()));
433 primitives.push_back(MuonValR4::drawLabel(std::format("ml: {:1d}, gap: {:1d}, type: {:}, pull: {:.2f}",
434 sTgcMeas->readoutElement()->multilayer(), sTgcMeas->gasGap(),
435 channelString, pull), legX, legY, 14));
436 }
437 legY-=0.05;
438 }
439 m_visionTool->visualizeBucket(ctx, *max.parentBucket(),
440 "truth", std::move(primitives));
441 }
442
443 UsedHitMarker_t allUsedHits = emptyBookKeeper(stripHitsLayers);
444
445 const Amg::Transform3D globToLocal = max.msSector()->globalToLocalTrans(gctx);
446 std::array<const SpacePoint*, 4> seedHits{};
447
448 InitialSeedVec_t preLimSeeds{};
449
450 for (std::size_t i = 0; i < layerSize - 3; ++i) {
451 seedHits[0] = stripHitsLayers[i].front();
452 for (std::size_t j = i + 1; j < layerSize - 2; ++j) {
453 seedHits[1] = stripHitsLayers[j].front();
454 for (std::size_t k = j + 1; k < layerSize - 1; ++k) {
455 seedHits[2] = stripHitsLayers[k].front();
456 for (std::size_t l = k + 1; l < layerSize; ++l) {
457 seedHits[3] = stripHitsLayers[l].front();
458
459 const HitLaySpan_t layers{stripHitsLayers[i], stripHitsLayers[j], stripHitsLayers[k], stripHitsLayers[l]};
460
461 //skip combination with at least one too busy layer
462 if (std::ranges::any_of(layers,
463 [this](const auto& layer) {
464 return layer.get().size() > m_maxClustersInLayer;
465 })) {
466 continue; // skip this combination
467 }
468
469 AmgSymMatrix(2) bMatrix = betaMatrix(seedHits);
470 if (std::abs(bMatrix.determinant()) < 1.e-6) {
471 continue;
472 }
473 ATH_MSG_DEBUG("Space point positions for seed layers: \n"
474 <<(*seedHits[0]) << ",\n"
475 <<(*seedHits[1]) << ",\n"
476 <<(*seedHits[2]) << ",\n"
477 <<(*seedHits[3]));
478
479 UsedHitSpan_t usedHits{allUsedHits[i], allUsedHits[j], allUsedHits[k], allUsedHits[l]};
480 // each layer may have more than one hit - take the hit combinations
481 constructPrelimnarySeeds(globToLocal.translation(), layers, usedHits, preLimSeeds);
482
483 //the layers not participated in the seed build - gonna be used for the extension
484 HitLaySpan_t extensionLayers{};
485 UsedHitSpan_t usedExtensionHits{};
486 usedExtensionHits.reserve(stripHitsLayers.size());
487 extensionLayers.reserve(stripHitsLayers.size());
488 for (std::size_t e = 0 ; e < stripHitsLayers.size(); ++e) {
489 if (!(e == i || e == j || e == k || e == l)){
490 extensionLayers.emplace_back(stripHitsLayers[e]);
491 usedExtensionHits.emplace_back(allUsedHits[e]);
492 }
493 }
494 // we have made sure to have hits from all the four layers -
495 // start by 4 hits for the seed and try to build the seed for the combinatorics found
496 for (auto &combinatoricHits : preLimSeeds) {
497 auto seed = buildSegmentSeed(combinatoricHits, bMatrix, max, extensionLayers, usedExtensionHits);
498 if (!seed) {
499 continue;
500 }
501 //if the seed build is successful, try to build the segment
502 ++nSeeds;
503 if(seed->getHitsInMax().size() < m_minSeedHits){
504 ATH_MSG_VERBOSE("Not succesfully extended seed");
505 continue;
506
507 }
508 ++nExtSeeds;
509 std::unique_ptr<Segment> segment = fitSegmentSeed(ctx, gctx, seed.get());
510 seeds.push_back(std::move(seed));
511
512
513 if (!segment) {
514 ATH_MSG_VERBOSE("Seed Rejection: Segment fit failed");
516 //mark hits from extended seed if no succesfully led to segment
517 markHitsAsUsed(seeds.back()->getHitsInMax(), stripHitsLayers, allUsedHits, 1, false);
518 }
519 continue;
520 }
521
522 ++nSegments;
523 // Flag hits as used and in the window around segment
524 HitVec segMeasSP;
525 segMeasSP.reserve(segment->measurements().size());
526 std::ranges::transform(segment->measurements(),
527 std::back_inserter(segMeasSP),
528 [](const auto& m) { return m->spacePoint(); });
529 //mark hits from segment
530 markHitsAsUsed(segMeasSP, stripHitsLayers, allUsedHits, 10, true);
531 segments.push_back(std::move(segment));
532 }
533 }
534 }
535 }
536 }
537
539 m_seedCounter->addToStat(max.msSector(), nSeeds, nExtSeeds, nSegments);
540 }
541
542 return std::make_pair(std::move(seeds),std::move(segments));
543}
544
545
547 const HitLayVec& allSortHits,
548 UsedHitMarker_t& usedHitMarker,
549 unsigned incr,
550 bool markNeighborHits) const {
551
552 SpacePointPerLayerSorter layerSorter{};
553
554 for(const auto& sp : spacePoints){
555 // Proection against the auxiliary measurement
556 if(!sp){
557 continue;
558 }
559
560 unsigned measLayer = layerSorter.sectorLayerNum(*sp);
561
562 Amg::Vector2D spPosX{Amg::Vector2D::Zero()};
564 switch (sp->primaryMeasurement()->numDimensions()) {
565 case 1:
566 spPosX[Amg::x] = sp->primaryMeasurement()->localPosition<1>().x();
567 break;
568 case 2:
569 spPosX = xAOD::toEigen(sp->primaryMeasurement()->localPosition<2>());
570 break;
571 default:
572 THROW_EXCEPTION("Unsupported dimension");
573 }
574
575 for (std::size_t lIdx = 0; lIdx < allSortHits.size(); ++lIdx) {
576 const HitVec& hVec{allSortHits[lIdx]};
577 //check if they are not in the same layer
578 unsigned hitLayer = layerSorter.sectorLayerNum(*hVec.front());
579 if(hitLayer != measLayer) {
580 ATH_MSG_VERBOSE("Not in the same layer since measLayer = "<< measLayer << " and "<<hitLayer);
581 continue;
582 }
583 for (std::size_t hIdx = 0 ; hIdx < hVec.size(); ++hIdx) {
584 //check the dY between the measurement and the hits
585 auto testHit = hVec[hIdx];
586 if (testHit == sp) {
587 usedHitMarker[lIdx][hIdx] += incr;
588 if(!markNeighborHits){
589 break;
590 }
591 } else if (markNeighborHits) {
592 Amg::Vector2D testPosX{Amg::Vector2D::Zero()};
594 switch (testHit->primaryMeasurement()->numDimensions()) {
595 case 1:
596 testPosX[Amg::x] = testHit->primaryMeasurement()->localPosition<1>().x();
597 break;
598 case 2:
599 testPosX = xAOD::toEigen(testHit->primaryMeasurement()->localPosition<2>());
600 break;
601 default:
602 THROW_EXCEPTION("Unsupported dimension");
603 }
604 //if the hit not found let's see if it is too close to the segment's measurement
605 double deltaX = (testPosX - spPosX).mag();
606 if(deltaX < m_maxdYWindow){
607 usedHitMarker[lIdx][hIdx] += incr;
608 }
609 }
610 }
611 }
612 }
613}
614
615StatusCode NswSegmentFinderAlg::execute(const EventContext &ctx) const {
616 // read the inputs
617 const EtaHoughMaxContainer *maxima{nullptr};
618 ATH_CHECK(SG::get( maxima, m_etaKey, ctx));
619
620 const ActsTrk::GeometryContext *gctx{nullptr};
621 ATH_CHECK(SG::get(gctx, m_geoCtxKey, ctx));
622
623 // prepare our output collection
624 SG::WriteHandle writeSegments{m_writeSegmentKey, ctx};
625 ATH_CHECK(writeSegments.record(std::make_unique<SegmentContainer>()));
626
627 SG::WriteHandle writeSegmentSeeds{m_writeSegmentSeedKey, ctx};
628 ATH_CHECK(writeSegmentSeeds.record(std::make_unique<SegmentSeedContainer>()));
629
630 // we use the information from the previous eta-hough transform
631 // to get the combined hits that belong in the same maxima
632 for (const HoughMaximum *max : *maxima) {
633
634 auto [seeds, segments] = findSegmentsFromMaximum(*max, *gctx, ctx);
635
636 if (msgLvl(MSG::VERBOSE)) {
637 for(const auto& hitMax : max->getHitsInMax()){
638 ATH_MSG_VERBOSE("Hit "<<m_idHelperSvc->toString(hitMax->identify())<<", "
639 <<Amg::toString(hitMax->localPosition())<<", dir: "
640 <<Amg::toString(hitMax->sensorDirection()));
641 }
642 }
643
644 for(auto& seed: seeds){
645
646 if (msgLvl(MSG::VERBOSE)){
647 std::stringstream sstr{};
648 sstr<<"Seed tanBeta = "<<seed->tanBeta()<<", y0 = "<<seed->interceptY()
649 <<", tanAlpha = "<<seed->tanAlpha()<<", x0 = "<<seed->interceptX()<<", hits in the seed "
650 <<seed->getHitsInMax().size()<<std::endl;
651
652 for(const auto& hit : seed->getHitsInMax()){
653 sstr<<" *** Hit "<<m_idHelperSvc->toString(hit->identify())<<", "
654 << Amg::toString(hit->localPosition())<<", dir: "<<Amg::toString(hit->sensorDirection())<<std::endl;
655 }
656 ATH_MSG_VERBOSE(sstr.str());
657 }
658 if (m_visionTool.isEnabled()) {
659 m_visionTool->visualizeSeed(ctx, *seed, "#phi-combinatorialSeed");
660 }
661
662 writeSegmentSeeds->push_back(std::move(seed));
663
664 }
665
666 for (auto &seg : segments) {
667
668 const Parameters pars = localSegmentPars(*gctx, *seg);
669
670 ATH_MSG_VERBOSE("Segment parameters : "<<toString(pars));
671
672 if (m_visionTool.isEnabled()) {
673 m_visionTool->visualizeSegment(ctx, *seg, "#phi-segment");
674 }
675
676 writeSegments->push_back(std::move(seg));
677
678 }
679 }
680
681 return StatusCode::SUCCESS;
682}
683
685
687 m_seedCounter->printTableSeedStats(msgStream());
688 }
689 return StatusCode::SUCCESS;
690}
691
692void NswSegmentFinderAlg::SeedStatistics::addToStat(const MuonGMR4::SpectrometerSector* msSector, unsigned seeds, unsigned extSeeds, unsigned segments){
693 std::unique_lock guard{m_mutex};
694 SectorField key{};
695 key.chIdx = msSector->chamberIndex();
696 key.phi = msSector->stationPhi();
697 key.eta = msSector->chambers().front()->stationEta();
698
699 auto &entry = m_seedStat[key];
700 entry.nSeeds += seeds;
701 entry.nExtSeeds += extSeeds;
702 entry.nSegments += segments;
703}
704
706
707
708 msg<<MSG::ALWAYS<<"Seed statistics per sector:"<<endmsg;
709 msg<<MSG::ALWAYS<<"-----------------------------------------------------"<<endmsg;
710 msg<<MSG::ALWAYS<<"| Chamber | Phi | Eta | Seeds | ExtSeeds | Segments |"<<endmsg;
711 msg<<MSG::ALWAYS<<"-----------------------------------------------------"<<endmsg;
712
714
715 for (const auto& entry : m_seedStat) {
716 const auto& sector = entry.first;
717 const auto& stats = entry.second;
718
719
720 msg<<MSG::ALWAYS << "| " << std::setw(3) << (sector.chIdx == ChIndex::EIL ? "EIL" :"EIS")
721 <<" | " << std::setw(2) << sector.phi
722 << " | " << std::setw(3) << sector.eta
723 << " | " << std::setw(7) << stats.nSeeds
724 << " | " << std::setw(8) << stats.nExtSeeds
725 << " | " << std::setw(8) << stats.nSegments
726 << " |"<<endmsg;
727
728
729 }
730
731 msg<<MSG::ALWAYS<<"------------------------------------------------------------"<<endmsg;
732 }
733
734
735} // namespace MuonR4
const boost::regex re(r_e)
Scalar mag() const
mag method
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define AmgSymMatrix(dim)
ATLAS-specific HepMC functions.
static Double_t sp
#define TEST_HIT_CORRIDOR(LAYER, HIT_ITER, START_LAYER)
Macro to check whether a hit is compatible with the hit corridor.
#define x
#define max(a, b)
Definition cfImp.cxx:41
const ServiceHandle< StoreGateSvc > & detStore() const
bool msgLvl(const MSG::Level lvl) const
const StripLayer & stripLayer(const Identifier &measId) const
int multilayer() const
Returns the multi layer of the element [1-2].
The MuonReadoutElement is an abstract class representing the geometry representing the muon detector.
const SpectrometerSector * msSector() const
Returns the pointer to the envelope volume enclosing all chambers in the sector.
const Amg::Transform3D & localToGlobalTrans(const ActsTrk::GeometryContext &ctx) const
Returns the local to global transformation into the ATLAS coordinate system.
A spectrometer sector forms the envelope of all chambers that are placed in the same MS sector & laye...
Amg::Transform3D globalToLocalTrans(const ActsTrk::GeometryContext &gctx) const
Returns the global -> local transformation from the ATLAS global.
const Amg::Transform3D & localToGlobalTrans(const ActsTrk::GeometryContext &gctx) const
Returns the local -> global tarnsformation from the sector.
const ChamberSet & chambers() const
Returns the associated chambers with this sector.
int stationPhi() const
: Returns the station phi of the sector
Muon::MuonStationIndex::ChIndex chamberIndex() const
Returns the chamber index scheme.
const StripDesign & design(bool phiView=false) const
Returns the underlying strip design.
Data class to represent an eta maximum in hough space.
std::vector< CalibSpacePointPtr > CalibSpacePointVec
void addToStat(const MuonGMR4::SpectrometerSector *msSector, unsigned int nSeeds, unsigned int nExtSeeds, unsigned int nSegments)
const MuonGMR4::MuonDetectorManager * m_detMgr
UnsignedIntegerProperty m_maxUsed
std::unique_ptr< SegmentSeed > buildSegmentSeed(const InitialSeed_t &initialSeed, const AmgSymMatrix(2)&bMatrix, const HoughMaximum &max, const HitLaySpan_t &extensionLayers, const UsedHitSpan_t &usedHits) const
Build the final seed from the initial seed hits and then attempt to append hits from the complementar...
std::pair< std::vector< std::unique_ptr< SegmentSeed > >, std::vector< std::unique_ptr< Segment > > > findSegmentsFromMaximum(const HoughMaximum &max, const ActsTrk::GeometryContext &gctx, const EventContext &ctx) const
Find seed and segment from an eta hough maximum.
std::unique_ptr< SegmentFit::SegmentLineFitter > m_lineFitter
UnsignedIntegerProperty m_maxClustersInLayer
virtual StatusCode initialize() override
virtual StatusCode execute(const EventContext &ctx) const override
HitWindow
To fastly check whether a hit is roughly compatible with a muon trajectory a narrow corridor is opene...
@ inside
The hit is below the predefined corridor.
@ tooHigh
The hit is inside the defined window and hence an initial candidate.
void constructPrelimnarySeeds(const Amg::Vector3D &beamSpot, const HitLaySpan_t &combinatoricLayers, const UsedHitSpan_t &usedHits, InitialSeedVec_t &outVec) const
Construct a set of prelimnary seeds from the selected combinatoric layers.
std::unique_ptr< Segment > fitSegmentSeed(const EventContext &ctx, const ActsTrk::GeometryContext &gctx, const SegmentSeed *patternSeed) const
Fit the segment seed.
ToolHandle< MuonValR4::IPatternVisualizationTool > m_visionTool
Pattern visualization tool.
std::vector< std::reference_wrapper< const HitVec > > HitLaySpan_t
Abbrivation of the space comprising multiple hit vectors without copy.
std::array< const SpacePoint *, 4 > InitialSeed_t
Abbrivation of the.
SG::WriteHandleKey< SegmentSeedContainer > m_writeSegmentSeedKey
HitWindow hitFromIPCorridor(const SpacePoint &testHit, const Amg::Vector3D &beamSpotPos, const Amg::Vector3D &dirEstUp, const Amg::Vector3D &dirEstDn) const
The hit is above the predefined corridor.
void markHitsAsUsed(const HitVec &spacePoints, const HitLayVec &allSortHits, UsedHitMarker_t &usedHitMarker, unsigned int increase, bool markNeighborHits) const
Hits that are used in a good seed/segment built should be flagged as used and not contribute to other...
UsedHitMarker_t emptyBookKeeper(const HitLayVec &sortedSp) const
Constructs an empty HitMarker from the split space points.
virtual StatusCode finalize() override
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
SpacePointPerLayerSplitter::HitLayVec HitLayVec
SpacePointPerLayerSplitter::HitVec HitVec
std::vector< InitialSeed_t > InitialSeedVec_t
Vector of initial seeds.
StripOrient classifyStrip(const SpacePoint &spacePoint) const
Determines the orientation of the strip space point.
StripOrient
Enumeration to classify the orientation of a NSW strip.
@ X
Stereo strips with negative angle.
@ V
Stereo strips with positive angle.
@ Unknown
Combined 2D space point (sTGC wire + strip / sTgc pad)
SG::WriteHandleKey< SegmentContainer > m_writeSegmentKey
SG::ReadHandleKey< ActsTrk::GeometryContext > m_geoCtxKey
std::vector< std::vector< unsigned int > > UsedHitMarker_t
Abbrivation of the container book keeping whether a hit is used or not.
ToolHandle< ISpacePointCalibrator > m_calibTool
HitVec extendHits(const Amg::Vector3D &startPos, const Amg::Vector3D &direction, const HitLaySpan_t &extensionLayers, const UsedHitSpan_t &usedHits) const
Extend the seed with the hits from the other layers.
UnsignedIntegerProperty m_minSeedHits
SG::ReadHandleKey< EtaHoughMaxContainer > m_etaKey
std::vector< std::reference_wrapper< std::vector< unsigned int > > > UsedHitSpan_t
Abbrivation of the container to pass a subset of markers wtihout copy.
Representation of a segment seed (a fully processed hough maximum) produced by the hough transform.
Definition SegmentSeed.h:14
const std::vector< HitType > & getHitsInMax() const
Returns the list of assigned hits.
const Parameters & parameters() const
Returns the parameter array.
Amg::Vector3D localDirection() const
Returns the direction of the seed in the sector frame.
const MuonGMR4::SpectrometerSector * msSector() const
Returns the associated chamber.
Amg::Vector3D localPosition() const
Returns the position of the seed in the sector frame.
The SpacePointPerLayerSorter sort two given space points by their layer Identifier.
unsigned int sectorLayerNum(const SpacePoint &sp) const
method returning the logic layer number
The SpacePointPerLayerSplitter takes a set of spacepoints already sorted by layer Identifier (see Muo...
const HitLayVec & stripHits() const
Returns the sorted strip hits.
The muon space point is the combination of two uncalibrated measurements one of them measures the eta...
const Identifier & identify() const
: Identifier of the primary measurement
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
ConstVectorMap< 3 > localDirection() const
Returns the local direction of the traversing particle.
Identifier identify() const
Returns the global ATLAS identifier of the SimHit.
ConstVectorMap< 3 > localPosition() const
Returns the local postion of the traversing particle.
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Amg::Vector3D dirFromAngles(const double phi, const double theta)
Constructs a direction vector from the azimuthal & polar angles.
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
Parameters localSegmentPars(const xAOD::MuonSegment &seg)
Returns the localSegPars decoration from a xAODMuon::Segment.
Acts::Experimental::CompositeSpacePointLineFitter::ParamVec_t Parameters
std::string toString(const Parameters &pars)
Dumps the parameters into a string with labels in front of each number.
This header ties the generic definitions in this package.
ISpacePointCalibrator::CalibSpacePointVec CalibSpacePointVec
const xAOD::MuonSimHit * getTruthMatchedHit(const xAOD::UncalibratedMeasurement &prdHit)
Returns the MuonSimHit, if there's any, matched to the uncalibrated muon measurement.
double houghTanBeta(const Amg::Vector3D &v)
Returns the hough tanBeta [y] / [z].
DataVector< HoughMaximum > EtaHoughMaxContainer
constexpr unsigned minLayers
SpacePointPerLayerSplitter::HitVec HitVec
double houghTanAlpha(const Amg::Vector3D &v)
: Returns the hough tanAlpha [x] / [z]
std::unique_ptr< TLatex > drawLabel(const std::string &text, const double xPos, const double yPos, const unsigned int fontSize=18)
Create a TLatex label,.
ChIndex
enum to classify the different chamber layers in the muon spectrometer
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
MuonSimHit_v1 MuonSimHit
Defined the version of the MuonSimHit.
Definition MuonSimHit.h:12
MMCluster_v1 MMCluster
sTgcMeasurement_v1 sTgcMeasurement
const ISpacePointCalibrator * calibrator
Pointer to the calibrator.
const Muon::IMuonIdHelperSvc * idHelperSvc
Pointer to the idHelperSvc.
const MuonValR4::IPatternVisualizationTool * visionTool
Pointer to the visualization tool.
#define THROW_EXCEPTION(MESSAGE)
Definition throwExcept.h:10