22#include "Acts/Seeding/CombinatorialSeedSolver.hpp"
27using namespace Acts::Experimental::CombinatorialSeedSolver;
32 return prd->readoutElement()->stripLayer(prd->measurementHash()).design();
35 const auto*
re = prd->readoutElement();
36 switch(prd->channelType()) {
38 return re->stripDesign(prd->measurementHash());
40 return re->wireDesign(prd->measurementHash());
42 return re->padDesign(prd->measurementHash());
45 THROW_EXCEPTION(
"Invalid space point for design retrieval "<<
sp.msSector()->idHelperSvc()->toString(
sp.identify()));
48 const auto& design = getDesign(
sp);
51 return 0.5* design.stripLength(prd->channelNumber());
56 auto padCorners = padDesign.
padCorners(prd->channelNumber());
57 return 0.5* std::abs(padCorners[0].
x() - padCorners[1].
x());
59 return 0.5* design.stripLength(prd->channelNumber());
64 inline std::string sTgcChannelType(
const int chType) {
71 double minPull{std::numeric_limits<float>::max()};
72 const MuonR4::SpacePoint* spacePoint{
nullptr};
94 ATH_MSG_ERROR(
"MM or STGC not part of initialized detector layout");
95 return StatusCode::FAILURE;
101 fitCfg.calcAlongStrip =
false;
104 fitCfg.parsToUse = {ParamDefs::x0, ParamDefs::y0, ParamDefs::theta, ParamDefs::phi};
106 m_lineFitter = std::make_unique<SegmentFit::SegmentLineFitter>(name(), std::move(fitCfg));
109 m_ambiSolver = std::make_unique<SegmentAmbiSolver>(name(), std::move(ambicfg));
113 m_seedCounter = std::make_unique<SeedStatistics>();
116 return StatusCode::SUCCESS;
122 for (std::size_t l = 0; l < sortedSp.size(); ++l) {
123 emptyKeeper[l].resize(sortedSp[l].
size(), 0);
132 const auto& design = getDesign(
sp);
133 if (!design.hasStereoAngle()) {
139 if (
sp.dimension() == 2) {
155 const Amg::Vector3D estPlaneArrivalUp = SeedingAux::extrapolateToPlane(beamSpotPos, dirEstUp, testHit);
156 const Amg::Vector3D estPlaneArrivalDn = SeedingAux::extrapolateToPlane(beamSpotPos, dirEstDn, testHit);
158 bool below{
true}, above{
true};
163 const double halfLength = 0.5* stripHalfLength(testHit);
169 below = estPlaneArrivalDn.y() > std::max(leftEdge.y(), rightEdge.y());
171 above = estPlaneArrivalUp.y() < std::min(leftEdge.y(), rightEdge.y());
177 below = estPlaneArrivalDn.y() > hY;
179 above = estPlaneArrivalUp.y() < hY;
191 << (below || above ?
" is outside the window" :
" is inside the window"));
202#define TEST_HIT_CORRIDOR(LAYER, HIT_ITER, START_LAYER) \
204 const SpacePoint* testMe = combinatoricLayers[LAYER].get()[HIT_ITER]; \
205 if (usedHits[LAYER].get()[HIT_ITER] > m_maxUsed) { \
206 ATH_MSG_VERBOSE(__func__<<":"<<__LINE__<<" - " \
207 <<m_idHelperSvc->toString(testMe->identify()) \
208 <<" already used in good seed." ); \
211 const HitWindow inWindow = hitFromIPCorridor(*testMe, beamSpot, dirEstUp, dirEstDn); \
212 if(inWindow == HitWindow::tooHigh) { \
213 ATH_MSG_VERBOSE(__func__<<":"<<__LINE__<<" - Hit " \
214 <<m_idHelperSvc->toString(testMe->identify()) \
215 <<" is beyond the corridor. Break loop"); \
217 } else if (inWindow == HitWindow::tooLow) { \
218 START_LAYER = HIT_ITER + 1; \
219 ATH_MSG_VERBOSE(__func__<<":"<<__LINE__<<" - Hit " \
220 <<m_idHelperSvc->toString(testMe->identify()) \
221 <<" is still below the corridor. Update start to " \
232 seedHitsFromLayers.clear();
233 std::size_t maxSize{1};
234 for (
const HitVec& hitVec : combinatoricLayers) {
235 maxSize = maxSize * hitVec.size();
237 seedHitsFromLayers.reserve(maxSize);
239 unsigned iterLay0{0}, iterLay1{0}, iterLay2{0}, iterLay3{0};
240 unsigned startLay1{0}, startLay2{0}, startLay3{0};
242 for( ; iterLay0 < combinatoricLayers[0].get().
size() ; ++iterLay0){
247 const SpacePoint* hit0 = combinatoricLayers[0].get()[iterLay0];
256 <<
", seed plane: "<<
Amg::toString(SeedingAux::extrapolateToPlane(beamSpot, initSeedDir, *hit0)));
258 for( iterLay1 = startLay1; iterLay1 < combinatoricLayers[1].get().
size() ; ++iterLay1){
260 for( iterLay2 = startLay2; iterLay2 < combinatoricLayers[2].get().
size() ; ++iterLay2){
262 for( iterLay3 = startLay3; iterLay3 < combinatoricLayers[3].get().
size(); ++iterLay3){
264 seedHitsFromLayers.emplace_back(std::array{hit0, combinatoricLayers[1].get()[iterLay1],
265 combinatoricLayers[2].get()[iterLay2],
266 combinatoricLayers[3].get()[iterLay3]});
272#undef TEST_HIT_CORRIDOR
283 for (std::size_t i = 0; i < extensionLayers.size(); ++i) {
284 const HitVec& layer{extensionLayers[i].get()};
285 const Amg::Vector3D extrapPos = SeedingAux::extrapolateToPlane(startPos, direction, *layer.front());
288 unsigned triedHit{0};
289 HitCandidate precisionHit, noPrecisionHit;
292 for (
unsigned j = 0; j < layer.size(); ++j) {
294 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Hit " << (*layer[j])<<
" already used with counter " << usedHits[i].
get().at(j) <<
". Skip.");
297 auto hit = layer.at(j);
298 const double pull = std::sqrt(SeedingAux::chi2Term(extrapPos, direction, *
hit));
299 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Trying extension with hit " << *
hit<<
" and pull "<<pull<<
" has truth: "<< (
getTruthMatchedHit(*
hit->primaryMeasurement()) !=
nullptr ?
"oui" :
"non"));
301 double minPull = isPrecision ? precisionHit.minPull : noPrecisionHit.minPull;
304 if (pull > minPull) {
314 precisionHit.spacePoint =
hit;
315 precisionHit.minPull = pull;
319 noPrecisionHit.spacePoint =
hit;
320 noPrecisionHit.minPull = pull;
327 bestCand = precisionHit.spacePoint;
329 bestCand = noPrecisionHit.spacePoint;
337 combinatoricHits.push_back(bestCand);
340 return combinatoricHits;
343std::unique_ptr<SegmentSeed>
349 bool allValid = std::any_of(initialSeed.begin(), initialSeed.end(),
350 [
this](
const auto&
hit){
351 if (hit->type() == xAOD::UncalibMeasType::MMClusterType) {
352 const auto* mmClust = static_cast<const xAOD::MMCluster*>(hit->primaryMeasurement());
353 return mmClust->stripNumbers().size() >= m_minClusSize;
359 ATH_MSG_VERBOSE(
"Seed rejection: Not all clusters meet minimum strip size");
364 std::array<double, 4> params = defineParameters(bMatrix, initialSeed);
366 const auto [segPos, direction] = seedSolution(initialSeed, params);
370 for (std::size_t i = 0; i < 4; ++i) {
371 const double halfLength = stripHalfLength(*initialSeed[i]);
373 if (std::abs(params[i]) > halfLength) {
374 ATH_MSG_VERBOSE(
"Seed Rejection: Invalid seed - outside of the strip's length "<< m_idHelperSvc->toString(initialSeed[i]->identify())
375 <<
", param: "<<params[i]<<
", halfLength: "<<halfLength);
382 double interceptX = segPos.x();
383 double interceptY = segPos.y();
386 if(std::abs(tanAlpha) > m_maxTanAlpha){
387 ATH_MSG_VERBOSE(
"Seed Rejection: Invalid seed - tanAlpha "<<tanAlpha<<
" above threshold "<<m_maxTanAlpha);
393 auto extendedHits = extendHits(segPos, direction, extensionLayers, usedHits);
394 HitVec hits{initialSeed.begin(),initialSeed.end()};
395 std::ranges::move(extendedHits, std::back_inserter(hits));
397 return std::make_unique<SegmentSeed>(tanBeta, interceptY, tanAlpha,
398 interceptX,
hits.size(),
399 std::move(hits),
max.parentBucket());
408 ATH_MSG_VERBOSE(
"Not enough hits in the SegmentSeed to fit a segment");
413 if (
msgLvl(MSG::VERBOSE)) {
414 std::stringstream hitStream{};
416 hitStream<<
"**** "<< (*hit)<<std::endl;
418 ATH_MSG_VERBOSE(__func__<<
"() - "<<__LINE__ <<
": Uncalibrated space points for the segment fit: "<<std::endl
430 locToGlob, std::move(calibratedHits));
451 << segment->measurements().size()
452 <<
" hits, chi2/ndof: "
453 << segment->chi2() / std::max(1u,segment->nDoF()));
456 segMeasSP.reserve(segment->measurements().size());
458 std::ranges::transform(
459 segment->measurements(),
460 std::back_inserter(segMeasSP),
461 [](
const auto& m) { return m->spacePoint(); }
467 segments.push_back(std::move(segment));
474 if(segmentCandidates.size()<=1){
479 ATH_MSG_VERBOSE(
"Resolving ambiguities for "<<segmentCandidates.size()<<
" segments");
485 for (std::unique_ptr<Segment>& seg : segmentCandidates) {
487 segmentsPerChamber[chamb].push_back(std::move(seg));
489 segmentCandidates.clear();
490 for (
auto& [chamber, resolveMe] : segmentsPerChamber) {
492 segmentCandidates.insert(segmentCandidates.end(),
493 std::make_move_iterator(resolvedSegments.begin()),
494 std::make_move_iterator(resolvedSegments.end()));
499std::pair<NswSegmentFinderAlg::SegmentSeedVec_t, NswSegmentFinderAlg::SegmentVec_t>
511 std::size_t layerSize = hitLayers.size();
515 auto isUnusedCombined = [&](std::size_t layIdx, std::size_t hitIdx) ->
bool {
518 THROW_EXCEPTION(
"Space point is not of sTgc type: "<<
sp->msSector()->idHelperSvc()->toString(
sp->identify()));
520 if(
sp->dimension() != 2){
533 return isPrecision && usedHits[layIdx].at(hitIdx) <=
m_maxUsed;
538 for(std::size_t layIdx1 = 0; layIdx1 < 2; ++layIdx1){
539 for(std::size_t layIdx2 = layerSize-1; layIdx2 >= layerSize-2; --layIdx2){
543 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
"Outermost layers are MM - stop searching for sTgc Measurements");
544 return std::make_pair(std::move(seeds), std::move(segments));
548 for(std::size_t hitIdx1 = 0; hitIdx1 < hitLayers[layIdx1].size(); ++hitIdx1) {
549 const SpacePoint* hit1 = hitLayers[layIdx1][hitIdx1];
550 if(!isUnusedCombined(layIdx1, hitIdx1)){
553 for(std::size_t hitIdx2 = 0; hitIdx2 < hitLayers[layIdx2].size(); ++hitIdx2) {
554 const SpacePoint* hit2 = hitLayers[layIdx2][hitIdx2];
555 if(!isUnusedCombined(layIdx2, hitIdx2)){
561 const double cosAngle = beamSpotHitDir.dot(seedDir);
563 if(std::abs(cosAngle) < thetaWindowCut){
567 HitVec seedHits{hit1, hit2};
568 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
"Attempt for STGC segment starting with the hits: " << *hit1 <<
", " << *hit2);
576 extensionLayers.reserve(hitLayers.size());
577 usedExtensionHits.reserve(hitLayers.size());
578 for (std::size_t e = 0 ; e < hitLayers.size(); ++e) {
579 if (!(e == layIdx1 || e == layIdx2)){
580 extensionLayers.emplace_back(hitLayers[e]);
581 usedExtensionHits.emplace_back(usedHits[e]);
584 auto extendedHits =
extendHits(seedPosZ0, seedDir, extensionLayers, usedExtensionHits);
585 std::ranges::move(extendedHits, std::back_inserter(seedHits));
588 auto seed = std::make_unique<SegmentSeed>(
houghTanBeta(seedDir), seedPosZ0.y(),
590 seedHits.size(), std::move(seedHits),
595 seeds.push_back(std::move(seed));
599 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Start to fit an STGC segment seed with "<<seed->getHitsInMax().size()<<
" hits \n"<<
print(seed->getHitsInMax()));
600 std::unique_ptr<Segment> segment =
fitSegmentSeed(ctx, gctx, seed.get());
601 processSegment(std::move(segment), seed->getHitsInMax(), hitLayers, usedHits, segments);
602 seeds.push_back(std::move(seed));
608 return std::make_pair(std::move(seeds),std::move(segments));
611std::pair<NswSegmentFinderAlg::SegmentSeedVec_t, NswSegmentFinderAlg::SegmentVec_t>
618 bool useOnlyMM)
const {
623 std::size_t layerSize = hitLayers.size();
627 return {std::move(seeds), std::move(segments)};
631 auto unusedStripHit = [&](
const HitVec& layerHits,
unsigned int layIdx) ->
const SpacePoint* {
634 for (
auto [idx,
hit] : Acts::enumerate(layerHits)) {
637 bool isUnused = usedHits[layIdx].at(idx) <=
m_maxUsed;
638 if (isStrip && isUnused && isMM) {
645 std::array<const SpacePoint*, 4> seedHits{};
648 for (std::size_t i = 0; i < layerSize - 3; ++i) {
649 seedHits[0] = unusedStripHit(hitLayers[i], i);
653 for (std::size_t j = i + 1; j < layerSize - 2; ++j) {
654 seedHits[1] = unusedStripHit(hitLayers[j], j);
658 for (std::size_t l = layerSize - 1; l > j+1; --l) {
659 seedHits[3] = unusedStripHit(hitLayers[l], l);
663 for (std::size_t k = l-1; k > j ; --k) {
664 seedHits[2] = unusedStripHit(hitLayers[k], k);
669 const HitLaySpan_t layers{hitLayers[i], hitLayers[j], hitLayers[k], hitLayers[l]};
671 bool tooBusy = std::ranges::any_of(layers,
672 [
this](
const auto& layer) {
681 if (std::abs(bMatrix.determinant()) < 1.e-6) {
685 <<(*seedHits[0]) <<
",\n"
686 <<(*seedHits[1]) <<
",\n"
687 <<(*seedHits[2]) <<
",\n"
691 UsedHitSpan_t usedHitsSpan{usedHits[i], usedHits[j], usedHits[k], usedHits[l]};
698 usedExtensionHits.reserve(hitLayers.size());
699 extensionLayers.reserve(hitLayers.size());
700 for (std::size_t e = 0 ; e < hitLayers.size(); ++e) {
701 if (!(e == i || e == j || e == k || e == l)){
702 extensionLayers.emplace_back(hitLayers[e]);
703 usedExtensionHits.emplace_back(usedHits[e]);
708 for (
auto &combinatoricHits : preLimSeeds) {
714 seeds.push_back(std::move(seed));
717 std::unique_ptr<Segment> segment =
fitSegmentSeed(ctx, gctx, seed.get());
718 processSegment(std::move(segment), seed->getHitsInMax(), hitLayers, usedHits, segments);
719 seeds.push_back(std::move(seed));
726 return std::make_pair(std::move(seeds),std::move(segments));
729std::pair<NswSegmentFinderAlg::SegmentSeedVec_t, NswSegmentFinderAlg::SegmentVec_t>
732 const EventContext& ctx)
const {
737 const std::size_t layerSize = stripHitsLayers.size();
748 return std::make_pair(std::move(seeds),std::move(segments));
753 constexpr double legX{0.2};
755 primitives.push_back(
MuonValR4::drawLabel(
"TrueHits matched with reco houghmax hits", legX, legY, 8));
770 const double pull = std::sqrt(SeedingAux::chi2Term(hitPos, hitDir, *
sp));
773 const auto* mmClust =
static_cast<const xAOD::MMCluster*
>(
sp->primaryMeasurement());
775 const auto& design = mmEle->
stripLayer(mmClust->measurementHash()).
design();
776 std::string stereoDesign{!design.hasStereoAngle() ?
"X" : design.stereoAngle() >0 ?
"U":
"V"};
777 primitives.push_back(
MuonValR4::drawLabel(std::format(
"ml: {:1d}, gap: {:1d}, {:}, pull: {:.2f}",
779 stereoDesign, pull), legX, legY, 8));
782 std::string channelString =
sp->secondaryMeasurement() ==
nullptr ?
783 sTgcChannelType(sTgcMeas->channelType()) :
784 std::format(
"{:}/{:}", sTgcChannelType(sTgcMeas->channelType()),
786 primitives.push_back(
MuonValR4::drawLabel(std::format(
"ml: {:1d}, gap: {:1d}, type: {:}, pull: {:.2f}",
787 sTgcMeas->readoutElement()->multilayer(), sTgcMeas->gasGap(),
788 channelString, pull), legX, legY, 8));
793 "bucket", std::move(primitives));
798 Acts::ObjVisualization3D visualHelper{};
806 visualHelper.write(std::format(
"Event_{:}_{:}_spacepoints_truth.obj", ctx.eventID().event_number(),
max.getHitsInMax().front()->chamber()->identString()));
811 std::size_t nSeeds{0}, nExtSeeds{0}, nSegments{0};
815 auto processSeedsAndSegments = [&](std::pair<SegmentSeedVec_t, SegmentVec_t>&& seedSegmentPairs, std::string_view source) {
816 auto& [returnSeeds, returnSegments] = seedSegmentPairs;
817 ATH_MSG_DEBUG(
"From " << source <<
": built " << returnSeeds.size() <<
" seeds and " << returnSegments.size() <<
" segments.");
818 for(
auto& seed : returnSeeds) {
820 Acts::ObjVisualization3D visualHelper{};
822 ATH_MSG_VERBOSE(
"Seed with "<< seed->getHitsInMax().size() <<
" hits rejected");
823 for(
const auto&
hit : seed->getHitsInMax()){
833 visualHelper.write(std::format(
"Event_{:}_{:}_notExtendedSeed.obj", ctx.eventID().event_number(), seed->getHitsInMax().front()->chamber()->identString()));
838 seeds.push_back(std::move(seed));
841 std::ranges::move(returnSegments, std::back_inserter(segments));
842 nSegments += returnSegments.size();
847 processSeedsAndSegments(
buildSegmentsFromSTGC(ctx, gctx, stripHitsLayers,
max, globToLocal.translation(), allUsedHits),
"sTgc segment seeds");
852 ATH_MSG_VERBOSE(
"Start building combinatoric seeds only from Micromegas");
853 processSeedsAndSegments(
buildSegmentsFromMM(ctx, gctx, stripHitsLayers,
max, globToLocal.translation(), allUsedHits,
true),
"MM combinatoric segment seeds");
857 ATH_MSG_VERBOSE(
"Start building combinatoric seeds from Micromegas and sTgc hits");
858 processSeedsAndSegments(
buildSegmentsFromMM(ctx, gctx, stripHitsLayers,
max, globToLocal.translation(), allUsedHits,
true),
"MM combinatoric segment seeds");
859 processSeedsAndSegments(
buildSegmentsFromMM(ctx, gctx, stripHitsLayers,
max, globToLocal.translation(), allUsedHits,
false),
"MM and STGC combinatoric segment seeds");
864 m_seedCounter->addToStat(
max.msSector(), nSeeds, nExtSeeds, nSegments);
867 return std::make_pair(std::move(seeds),std::move(segments));
874 bool markNeighborHits)
const {
878 for(
const auto&
sp : spacePoints){
888 switch (
sp->primaryMeasurement()->numDimensions()) {
890 spPosX[
Amg::x] =
sp->primaryMeasurement()->localPosition<1>().
x();
893 spPosX = xAOD::toEigen(
sp->primaryMeasurement()->localPosition<2>());
899 for (std::size_t lIdx = 0; lIdx < allSortHits.size(); ++lIdx) {
900 const HitVec& hVec{allSortHits[lIdx]};
903 if(hitLayer != measLayer) {
904 ATH_MSG_VERBOSE(
"Not in the same layer since measLayer = "<< measLayer <<
" and "<<hitLayer);
907 for (std::size_t hIdx = 0 ; hIdx < hVec.size(); ++hIdx) {
909 auto testHit = hVec[hIdx];
911 usedHitMarker[lIdx][hIdx] += incr;
912 if(!markNeighborHits){
915 }
else if (markNeighborHits) {
918 switch (testHit->primaryMeasurement()->numDimensions()) {
920 testPosX[
Amg::x] = testHit->primaryMeasurement()->localPosition<1>().
x();
923 testPosX = xAOD::toEigen(testHit->primaryMeasurement()->localPosition<2>());
929 double deltaX = (testPosX - spPosX).
mag();
931 usedHitMarker[lIdx][hIdx] += incr;
934 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
"- Marking hit "<<(*testHit)<<
", used count: "
935 <<usedHitMarker[lIdx][hIdx]);
954 ATH_CHECK(writeSegmentSeeds.
record(std::make_unique<SegmentSeedContainer>()));
962 if (
msgLvl(MSG::VERBOSE)) {
964 for(
const auto& hitMax :
max->getHitsInMax()){
971 for(
auto& seed: seeds){
973 if (
msgLvl(MSG::VERBOSE)){
974 std::stringstream sstr{};
975 sstr<<
"Seed tanBeta = "<<seed->tanBeta()<<
", y0 = "<<seed->interceptY()
976 <<
", tanAlpha = "<<seed->tanAlpha()<<
", x0 = "<<seed->interceptX()<<
", hits in the seed "
977 <<seed->getHitsInMax().size()<<std::endl;
979 for(
const auto&
hit : seed->getHitsInMax()){
986 m_visionTool->visualizeSeed(ctx, *seed,
"#phi-combinatorialSeed");
989 writeSegmentSeeds->push_back(std::move(seed));
994 ATH_MSG_VERBOSE(
"Before ambiguity resolution, there are in total "<<segments.size()<<
" segments:");
995 for(
const auto& seg : segments){
998 std::stringstream sstr{};
999 sstr<<
"Segment chi2/ndof = "<<seg->chi2()/std::max(1u,seg->nDoF())<<
", hits in the segment "
1000 <<seg->measurements().size()<<std::endl;
1003 sstr<<
"Segment parameters : "<<
toString(pars)<<std::endl;
1004 for(
const auto&
hit : seg->measurements()){
1005 bool hasTruth{
false};
1008 std::string
type =
hit->fitState() != CalibratedSpacePoint::State::Valid ?
"outlier" :
"valid";
1010 sstr<<
" *** Hit "<<
m_idHelperSvc->toString(
hit->spacePoint()->identify())<<
", "
1013 <<
Amg::toString(
hit->spacePoint()->sensorDirection())<<
", has truth matched: "<<hasTruth<<std::endl;
1024 ATH_MSG_VERBOSE(
"After ambiguity resolution, there are in total "<<segments.size()<<
" segments:");
1026 for (
auto &seg : segments) {
1027 if(
msgLvl(MSG::VERBOSE)){
1028 std::stringstream sstr{};
1029 sstr<<
"Segment chi2/ndof = "<<seg->chi2()/std::max(1u,seg->nDoF())<<
", hits in the segment "
1030 <<seg->measurements().size()<<std::endl;
1032 sstr<<
"Segment parameters : "<<
toString(pars)<<std::endl;
1034 for(
const auto&
hit : seg->measurements()){
1035 bool hasTruth{
false};
1038 std::string
type =
hit->fitState() != CalibratedSpacePoint::State::Valid ?
"outlier" :
"valid";
1039 sstr<<
" *** Hit "<<
m_idHelperSvc->toString(
hit->spacePoint()->identify())<<
", "
1042 <<
Amg::toString(
hit->spacePoint()->sensorDirection())<<
", has truth matched: "<<hasTruth<<std::endl;
1050 m_visionTool->visualizeSegment(ctx, *seg,
"#phi-segment");
1054 Acts::ObjVisualization3D visualHelper{};
1057 visualHelper.write(std::format(
"Event_{:}_segment_{:}.obj", ctx.eventID().event_number(), seg->msSector()->identString()));
1060 writeSegments->push_back(std::move(seg));
1067 return StatusCode::SUCCESS;
1072 m_seedCounter->printTableSeedStats(msgStream());
1074 return StatusCode::SUCCESS;
1078 std::unique_lock guard{
m_mutex};
1082 key.eta = msSector->
chambers().front()->stationEta();
1085 entry.nSeeds += seeds;
1086 entry.nExtSeeds += extSeeds;
1087 entry.nSegments += segments;
1093 std::stringstream sstr{};
1094 sstr<<
"Seed statistics per sector:"<<std::endl;
1095 sstr<<
"-----------------------------------------------------"<<std::endl;
1096 sstr<<
"| Chamber | Phi | Eta | Seeds | ExtSeeds | FittedSegments |"<<std::endl;
1097 sstr<<
"-----------------------------------------------------"<<std::endl;
1101 for (
const auto& [sector, stats] :
m_seedStat) {
1102 sstr <<
"| " << std::setw(3) <<
chName(sector.chIdx)
1103 <<
" | " << std::setw(2) <<
static_cast<unsigned>(sector.phi)
1104 <<
" | " << std::setw(3) <<
static_cast<int>(sector.eta)
1105 <<
" | " << std::setw(7) << stats.nSeeds
1106 <<
" | " << std::setw(8) << stats.nExtSeeds
1107 <<
" | " << std::setw(8) << stats.nSegments
1111 sstr<<
"------------------------------------------------------------"<<std::endl;
1112 msg<<MSG::ALWAYS<<
"\n"<<sstr.str()<<
endmsg;
Scalar mag() const
mag method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define AmgSymMatrix(dim)
ATLAS-specific HepMC functions.
sTgcIdHelper::sTgcChannelTypes chType
#define TEST_HIT_CORRIDOR(LAYER, HIT_ITER, START_LAYER)
Macro to check whether a hit is compatible with the hit corridor.
size_t size() const
Number of registered mappings.
struct TBPatternUnitContext Unknown
Acts::GeometryContext context() const
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 SpectrometerSector * msSector() const
Returns the pointer to the envelope volume enclosing all chambers in the sector.
const Amg::Transform3D & localToGlobalTransform(const ActsTrk::GeometryContext &ctx) const override final
Returns the transformation from the local coordinate system of the readout element into the global AT...
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
SeedStatistic_T m_seedStat
void printTableSeedStats(MsgStream &msg) const
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.
void resolveAmbiguities(const ActsTrk::GeometryContext &gctx, SegmentVec_t &segmentCandidates) const
Resolve the ambiguities of the segments per chamber and return the surviving segments.
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
DoubleProperty m_minPullThreshold
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.
DoubleProperty m_maxdYWindow
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
DoubleProperty m_windowTheta
BooleanProperty m_dumpSeedStatistics
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
SpacePointPerLayerSplitter::HitLayVec HitLayVec
SpacePointPerLayerSplitter::HitVec HitVec
std::vector< InitialSeed_t > InitialSeedVec_t
Vector of initial seeds.
BooleanProperty m_doOnlyMMCombinatorics
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.
@ C
Single phi measurements.
@ 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
ActsTrk::GeoContextReadKey_t m_geoCtxKey
std::vector< std::vector< unsigned int > > UsedHitMarker_t
Abbrivation of the container book keeping whether a hit is used or not.
BooleanProperty m_dumpObj
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::unique_ptr< SegmentFit::SegmentAmbiSolver > m_ambiSolver
std::vector< std::reference_wrapper< std::vector< unsigned int > > > UsedHitSpan_t
Abbrivation of the container to pass a subset of markers wtihout copy.
BooleanProperty m_markHitsFromSeed
Representation of a segment seed (a fully processed hough maximum) produced by the hough transform.
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 Amg::Vector3D & sensorDirection() const
const Identifier & identify() const
: Identifier of the primary measurement
const Amg::Vector3D & localPosition() const
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?)
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
double houghTanBeta(const Amg::Vector3D &v)
Returns the hough tanBeta [y] / [z].
DataVector< HoughMaximum > EtaHoughMaxContainer
const xAOD::MuonSimHit * getTruthMatchedHit(const xAOD::MuonMeasurement &prdHit)
Returns the MuonSimHit, if there's any, matched to the uncalibrated muon measurement.
constexpr unsigned minLayers
bool isPrecisionHit(const SpacePoint &hit)
Returns whether the uncalibrated spacepoint is a precision hit (Mdt, micromegas, stgc strips).
SpacePointPerLayerSplitter::HitVec HitVec
std::string print(const cont_t &container)
Print a space point container to string.
double houghTanAlpha(const Amg::Vector3D &v)
: Returns the hough tanAlpha [x] / [z]
void drawSegmentMeasurements(const Acts::GeometryContext &tgContext, const xAOD::MuonSegment &segment, Acts::ObjVisualization3D &visualHelper, const Acts::ViewConfig &viewConfig=Acts::s_viewSensitive)
Draw all uncalibrated measurements associated to the segment.
std::unique_ptr< TLatex > drawLabel(const std::string &text, const double xPos, const double yPos, const double textSize=18, const bool useNDC=true, const int color=kBlack)
Create a TLatex label,.
void drawSegmentLine(const Acts::GeometryContext &tgContext, const xAOD::MuonSegment &segment, Acts::ObjVisualization3D &visualHelper, const Acts::ViewConfig &viewConfig=Acts::s_viewLine, const double standardLength=1.*Gaudi::Units::m)
Draw a segment line inside the obj file.
void drawSpacePoint(const Acts::GeometryContext &tgContext, const MuonR4::SpacePoint &spacePoint, Acts::ObjVisualization3D &visualHelper, const Acts::ViewConfig &viewConfig=Acts::s_viewSensitive)
Draw an uncalibrated space point inside the obj file.
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.
sTgcMeasurement_v1 sTgcMeasurement
Helper struct to ensure that the spectrometer sectors & chambers are sorted.
sector's field to dump the seed statistics
Configuration object to stree the ambiguties.
const ISpacePointCalibrator * calibrator
Pointer to the calibrator.
const Muon::IMuonIdHelperSvc * idHelperSvc
Pointer to the idHelperSvc.
const MuonValR4::IPatternVisualizationTool * visionTool
Pointer to the visualization tool.
double recoveryPull
Maximum pull on a measurement to add it back on the line.
Full configuration object.
#define THROW_EXCEPTION(MESSAGE)