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
12
13
15
18
20
21#include "Acts/Seeding/CombinatorialSeedSolver.hpp"
22
23#include <ranges>
24#include <format>
25
26using namespace Acts::Experimental::CombinatorialSeedSolver;
27namespace {
28 inline const MuonGMR4::StripDesign& getDesign(const MuonR4::SpacePoint& sp) {
30 const auto* prd = static_cast<const xAOD::MMCluster*>(sp.primaryMeasurement());
31 return prd->readoutElement()->stripLayer(prd->measurementHash()).design();
32 } else if (sp.type() == xAOD::UncalibMeasType::sTgcStripType) {
33 const auto* prd = static_cast<const xAOD::sTgcMeasurement*>(sp.primaryMeasurement());
34 const auto* re = prd->readoutElement();
35 switch(prd->channelType()) {
37 return re->stripDesign(prd->measurementHash());
39 return re->wireDesign(prd->measurementHash());
41 return re->padDesign(prd->measurementHash());
42 }
43 }
44 THROW_EXCEPTION("Invalid space point for design retrieval "<<sp.msSector()->idHelperSvc()->toString(sp.identify()));
45 }
46 inline double stripHalfLength(const MuonR4::SpacePoint& sp) {
47 const auto& design = getDesign(sp);
49 const auto* prd = static_cast<const xAOD::MMCluster*>(sp.primaryMeasurement());
50 return 0.5* design.stripLength(prd->channelNumber());
51 } else{
52 const auto* prd = static_cast<const xAOD::sTgcMeasurement*>(sp.primaryMeasurement());
53 if(prd->channelType() == sTgcIdHelper::Pad){
54 const auto& padDesign = static_cast<const MuonGMR4::PadDesign&>(design);
55 auto padCorners = padDesign.padCorners(prd->channelNumber());
56 return 0.5* std::abs(padCorners[0].x() - padCorners[1].x());
57 }
58 return 0.5* design.stripLength(prd->channelNumber());
59 }
60
61 return 0.;
62 }
63 inline std::string sTgcChannelType(const int chType) {
64 return chType == sTgcIdHelper::Strip ? "S" :
65 chType == sTgcIdHelper::Wire ? "W" : "P";
66 }
67}
68
69namespace MuonR4 {
70
71using namespace SegmentFit;
72constexpr unsigned minLayers{4};
73
75
77 ATH_CHECK(m_geoCtxKey.initialize());
78 ATH_CHECK(m_etaKey.initialize());
79 ATH_CHECK(m_writeSegmentKey.initialize());
80 ATH_CHECK(m_writeSegmentSeedKey.initialize());
81 ATH_CHECK(m_idHelperSvc.retrieve());
82 ATH_CHECK(m_calibTool.retrieve());
83 ATH_CHECK(m_visionTool.retrieve(DisableTool{m_visionTool.empty()}));
84 ATH_CHECK(detStore()->retrieve(m_detMgr));
85
86 if (!(m_idHelperSvc->hasMM() || m_idHelperSvc->hasSTGC())) {
87 ATH_MSG_ERROR("MM or STGC not part of initialized detector layout");
88 return StatusCode::FAILURE;
89 }
90
92 fitCfg.calibrator = m_calibTool.get();
93 fitCfg.visionTool = m_visionTool.get();
94 fitCfg.calcAlongStrip = false;
95 fitCfg.idHelperSvc = m_idHelperSvc.get();
96 fitCfg.parsToUse = {ParamDefs::x0, ParamDefs::y0, ParamDefs::theta, ParamDefs::phi};
97
98 m_lineFitter = std::make_unique<SegmentFit::SegmentLineFitter>(name(), std::move(fitCfg));
99
101 m_seedCounter = std::make_unique<SeedStatistics>();
102 }
103
104 return StatusCode::SUCCESS;
105}
106
109 UsedHitMarker_t emptyKeeper(sortedSp.size());
110 for (std::size_t l = 0; l < sortedSp.size(); ++l) {
111 emptyKeeper[l].resize(sortedSp[l].size(), 0);
112 }
113 return emptyKeeper;
114}
115
118
120 const auto& design = getDesign(sp);
121 if (!design.hasStereoAngle()) {
122 return StripOrient::X;
123 }
124 return design.stereoAngle() > 0. ? StripOrient::U : StripOrient::V;
125 } else if (sp.type() == xAOD::UncalibMeasType::sTgcStripType) {
126 const auto* prd = static_cast<const xAOD::sTgcMeasurement*>(sp.primaryMeasurement());
127 if (sp.dimension() == 2) {
128 return StripOrient::C;
129 }
130 //check if we have strip only or wire only measurements
131 return prd->channelType() == sTgcIdHelper::Strip ? StripOrient::X : StripOrient::P;
132
133 }
134 ATH_MSG_WARNING("Cannot classify orientation of "<<m_idHelperSvc->toString(sp.identify()));
136}
139 const Amg::Vector3D& beamSpotPos,
140 const Amg::Vector3D& dirEstUp,
141 const Amg::Vector3D& dirEstDn) const{
142
143 const Amg::Vector3D estPlaneArrivalUp = SeedingAux::extrapolateToPlane(beamSpotPos, dirEstUp, testHit);
144 const Amg::Vector3D estPlaneArrivalDn = SeedingAux::extrapolateToPlane(beamSpotPos, dirEstDn, testHit);
145
146 bool below{true}, above{true};
147 switch (classifyStrip(testHit)) {
148 using enum StripOrient;
149 case U:
150 case V:{
151 const double halfLength = 0.5* stripHalfLength(testHit);
153 const Amg::Vector3D leftEdge = testHit.localPosition() - halfLength * testHit.sensorDirection();
154 const Amg::Vector3D rightEdge = testHit.localPosition() + halfLength * testHit.sensorDirection();
155
157 below = estPlaneArrivalDn.y() > std::max(leftEdge.y(), rightEdge.y());
159 above = estPlaneArrivalUp.y() < std::min(leftEdge.y(), rightEdge.y());
160 break;
161 } case X:
162 case C: {
164 const double hY = testHit.localPosition().y();
165 below = estPlaneArrivalDn.y() > hY;
167 above = estPlaneArrivalUp.y() < hY;
168 break;
169 }
170 case P:{
171 break;
172 }
173 case Unknown:{
174 break;
175 }
176
177 }
178 ATH_MSG_VERBOSE("Hit " << m_idHelperSvc->toString(testHit.identify())
179 << (below || above ? " is outside the window" : " is inside the window"));
180 if(below) {
181 return HitWindow::tooLow;
182 }
183 if(above) {
184 return HitWindow::tooHigh;
185 }
186 return HitWindow::inside;
187};
188
190#define TEST_HIT_CORRIDOR(LAYER, HIT_ITER, START_LAYER) \
191{ \
192 const SpacePoint* testMe = combinatoricLayers[LAYER].get()[HIT_ITER]; \
193 if (usedHits[LAYER].get()[HIT_ITER] > m_maxUsed) { \
194 ATH_MSG_VERBOSE(__func__<<":"<<__LINE__<<" - " \
195 <<m_idHelperSvc->toString(testMe->identify()) \
196 <<" already used in good seed." ); \
197 continue; \
198 } \
199 const HitWindow inWindow = hitFromIPCorridor(*testMe, beamSpot, dirEstUp, dirEstDn); \
200 if(inWindow == HitWindow::tooHigh) { \
201 ATH_MSG_VERBOSE(__func__<<":"<<__LINE__<<" - Hit " \
202 <<m_idHelperSvc->toString(testMe->identify()) \
203 <<" is beyond the corridor. Break loop"); \
204 break; \
205 } else if (inWindow == HitWindow::tooLow) { \
206 START_LAYER = HIT_ITER + 1; \
207 ATH_MSG_VERBOSE(__func__<<":"<<__LINE__<<" - Hit " \
208 <<m_idHelperSvc->toString(testMe->identify()) \
209 <<" is still below the corridor. Update start to " \
210 <<START_LAYER); \
211 continue; \
212 } \
213}
214
216 const HitLaySpan_t& combinatoricLayers,
217 const UsedHitSpan_t& usedHits,
218 InitialSeedVec_t& seedHitsFromLayers) const {
220 seedHitsFromLayers.clear();
221 std::size_t maxSize{1};
222 for (const HitVec& hitVec : combinatoricLayers) {
223 maxSize = maxSize * hitVec.size();
224 }
225 seedHitsFromLayers.reserve(maxSize);
226
227 unsigned iterLay0{0}, iterLay1{0}, iterLay2{0}, iterLay3{0};
228 unsigned startLay1{0}, startLay2{0}, startLay3{0};
229
230 for( ; iterLay0 < combinatoricLayers[0].get().size() ; ++iterLay0){
232 if (usedHits[0].get()[iterLay0] > m_maxUsed) {
233 continue;
234 }
235 const SpacePoint* hit0 = combinatoricLayers[0].get()[iterLay0];
237 const Amg::Vector3D initSeedDir{(beamSpot - hit0->localPosition()).unit()};
238 const Amg::Vector3D dirEstUp = Amg::dirFromAngles(initSeedDir.phi(), initSeedDir.theta() - m_windowTheta);
239 const Amg::Vector3D dirEstDn = Amg::dirFromAngles(initSeedDir.phi(), initSeedDir.theta() + m_windowTheta);
240
241 ATH_MSG_VERBOSE("Reference hit: "<<m_idHelperSvc->toString(hit0->identify())
242 <<", position: "<<Amg::toString(hit0->localPosition())
243 <<", seed dir: "<<Amg::toString(initSeedDir)
244 <<", seed plane: "<<Amg::toString(SeedingAux::extrapolateToPlane(beamSpot, initSeedDir, *hit0)));
246 for( iterLay1 = startLay1; iterLay1 < combinatoricLayers[1].get().size() ; ++iterLay1){
247 TEST_HIT_CORRIDOR(1, iterLay1, startLay1);
248 for( iterLay2 = startLay2; iterLay2 < combinatoricLayers[2].get().size() ; ++iterLay2){
249 TEST_HIT_CORRIDOR(2, iterLay2, startLay2);
250 for( iterLay3 = startLay3; iterLay3 < combinatoricLayers[3].get().size(); ++iterLay3){
251 TEST_HIT_CORRIDOR(3, iterLay3, startLay3);
252 seedHitsFromLayers.emplace_back(std::array{hit0, combinatoricLayers[1].get()[iterLay1],
253 combinatoricLayers[2].get()[iterLay2],
254 combinatoricLayers[3].get()[iterLay3]});
255 }
256 }
257 }
258 }
259}
260#undef TEST_HIT_CORRIDOR
261
264 const Amg::Vector3D& direction,
265 const HitLaySpan_t& extensionLayers,
266 const UsedHitSpan_t& usedHits) const {
267
268 //the hits we need to return to extend the segment seed
269 HitVec combinatoricHits;
270
271 for (std::size_t i = 0; i < extensionLayers.size(); ++i) {
272 const HitVec& layer{extensionLayers[i].get()};
273 const Amg::Vector3D extrapPos = SeedingAux::extrapolateToPlane(startPos, direction, *layer.front());
274
275 unsigned indexOfHit = layer.size() + 1;
276 unsigned triedHit{0};
277 double minPull{std::numeric_limits<double>::max()};
278
279 // loop over the hits on the same layer
280 for (unsigned j = 0; j < layer.size(); ++j) {
281 if (usedHits[i].get().at(j) > m_maxUsed) {
282 continue;
283 }
284 auto hit = layer.at(j);
285 const double pull = std::sqrt(SeedingAux::chi2Term(extrapPos, direction, *hit));
286 ATH_MSG_VERBOSE("Trying extension with hit " << m_idHelperSvc->toString(hit->identify()));
287
288 //find the hit with the minimum pull (check at least one hit after we have increasing pulls)
289 if (pull > minPull) {
290 triedHit+=1;
291 continue;
292 }
293
294 if(triedHit>1){
295 break;
296 }
297
298 indexOfHit = j;
299 minPull = pull;
300 }
301
302 // complete the seed with the extended hits
303 if (minPull < m_minPullThreshold) {
304 const auto* bestCand = layer.at(indexOfHit);
305 ATH_MSG_VERBOSE("Extension successfull - hit" << m_idHelperSvc->toString(bestCand->identify())
306 <<", pos: "<<Amg::toString(bestCand->localPosition())
307 <<", dir: "<<Amg::toString(bestCand->sensorDirection())<<" found with pull "<<minPull);
308 combinatoricHits.push_back(bestCand);
309 }
310 }
311 return combinatoricHits;
312}
313
314std::unique_ptr<SegmentSeed>
316 const AmgSymMatrix(2)& bMatrix,
317 const HoughMaximum& max,
318 const HitLaySpan_t& extensionLayers,
319 const UsedHitSpan_t& usedHits) const {
320 bool allValid = std::any_of(initialSeed.begin(), initialSeed.end(),
321 [this](const auto& hit){
322 if (hit->type() == xAOD::UncalibMeasType::MMClusterType) {
323 const auto* mmClust = static_cast<const xAOD::MMCluster*>(hit->primaryMeasurement());
324 return mmClust->stripNumbers().size() >= m_minClusSize;
325 }
326 return true;
327 });
328
329 if (!allValid) {
330 ATH_MSG_VERBOSE("Seed rejection: Not all clusters meet minimum strip size");
331 return nullptr;
332 }
333
334
335 std::array<double, 4> params = defineParameters(bMatrix, initialSeed);
336
337 const auto [segPos, direction] = seedSolution(initialSeed, params);
338
339 // check the consistency of the parameters - expected to lay in the strip's
340 // length
341 for (std::size_t i = 0; i < 4; ++i) {
342 const double halfLength = stripHalfLength(*initialSeed[i]);
343
344 if (std::abs(params[i]) > halfLength) {
345 ATH_MSG_VERBOSE("Seed Rejection: Invalid seed - outside of the strip's length "<< m_idHelperSvc->toString(initialSeed[i]->identify())
346 <<", param: "<<params[i]<<", halfLength: "<<halfLength);
347 return nullptr;
348 }
349 }
350 double tanAlpha = houghTanAlpha(direction);
351 double tanBeta = houghTanBeta(direction);
352
353 double interceptX = segPos.x();
354 double interceptY = segPos.y();
355
356
357 // extend the seed to the segment -- include hits from the other layers too
358 auto extendedHits = extendHits(segPos, direction, extensionLayers, usedHits);
359 HitVec hits{initialSeed.begin(),initialSeed.end()};
360 std::ranges::move(extendedHits, std::back_inserter(hits));
361
362 return std::make_unique<SegmentSeed>(tanBeta, interceptY, tanAlpha,
363 interceptX, hits.size(),
364 std::move(hits), max.parentBucket());
365}
366
367
368std::unique_ptr<Segment> NswSegmentFinderAlg::fitSegmentSeed(const EventContext& ctx,
369 const ActsTrk::GeometryContext& gctx,
370 const SegmentSeed* patternSeed) const{
371
372 if(patternSeed->getHitsInMax().size() < m_minSeedHits){
373 ATH_MSG_VERBOSE("Not enough hits in the SegmentSeed to fit a segment");
374 return nullptr;
375 }
376
377 ATH_MSG_VERBOSE("Fit the SegmentSeed");
378 if (msgLvl(MSG::VERBOSE)) {
379 std::stringstream hitStream{};
380 for (const auto& hit : patternSeed->getHitsInMax()) {
381 hitStream<<"**** "<< (*hit)<<std::endl;
382 }
383 ATH_MSG_VERBOSE(__func__<<"() - "<<__LINE__ <<": Uncalibrated space points for the segment fit: "<<std::endl
384 <<hitStream.str());
385 }
386
387 //Calibration of the seed spacepoints
388 CalibSpacePointVec calibratedHits = m_calibTool->calibrate(ctx, patternSeed->getHitsInMax(),
389 patternSeed->localPosition(),
390 patternSeed->localDirection(), 0.);
391
392 const Amg::Transform3D& locToGlob{patternSeed->msSector()->localToGlobalTransform(gctx)};
393
394 return m_lineFitter->fitSegment(ctx, patternSeed, patternSeed->parameters(),
395 locToGlob, std::move(calibratedHits));
396}
397
398void NswSegmentFinderAlg::processSegment(std::unique_ptr<Segment> segment,
399 const HitVec& seedHits,
400 const HitLayVec& hitLayers,
401 UsedHitMarker_t& usedHits,
402 SegmentVec_t& segments) const {
403
404 if (!segment) {
405 ATH_MSG_VERBOSE("Seed Rejection: Segment fit failed");
406
407 if (m_markHitsFromSeed && seedHits.size() > m_minSeedHits) {
408 // Mark hits from extended seed (used increment by 1)
409 markHitsAsUsed(seedHits, hitLayers, usedHits, 1, false);
410 }
411 return;
412 }
413
414 // -------- success path --------
415 ATH_MSG_DEBUG("Segment built with "
416 << segment->measurements().size()
417 << " hits, chi2/ndof: "
418 << segment->chi2() / std::max(1u,segment->nDoF()));
419
420 HitVec segMeasSP;
421 segMeasSP.reserve(segment->measurements().size());
422
423 std::ranges::transform(
424 segment->measurements(),
425 std::back_inserter(segMeasSP),
426 [](const auto& m) { return m->spacePoint(); }
427 );
428
429 // Mark segment hits as fully used (used increment by 10,
430 // hits are effectively removed)
431 markHitsAsUsed(segMeasSP, hitLayers, usedHits, 10, true);
432 segments.push_back(std::move(segment));
433
434}
435
436std::pair<NswSegmentFinderAlg::SegmentSeedVec_t, NswSegmentFinderAlg::SegmentVec_t>
438 const ActsTrk::GeometryContext &gctx,
439 const HitLayVec& hitLayers,
440 const HoughMaximum& max,
441 const Amg::Vector3D& beamSpotPos,
442 UsedHitMarker_t& usedHits) const {
443
444 //go through the layers and build seeds from the combinations of hits
445 //starting from the outermost layers with 2D measurements (excluding pads)
446 SegmentSeedVec_t seeds{};
447 SegmentVec_t segments{};
448 std::size_t layerSize = hitLayers.size();
449 double thetaWindowCut{std::cos(2*m_windowTheta)};
450
451 // lamda helper to check if the spacepoint is combined (but not pad) and unused in an already constructed seed
452 auto isUnusedCombined = [&](std::size_t layIdx, std::size_t hitIdx) -> bool {
453 const SpacePoint* sp = hitLayers[layIdx][hitIdx];
455 THROW_EXCEPTION("Space point is not of sTgc type: "<<sp->msSector()->idHelperSvc()->toString(sp->identify()));
456 }
457 const auto* prd = static_cast<const xAOD::sTgcMeasurement*>(sp->primaryMeasurement());
458 bool isCombined = sTgcChannelType(prd->channelType()) == "S" && sp->dimension() == 2;
459 bool isUnused = usedHits[layIdx].at(hitIdx) <= m_maxUsed;
460 return isCombined && isUnused;
461
462 };
463
464 // find the 2D measurements from the outermost layers - even move one layer inside
465 for(std::size_t layIdx1 = 0; layIdx1 < 2; ++layIdx1){
466 for(std::size_t layIdx2 = layerSize-1; layIdx2 >= layerSize-2; --layIdx2){
467 //in case of MM layers we stop - the layers are sorted in Z
468 if(hitLayers[layIdx1].front()->type() == xAOD::UncalibMeasType::MMClusterType ||
469 hitLayers[layIdx2].front()->type() == xAOD::UncalibMeasType::MMClusterType){
470 ATH_MSG_VERBOSE("Outermost layers are MM - stop searching for sTgc Measurements");
471 return std::make_pair(std::move(seeds), std::move(segments));
472 }
473
474 //check if we have 2D measurements on these layers that are unused (excluding the pads)
475 for(std::size_t hitIdx1 = 0; hitIdx1 < hitLayers[layIdx1].size(); ++hitIdx1) {
476 const SpacePoint* hit1 = hitLayers[layIdx1][hitIdx1];
477 if(!isUnusedCombined(layIdx1, hitIdx1)){
478 continue;
479 }
480 for(std::size_t hitIdx2 = 0; hitIdx2 < hitLayers[layIdx2].size(); ++hitIdx2) {
481 const SpacePoint* hit2 = hitLayers[layIdx2][hitIdx2];
482 if(!isUnusedCombined(layIdx2, hitIdx2)){
483 continue;
484 }
485 //test if this selection of the hits from the two layers is aligned with the beam spot
486 const Amg::Vector3D beamSpotHitDir{(beamSpotPos - hit1->localPosition()).unit()};
487 const Amg::Vector3D seedDir{(hit2->localPosition() - hit1->localPosition()).unit()};
488 const double cosAngle = beamSpotHitDir.dot(seedDir);
489 //accept the deflection of direction with a tolerance of 1 deg
490 if(std::abs(cosAngle) < thetaWindowCut){
491 continue;
492 }
493 //found 2D hits on the outermost layers - build a seed
494 HitVec seedHits{hit1, hit2};
495 //get the seed direction and position from the two 2D hits
496 const Amg::Vector3D seedPos = hit1->localPosition();
497 //express position in z=0
498 const Amg::Vector3D seedPosZ0 = seedPos + Amg::intersect<3>(seedPos, seedDir, Amg::Vector3D::UnitZ(), 0.).value_or(0.)*seedDir;
499 // extend the seed to the other layers
500 HitLaySpan_t extensionLayers{};
501 UsedHitSpan_t usedExtensionHits{};
502 extensionLayers.reserve(hitLayers.size());
503 usedExtensionHits.reserve(hitLayers.size());
504 for (std::size_t e = 0 ; e < hitLayers.size(); ++e) {
505 if (!(e == layIdx1 || e == layIdx2)){
506 extensionLayers.emplace_back(hitLayers[e]);
507 usedExtensionHits.emplace_back(usedHits[e]);
508 }
509 }
510 auto extendedHits = extendHits(seedPosZ0, seedDir, extensionLayers, usedExtensionHits);
511 std::ranges::move(extendedHits, std::back_inserter(seedHits));
512
513 //make seed
514 auto seed = std::make_unique<SegmentSeed>(houghTanBeta(seedDir), seedPosZ0.y(),
515 houghTanAlpha(seedDir), seedPosZ0.x(),
516 seedHits.size(), std::move(seedHits),
517 max.parentBucket());
518
519 //skip segment fit with less than 5 hits
520 if(seed->getHitsInMax().size() < m_minSeedHits){
521 seeds.push_back(std::move(seed));
522 continue;
523 }
524 //fit the segment seed
525 std::unique_ptr<Segment> segment = fitSegmentSeed(ctx, gctx, seed.get());
526 processSegment(std::move(segment), seed->getHitsInMax(), hitLayers, usedHits, segments);
527 seeds.push_back(std::move(seed));
528
529 }
530 }
531 }
532 }
533 return std::make_pair(std::move(seeds),std::move(segments));
534}
535
536std::pair<NswSegmentFinderAlg::SegmentSeedVec_t, NswSegmentFinderAlg::SegmentVec_t>
538 const ActsTrk::GeometryContext &gctx,
539 const HitLayVec& hitLayers,
540 const HoughMaximum& max,
541 const Amg::Vector3D& beamSpotPos,
542 UsedHitMarker_t& usedHits,
543 bool useOnlyMM) const {
544
545 //go through the layers and build seeds from the combinations of hits
546 SegmentSeedVec_t seeds{};
547 SegmentVec_t segments{};
548 std::size_t layerSize = hitLayers.size();
549
550 if(layerSize < minLayers){
551 ATH_MSG_VERBOSE("Not enough layers to build a seed");
552 return {std::move(seeds), std::move(segments)};
553 }
554
555 //lamda helper to find the first unused strip hit on the layer
556 auto unusedStripHit = [&](const HitVec& layerHits, unsigned int layIdx) -> const SpacePoint* {
557 //in case of MM only combinatorial seeding - we consider only MM strip hits for seeding
558 bool isMM = useOnlyMM ? layerHits.front()->type() == xAOD::UncalibMeasType::MMClusterType : true;
559 for (auto [idx, hit] : Acts::enumerate(layerHits)) {
560 auto spOrient = classifyStrip(*hit);
561 bool isStrip = spOrient == StripOrient::X || spOrient == StripOrient::U || spOrient == StripOrient::V;
562 bool isUnused = usedHits[layIdx].at(idx) <= m_maxUsed;
563 if (isStrip && isUnused && isMM) {
564 return hit;
565 }
566 }
567 return nullptr;
568 };
569
570 std::array<const SpacePoint*, 4> seedHits{};
571 InitialSeedVec_t preLimSeeds{};
572
573 for (std::size_t i = 0; i < layerSize - 3; ++i) {
574 seedHits[0] = unusedStripHit(hitLayers[i], i);
575 if(!seedHits[0]) {
576 continue;
577 }
578 for (std::size_t j = i + 1; j < layerSize - 2; ++j) {
579 seedHits[1] = unusedStripHit(hitLayers[j], j);
580 if(!seedHits[1]){
581 continue;
582 }
583 for (std::size_t k = j + 1; k < layerSize - 1; ++k) {
584 seedHits[2] = unusedStripHit(hitLayers[k], k);
585 if(!seedHits[2]){
586 continue;
587 }
588 for (std::size_t l = k + 1; l < layerSize; ++l) {
589 seedHits[3] = unusedStripHit(hitLayers[l], l);
590 if(!seedHits[3]){
591 continue;
592 }
593
594 const HitLaySpan_t layers{hitLayers[i], hitLayers[j], hitLayers[k], hitLayers[l]};
595 //skip combination with at least one too busy layer
596 bool tooBusy = std::ranges::any_of(layers,
597 [this](const auto& layer) {
598 return layer.get().size() > m_maxClustersInLayer;
599 });
600 if (tooBusy) {
601 continue; // skip this combination
602 }
603
604 AmgSymMatrix(2) bMatrix = betaMatrix(seedHits);
605
606 if (std::abs(bMatrix.determinant()) < 1.e-6) {
607 continue;
608 }
609 ATH_MSG_DEBUG("Space point positions for seed layers: \n"
610 <<(*seedHits[0]) << ",\n"
611 <<(*seedHits[1]) << ",\n"
612 <<(*seedHits[2]) << ",\n"
613 <<(*seedHits[3]));
614
615
616 UsedHitSpan_t usedHitsSpan{usedHits[i], usedHits[j], usedHits[k], usedHits[l]};
617 // each layer may have more than one hit - take the hit combinations
618 constructPreliminarySeeds(beamSpotPos, layers, usedHitsSpan, preLimSeeds);
619
620 //the layers not participated in the seed build - gonna be used for the extension
621 HitLaySpan_t extensionLayers{};
622 UsedHitSpan_t usedExtensionHits{};
623 usedExtensionHits.reserve(hitLayers.size());
624 extensionLayers.reserve(hitLayers.size());
625 for (std::size_t e = 0 ; e < hitLayers.size(); ++e) {
626 if (!(e == i || e == j || e == k || e == l)){
627 extensionLayers.emplace_back(hitLayers[e]);
628 usedExtensionHits.emplace_back(usedHits[e]);
629 }
630 }
631 // we have made sure to have hits from all the four layers -
632 // start by 4 hits for the seed and try to build the extended seed for the combinatorics found
633 for (auto &combinatoricHits : preLimSeeds) {
634 auto seed = constructCombinatorialSeed(combinatoricHits, bMatrix, max, extensionLayers, usedExtensionHits);
635 if(!seed){
636 continue;
637 }
638 if (seed->getHitsInMax().size() < m_minSeedHits) {
639 seeds.push_back(std::move(seed));
640 continue;
641 }
642
643 std::unique_ptr<Segment> segment = fitSegmentSeed(ctx, gctx, seed.get());
644 processSegment(std::move(segment), seed->getHitsInMax(), hitLayers, usedHits, segments);
645 seeds.push_back(std::move(seed));
646
647 }
648 }
649 }
650 }
651 }
652 return std::make_pair(std::move(seeds),std::move(segments));
653}
654
655std::pair<NswSegmentFinderAlg::SegmentSeedVec_t, NswSegmentFinderAlg::SegmentVec_t>
657 const ActsTrk::GeometryContext &gctx,
658 const EventContext& ctx) const {
659 // first sort the hits per layer from the maximum
660 SpacePointPerLayerSplitter hitLayers{max.getHitsInMax()};
661
662 const HitLayVec& stripHitsLayers{hitLayers.stripHits()};
663 const std::size_t layerSize = stripHitsLayers.size();
664
665 //seeds and segments containers
666 SegmentSeedVec_t seeds{};
667 SegmentVec_t segments{};
668
669 const Amg::Transform3D globToLocal = max.msSector()->globalToLocalTransform(gctx);
670 //counters for the number of seeds, extented seeds and segments
671
672 if (layerSize < minLayers) {
673 ATH_MSG_VERBOSE("Not enough layers to build a seed");
674 return std::make_pair(std::move(seeds),std::move(segments));
675 }
676
677 if (m_visionTool.isEnabled()) {
679 constexpr double legX{0.2};
680 double legY{0.8};
681 for (const SpacePoint* sp : max.getHitsInMax()) {
682 const xAOD::MuonSimHit* simHit = getTruthMatchedHit(*sp->primaryMeasurement());
683 if (!simHit) {
684 continue;
685 }
686
687 const MuonGMR4::MuonReadoutElement* reEle = m_detMgr->getReadoutElement(simHit->identify());
688 const Amg::Transform3D toChamb = reEle->msSector()->globalToLocalTransform(gctx) *
689 reEle->localToGlobalTransform(gctx, sp->identify());
690
691 const Amg::Vector3D hitPos = toChamb * xAOD::toEigen(simHit->localPosition());
692 const Amg::Vector3D hitDir = toChamb.linear() * xAOD::toEigen(simHit->localDirection());
693 const double pull = std::sqrt(SeedingAux::chi2Term(hitPos, hitDir, *sp));
694
696 const auto* mmClust = static_cast<const xAOD::MMCluster*>(sp->primaryMeasurement());
697 const MuonGMR4::MmReadoutElement* mmEle = mmClust->readoutElement();
698 const auto& design = mmEle->stripLayer(mmClust->measurementHash()).design();
699 std::string stereoDesign{!design.hasStereoAngle() ? "X" : design.stereoAngle() >0 ? "U": "V"};
700 primitives.push_back(MuonValR4::drawLabel(std::format("ml: {:1d}, gap: {:1d}, {:}, pull: {:.2f}",
701 mmEle->multilayer(), mmClust->gasGap(),
702 stereoDesign, pull), legX, legY, 14));
703 } else if(sp->type() == xAOD::UncalibMeasType::sTgcStripType) {
704 const auto* sTgcMeas = static_cast<const xAOD::sTgcMeasurement*>(sp->primaryMeasurement());
705 std::string channelString = sp->secondaryMeasurement() == nullptr ?
706 sTgcChannelType(sTgcMeas->channelType()) :
707 std::format("{:}/{:}", sTgcChannelType(sTgcMeas->channelType()),
708 sTgcChannelType(static_cast<const xAOD::sTgcMeasurement*>(sp->secondaryMeasurement())->channelType()));
709 primitives.push_back(MuonValR4::drawLabel(std::format("ml: {:1d}, gap: {:1d}, type: {:}, pull: {:.2f}",
710 sTgcMeas->readoutElement()->multilayer(), sTgcMeas->gasGap(),
711 channelString, pull), legX, legY, 14));
712 }
713 legY-=0.05;
714 }
715 m_visionTool->visualizeBucket(ctx, *max.parentBucket(),
716 "truth", std::move(primitives));
717 }
718
719 UsedHitMarker_t allUsedHits = emptyBookKeeper(stripHitsLayers);
720 std::size_t nSeeds{0}, nExtSeeds{0}, nSegments{0}; //for the seed statistics
721
722 // helper lamda function to increase counters and fill the seeds and segments we want to return after we construct them
723 // the extended seeds are returned even if they did not make it to a segment and the segments only if successfully fitted
724 auto processSeedsAndSegments = [&](std::pair<SegmentSeedVec_t, SegmentVec_t>&& seedSegmentPairs, std::string_view source) {
725 auto& [returnSeeds, returnSegments] = seedSegmentPairs;
726 ATH_MSG_DEBUG("From " << source << ": built " << returnSeeds.size() << " seeds and " << returnSegments.size() << " segments.");
727 for(auto& seed : returnSeeds) {
728 ++nSeeds;
729 if(seed->getHitsInMax().size() < m_minSeedHits){
730 continue;
731 }
732 ++nExtSeeds;
733 seeds.push_back(std::move(seed));
734 }
735 //move all the segments to the output container
736 std::ranges::move(returnSegments, std::back_inserter(segments));
737 nSegments += returnSegments.size();
738 };
739
740 //Start from outermost sTgc layers with combined 2D measurements
741 ATH_MSG_VERBOSE("Start building seed from sTgc outermost layers");
742 processSeedsAndSegments(buildSegmentsFromSTGC(ctx, gctx, stripHitsLayers, max, globToLocal.translation(), allUsedHits), "sTgc segment seeds");
743
744 //continue with the combinatorial seeding for the strip measurements
746
747 processSeedsAndSegments(buildSegmentsFromMM(ctx, gctx, stripHitsLayers, max, globToLocal.translation(), allUsedHits, true), "MM combinatoric segment seeds");
748
749 }else{
750
751 processSeedsAndSegments(buildSegmentsFromMM(ctx, gctx, stripHitsLayers, max, globToLocal.translation(), allUsedHits, true), "MM combinatoric segment seeds");
752 processSeedsAndSegments(buildSegmentsFromMM(ctx, gctx, stripHitsLayers, max, globToLocal.translation(), allUsedHits, false), "MM and STGC combinatoric segment seeds");
753
754 }
755
756 if(m_seedCounter) {
757 m_seedCounter->addToStat(max.msSector(), nSeeds, nExtSeeds, nSegments);
758 }
759
760 return std::make_pair(std::move(seeds),std::move(segments));
761}
762
764 const HitLayVec& allSortHits,
765 UsedHitMarker_t& usedHitMarker,
766 unsigned incr,
767 bool markNeighborHits) const {
768
769 SpacePointPerLayerSorter layerSorter{};
770
771 for(const auto& sp : spacePoints){
772 // Proection against the auxiliary measurement
773 if(!sp){
774 continue;
775 }
776
777 unsigned measLayer = layerSorter.sectorLayerNum(*sp);
778
779 Amg::Vector2D spPosX{Amg::Vector2D::Zero()};
781 switch (sp->primaryMeasurement()->numDimensions()) {
782 case 1:
783 spPosX[Amg::x] = sp->primaryMeasurement()->localPosition<1>().x();
784 break;
785 case 2:
786 spPosX = xAOD::toEigen(sp->primaryMeasurement()->localPosition<2>());
787 break;
788 default:
789 THROW_EXCEPTION("Unsupported dimension");
790 }
791
792 for (std::size_t lIdx = 0; lIdx < allSortHits.size(); ++lIdx) {
793 const HitVec& hVec{allSortHits[lIdx]};
794 //check if they are not in the same layer
795 unsigned hitLayer = layerSorter.sectorLayerNum(*hVec.front());
796 if(hitLayer != measLayer) {
797 ATH_MSG_VERBOSE("Not in the same layer since measLayer = "<< measLayer << " and "<<hitLayer);
798 continue;
799 }
800 for (std::size_t hIdx = 0 ; hIdx < hVec.size(); ++hIdx) {
801 //check the dY between the measurement and the hits
802 auto testHit = hVec[hIdx];
803 if (testHit == sp) {
804 usedHitMarker[lIdx][hIdx] += incr;
805 if(!markNeighborHits){
806 break;
807 }
808 } else if (markNeighborHits) {
809 Amg::Vector2D testPosX{Amg::Vector2D::Zero()};
811 switch (testHit->primaryMeasurement()->numDimensions()) {
812 case 1:
813 testPosX[Amg::x] = testHit->primaryMeasurement()->localPosition<1>().x();
814 break;
815 case 2:
816 testPosX = xAOD::toEigen(testHit->primaryMeasurement()->localPosition<2>());
817 break;
818 default:
819 THROW_EXCEPTION("Unsupported dimension");
820 }
821 //if the hit not found let's see if it is too close to the segment's measurement
822 double deltaX = (testPosX - spPosX).mag();
823 if(deltaX < m_maxdYWindow){
824 usedHitMarker[lIdx][hIdx] += incr;
825 }
826 }
827 }
828 }
829 }
830}
831
832StatusCode NswSegmentFinderAlg::execute(const EventContext &ctx) const {
833 // read the inputs
834 const EtaHoughMaxContainer *maxima{nullptr};
835 ATH_CHECK(SG::get( maxima, m_etaKey, ctx));
836
837 const ActsTrk::GeometryContext *gctx{nullptr};
838 ATH_CHECK(SG::get(gctx, m_geoCtxKey, ctx));
839
840 // prepare our output collection
841 SG::WriteHandle writeSegments{m_writeSegmentKey, ctx};
842 ATH_CHECK(writeSegments.record(std::make_unique<SegmentContainer>()));
843
844 SG::WriteHandle writeSegmentSeeds{m_writeSegmentSeedKey, ctx};
845 ATH_CHECK(writeSegmentSeeds.record(std::make_unique<SegmentSeedContainer>()));
846
847 // we use the information from the previous eta-hough transform
848 // to get the combined hits that belong in the same maxima
849 for (const HoughMaximum *max : *maxima) {
850
851 auto [seeds, segments] = findSegmentsFromMaximum(*max, *gctx, ctx);
852
853 if (msgLvl(MSG::VERBOSE)) {
854 for(const auto& hitMax : max->getHitsInMax()){
855 ATH_MSG_VERBOSE("Hit "<<m_idHelperSvc->toString(hitMax->identify())<<", "
856 <<Amg::toString(hitMax->localPosition())<<", dir: "
857 <<Amg::toString(hitMax->sensorDirection()));
858 }
859 }
860
861 for(auto& seed: seeds){
862
863 if (msgLvl(MSG::VERBOSE)){
864 std::stringstream sstr{};
865 sstr<<"Seed tanBeta = "<<seed->tanBeta()<<", y0 = "<<seed->interceptY()
866 <<", tanAlpha = "<<seed->tanAlpha()<<", x0 = "<<seed->interceptX()<<", hits in the seed "
867 <<seed->getHitsInMax().size()<<std::endl;
868
869 for(const auto& hit : seed->getHitsInMax()){
870 sstr<<" *** Hit "<<m_idHelperSvc->toString(hit->identify())<<", "
871 << Amg::toString(hit->localPosition())<<", dir: "<<Amg::toString(hit->sensorDirection())<<std::endl;
872 }
873 ATH_MSG_VERBOSE(sstr.str());
874 }
875 if (m_visionTool.isEnabled()) {
876 m_visionTool->visualizeSeed(ctx, *seed, "#phi-combinatorialSeed");
877 }
878
879 writeSegmentSeeds->push_back(std::move(seed));
880
881 }
882
883 for (auto &seg : segments) {
884
885 const Parameters pars = localSegmentPars(*gctx, *seg);
886
887 ATH_MSG_VERBOSE("Segment parameters : "<<toString(pars));
888
889 if (m_visionTool.isEnabled()) {
890 m_visionTool->visualizeSegment(ctx, *seg, "#phi-segment");
891 }
892
893 writeSegments->push_back(std::move(seg));
894
895 }
896 }
897
898 return StatusCode::SUCCESS;
899}
900
902 if(m_seedCounter) {
903 m_seedCounter->printTableSeedStats(msgStream());
904 }
905 return StatusCode::SUCCESS;
906}
907
908void NswSegmentFinderAlg::SeedStatistics::addToStat(const MuonGMR4::SpectrometerSector* msSector, unsigned seeds, unsigned extSeeds, unsigned segments){
909 std::unique_lock guard{m_mutex};
910 SectorField key{};
911 key.chIdx = msSector->chamberIndex();
912 key.phi = msSector->stationPhi();
913 key.eta = msSector->chambers().front()->stationEta();
914
915 auto &entry = m_seedStat[key];
916 entry.nSeeds += seeds;
917 entry.nExtSeeds += extSeeds;
918 entry.nSegments += segments;
919}
920
922
923
924 std::stringstream sstr{};
925 sstr<<"Seed statistics per sector:"<<std::endl;
926 sstr<<"-----------------------------------------------------"<<std::endl;
927 sstr<<"| Chamber | Phi | Eta | Seeds | ExtSeeds | Segments |"<<std::endl;
928 sstr<<"-----------------------------------------------------"<<std::endl;
929
930 using namespace Muon::MuonStationIndex;
931
932 for (const auto& [sector, stats] : m_seedStat) {
933 sstr << "| " << std::setw(3) << chName(sector.chIdx)
934 << " | " << std::setw(2) << static_cast<unsigned>(sector.phi)
935 << " | " << std::setw(3) << static_cast<int>(sector.eta)
936 << " | " << std::setw(7) << stats.nSeeds
937 << " | " << std::setw(8) << stats.nExtSeeds
938 << " | " << std::setw(8) << stats.nSegments
939 << " |"<<std::endl;
940 }
941
942 sstr<<"------------------------------------------------------------"<<std::endl;
943 msg<<MSG::ALWAYS<<"\n"<<sstr.str()<<endmsg;
944 }
945
946
947} // 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].
MuonReadoutElement is an abstract class representing the geometry of a muon detector.
const Amg::Transform3D & localToGlobalTransform(const ActsTrk::GeometryContext &ctx) const
Returns the transformation from the local coordinate system of the readout element into the global AT...
const SpectrometerSector * msSector() const
Returns the pointer to the envelope volume enclosing all chambers in the sector.
A spectrometer sector forms the envelope of all chambers that are placed in the same MS sector & laye...
const Amg::Transform3D & localToGlobalTransform(const ActsTrk::GeometryContext &gctx) const
Returns the local -> global tarnsformation from the sector.
Amg::Transform3D globalToLocalTransform(const ActsTrk::GeometryContext &gctx) const
Returns the global -> local transformation from the ATLAS global.
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::pair< SegmentSeedVec_t, SegmentVec_t > findSegmentsFromMaximum(const HoughMaximum &max, const ActsTrk::GeometryContext &gctx, const EventContext &ctx) const
Find seed and segment from an eta hough maximum.
std::unique_ptr< SegmentSeed > constructCombinatorialSeed(const InitialSeed_t &initialSeed, const AmgSymMatrix(2)&bMatrix, const HoughMaximum &max, const HitLaySpan_t &extensionLayers, const UsedHitSpan_t &usedHits) const
Construct a combinatorial seed from the initial 4-layer seed hits.
std::unique_ptr< SegmentFit::SegmentLineFitter > m_lineFitter
std::pair< SegmentSeedVec_t, SegmentVec_t > buildSegmentsFromMM(const EventContext &ctx, const ActsTrk::GeometryContext &gctx, const HitLayVec &hitLayers, const HoughMaximum &max, const Amg::Vector3D &beamSpotPos, UsedHitMarker_t &usedHits, bool useOnlyMM) const
Build the final segment seed from strip like measurements using the combinatorial seeding for MicroMe...
UnsignedIntegerProperty m_maxClustersInLayer
virtual StatusCode initialize() override
virtual StatusCode execute(const EventContext &ctx) const override
std::pair< SegmentSeedVec_t, SegmentVec_t > buildSegmentsFromSTGC(const EventContext &ctx, const ActsTrk::GeometryContext &gctx, const HitLayVec &hitLayers, const HoughMaximum &max, const Amg::Vector3D &beamSpotPos, UsedHitMarker_t &usedHits) const
Build the segment for a seed from STGC 2D measurement layers directly and then attempt to append hits...
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.
std::unique_ptr< Segment > fitSegmentSeed(const EventContext &ctx, const ActsTrk::GeometryContext &gctx, const SegmentSeed *patternSeed) const
Fit the segment seeds.
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 initial seed.
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.
std::vector< std::unique_ptr< SegmentSeed > > SegmentSeedVec_t
Abbrivation of the seed vector.
void constructPreliminarySeeds(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.
void processSegment(std::unique_ptr< Segment > segment, const HitVec &seedHits, const HitLayVec &hitLayers, UsedHitMarker_t &usedHits, SegmentVec_t &segments) const
Process the segment and mark the hits if it is successfully built or not by differently mark the hits...
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)
std::vector< std::unique_ptr< Segment > > SegmentVec_t
Abbrivation of the final segment vector.
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::optional< double > intersect(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
Calculates the point B' along the line B that's closest to a second line A.
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, const bool useNDC=true)
Create a TLatex label,.
const std::string & chName(ChIndex index)
convert ChIndex into a string
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