ATLAS Offline Software
PhiHoughTransformAlg.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #include "PhiHoughTransformAlg.h"
6 
9 
11 
12 namespace {
13  void sortHits(std::vector<MuonR4::HoughHitType>& hits) {
14  std::ranges::sort(hits,
15  [](const MuonR4::HoughHitType&a, const MuonR4::HoughHitType& b){
16  const Amg::Vector3D& hitA{a->positionInChamber()};
17  const Amg::Vector3D& hitB{b->positionInChamber()};
18  constexpr double layerTol = 1.*Gaudi::Units::mm;
19  if (std::abs(hitA.z() - hitB.z()) > layerTol) {
20  return hitA.z() < hitB.z();
21  }
22  return hitA.y() < hitB.y();
23  });
24  }
25 }
26 namespace MuonR4{
27 
29  ISvcLocator* pSvcLocator)
30  : AthReentrantAlgorithm(name, pSvcLocator) {}
31 
34  ATH_CHECK(m_maxima.initialize());
35  ATH_CHECK(m_segmentSeeds.initialize());
36 
37  return StatusCode::SUCCESS;
38 }
39 
40 template <class ContainerType>
42  const EventContext& ctx, const SG::ReadHandleKey<ContainerType>& key,
43  const ContainerType*& contToPush) const {
44  contToPush = nullptr;
45  if (key.empty()) {
46  ATH_MSG_VERBOSE("No key has been parsed for object "
47  << typeid(ContainerType).name());
48  return StatusCode::SUCCESS;
49  }
50  SG::ReadHandle<ContainerType> readHandle{key, ctx};
51  ATH_CHECK(readHandle.isPresent());
52  contToPush = readHandle.cptr();
53  return StatusCode::SUCCESS;
54 }
55 
57  HoughEventData& data) const {
58  HoughPlaneConfig cfg;
59  cfg.nBinsX = m_nBinsTanPhi;
60  cfg.nBinsY = m_nBinsIntercept;
61  // configure the peak finder for the phi-extension.
62  // Expect "shallow" maxima with 2-3 hits.
63  ActsPeakFinderForMuonCfg peakFinderCfg;
64  peakFinderCfg.fractionCutoff = 0.4;
65  peakFinderCfg.threshold = 2; // 2D spacepoints receive a weight of 2
66  peakFinderCfg.minSpacingBetweenPeaks = {0., 30.};
67  data.houghPlane = std::make_unique<HoughPlane>(cfg);
68  data.peakFinder = std::make_unique<ActsPeakFinderForMuon>(peakFinderCfg);
69 
70  return StatusCode::SUCCESS;
71 }
72 
74  const ActsPeakFinderForMuon::Maximum& phiMaximum,
75  const HoughMaximum& etaMaximum) const {
76  std::unordered_map<const xAOD::UncalibratedMeasurement*, bool> foundEtas;
77  // loop over the original eta maximum and check all hits measuring the eta-coordinate
78  for (auto& hit : etaMaximum.getHitsInMax()) {
79  if (hit->measuresEta() && hit->measuresPhi()) {
80  auto [iter, added] =
81  foundEtas.emplace(hit->primaryMeasurement(), false);
82  // test if the PRD for the eta-measurement appears on at least
83  // one space point of this phi extension.
84  // This will be done for all space points containing the eta-PRD
85  iter->second |= phiMaximum.hitIdentifiers.count(hit);
86  }
87  }
88  // count the number of eta PRD not compatible with this extension.
89  return std::count_if(
90  foundEtas.begin(), foundEtas.end(),
91  [](const std::pair<const xAOD::UncalibratedMeasurement*, bool>& p) {
92  return !p.second;
93  });
94 }
95 std::unique_ptr<SegmentSeed>
97  const ActsPeakFinderForMuon::Maximum & phiMax) const {
98  // book a new hit list
99  std::vector<HoughHitType> hitsOnMax;
100  // copy the pure eta hits onto the hit list
101  std::copy_if(etaMax.getHitsInMax().begin(), etaMax.getHitsInMax().end(), std::back_inserter(hitsOnMax), [](const HoughHitType &hit){
102  return (hit->measuresEta() && !hit->measuresPhi());
103  });
104  // and then add all hits (2D and pure phi) from the phi-extension to it
105  hitsOnMax.insert(hitsOnMax.end(), phiMax.hitIdentifiers.begin(), phiMax.hitIdentifiers.end());
106  // use this to construct the segment seed
107  sortHits(hitsOnMax);
108  return std::make_unique<SegmentSeed>(etaMax.tanTheta(), etaMax.interceptY(), phiMax.x, phiMax.y, hitsOnMax.size(), std::move(hitsOnMax), etaMax.parentBucket());
109 }
110 
112  const HoughMaximum & maximum,
113  HoughEventData& eventData) const{
114  // reset the event data
115  eventData.phiHitsOnMax = 0;
116  eventData.searchSpaceTanAngle = std::make_pair(1e10, -1e10);
117  eventData.searchSpaceIntercept = std::make_pair(1e10, -1e10);
118  // loop over the measurements on the maximum
119  for (auto hit : maximum.getHitsInMax()) {
120  // reject the pure eta measurements - not relevant here
121  if (!hit->measuresPhi())
122  continue;
123  // find the direction of the IP viewed from the chamber frame
124  Amg::Vector3D extrapDir = (hit->positionInChamber() - hit->chamber()->globalToLocalTrans(gctx).translation()).unit();
125  // express the x location of our phi hits on the chamber plane (z = 0) when projecting from the beam spot
126  std::optional<double> dummyIntercept = Amg::intersect<3>(hit->positionInChamber(),extrapDir,Amg::Vector3D::UnitZ(),0);
127  double x0 = (hit->positionInChamber() + dummyIntercept.value_or(0) * extrapDir).x();
128  // now we can obtain the most likely tan(phi) via the pointing vector from the origin to our hit
129  double tanPhi = extrapDir.x()/extrapDir.z();
130  // update our search space with this info
131  eventData.updateSearchWindow(eventData.searchSpaceTanAngle, tanPhi);
132  eventData.updateSearchWindow(eventData.searchSpaceIntercept, x0);
133  // and increment the hit counter
134  ++ eventData.phiHitsOnMax;
135  }
136  // now use the results from the individual hits to define an axis range adapted to the binning we desire
137  double chamberCenter = (eventData.searchSpaceIntercept.second + eventData.searchSpaceIntercept.first) * 0.5;
138  double searchStart = chamberCenter - 0.5 * eventData.houghPlane->nBinsY() * m_targetResoIntercept;
139  double searchEnd = chamberCenter + 0.5 * eventData.houghPlane->nBinsY() * m_targetResoIntercept;
140  // Protection for very wide buckets - if the search space does not cover all of the bucket, widen the bin size
141  // so that we cover everything
142  searchStart = std::min(searchStart, eventData.searchSpaceIntercept.first- m_minSigmasSearchIntercept * m_targetResoIntercept);
143  searchEnd = std::max(searchEnd, eventData.searchSpaceIntercept.second + m_minSigmasSearchIntercept * m_targetResoIntercept);
144  // also treat tan(phi)
145  double tanPhiMean = 0.5 * (eventData.searchSpaceTanAngle.first + eventData.searchSpaceTanAngle.second);
146  double searchStartTanPhi = tanPhiMean - 0.5 * eventData.houghPlane->nBinsX() * m_targetResoTanPhi;
147  double searchEndTanPhi = tanPhiMean + 0.5* eventData.houghPlane->nBinsX() * m_targetResoTanPhi;
148  searchStartTanPhi = std::min(searchStartTanPhi, eventData.searchSpaceTanAngle.first- m_minSigmasSearchTanPhi * m_targetResoTanPhi);
149  searchEndTanPhi = std::max(searchEndTanPhi, eventData.searchSpaceTanAngle.second + m_minSigmasSearchTanPhi * m_targetResoTanPhi);
150 
151  // and update the axis ranges for the search space according to our results
152  eventData.currAxisRanges =
153  Acts::HoughTransformUtils::HoughAxisRanges{searchStartTanPhi, searchEndTanPhi, searchStart, searchEnd};
154 
155  return StatusCode::SUCCESS;
156 }
157 
158 std::vector<ActsPeakFinderForMuon::Maximum> PhiHoughTransformAlg::findRankedSegmentSeeds (HoughEventData & eventData, const HoughMaximum & maximum) const{
159  std::map<int, std::vector<ActsPeakFinderForMuon::Maximum>> rankedSeeds;
160  using namespace std::placeholders;
161  // reset the accumulator
162  eventData.houghPlane->reset();
163  // fill the accumulator with the phi measurements
164  for (auto hit : maximum.getHitsInMax()){
165  if (!hit->measuresPhi())
166  continue;
167  eventData.houghPlane->fill<HoughHitType>(
168  hit, eventData.currAxisRanges,
170  std::bind(HoughHelpers::Phi::houghWidthStrip, _1, _2, m_targetResoIntercept), hit, 0,
171  // up-weigh 2D spacepoints w.r.t 1D phi hits to prevent
172  // discarding measurements known to be compatible in eta
173  (hit->measuresEta() ? 2.0 : 1.0) / (m_downWeightMultiplePrd? hit->nPhiInstanceCounts() : 1)
174  );
175  }
176  // run the peak finder
177  auto foundMaxPhi = eventData.peakFinder->findPeaks(
178  *(eventData.houghPlane), eventData.currAxisRanges);
179  // now rank the found peaks by the number of eta-compatible PRDs they would discard.
180  for (auto solution : foundMaxPhi) {
181  // for each solution, count how many eta PRDs would not be compatible with this phi extension.
182  // rank by the lowest number of such "holes".
183  rankedSeeds[countIncompatibleEtaHits(solution, maximum)].push_back(solution);
184  }
185  // return only the best solution(s)
186  auto best = rankedSeeds.begin();
187  // and apply the maximum hole cut.
188  if (best != rankedSeeds.end() && best->first <= m_maxEtaHolesOnMax){
189  return best->second;
190  }
191  return {};
192 }
193 std::unique_ptr<SegmentSeed>
195  // recovers cases of a single phi hit assuming a straight
196  // line extrapolation from the beam line to the phi measurement
197  std::vector<HoughHitType> hits{maximum.getHitsInMax()};
198  sortHits(hits);
199  return std::make_unique<SegmentSeed>(maximum.tanTheta(), maximum.interceptY(),
200  data.searchSpaceTanAngle.first,
201  data.searchSpaceIntercept.first,
202  maximum.getCounts(),
203  std::move(hits), maximum.parentBucket());
204 
205 }
206 
207 
208 StatusCode PhiHoughTransformAlg::execute(const EventContext& ctx) const {
209 
210  // read the inputs
211  const EtaHoughMaxContainer* maxima{nullptr};
212  ATH_CHECK(retrieveContainer(ctx, m_maxima, maxima));
213 
214  const ActsGeometryContext* gctx{nullptr};
216 
217  // book the event data object
218  HoughEventData eventData{};
219 
220  // prepare the accumulator
221  ATH_CHECK(prepareHoughPlane(eventData));
222 
223  // prepare our output collection
225  ATH_CHECK(writeMaxima.record(std::make_unique<SegmentSeedContainer>()));
226 
227  // loop over the previously found eta-maxima for each station
228  for (const HoughMaximum* max : *maxima) {
229  // for each maximum, pre-process
230  ATH_CHECK(preProcessMaximum(*gctx, *max, eventData));
231  bool foundSolution=false;
232  // if we have enough hits, run a phi transform
233  if (eventData.phiHitsOnMax > 1){
234  std::vector<ActsPeakFinderForMuon::Maximum> rankedSeeds = findRankedSegmentSeeds(eventData, *max);
235  for (auto & phiSolution : rankedSeeds){
236  foundSolution = true;
237  writeMaxima->push_back(buildSegmentSeed(*max, phiSolution));
238  }
239  }
240  // if we do not have at least two phi-hits for a proper transform:
241  if (!foundSolution){
242  // if we have a single phi hit, we can approximate the phi
243  // solution using the beam spot (as the IP is far).
244  // This is steered by a flag, and not appropriate for splashes
245  // or cosmics.
246  if (m_recoverSinglePhiWithBS && eventData.phiHitsOnMax == 1){
247  writeMaxima->push_back(recoverSinglePhiMax(eventData,*max));
248  }
249  // otherwise we have no phi-solution, and we fall back to writing a 1D eta-maximum
250  else{
251  writeMaxima->push_back(std::make_unique<SegmentSeed>(*max));
252  }
253  }
254  }
255  // add the maxima for this station to the output
256 
257  return StatusCode::SUCCESS;
258 }
259 }
MuonR4::PhiHoughTransformAlg::m_segmentSeeds
SG::WriteHandleKey< SegmentSeedContainer > m_segmentSeeds
Definition: PhiHoughTransformAlg.h:99
MuonR4::PhiHoughTransformAlg::buildSegmentSeed
std::unique_ptr< SegmentSeed > buildSegmentSeed(const HoughMaximum &etaMax, const MuonR4::ActsPeakFinderForMuon::Maximum &phiMax) const
constructs a segment seed from an eta maximum and a phi-extension.
Definition: PhiHoughTransformAlg.cxx:96
MuonR4::PhiHoughTransformAlg::PhiHoughTransformAlg
PhiHoughTransformAlg(const std::string &name, ISvcLocator *pSvcLocator)
Definition: PhiHoughTransformAlg.cxx:28
data
char data[hepevt_bytes_allocation_ATLAS]
Definition: HepEvt.cxx:11
MuonR4::PhiHoughTransformAlg::initialize
virtual StatusCode initialize() override
Definition: PhiHoughTransformAlg.cxx:32
MuonR4::HoughMaximum::tanTheta
double tanTheta() const
getter
Definition: HoughMaximum.h:36
TRTCalib_Extractor.hits
hits
Definition: TRTCalib_Extractor.py:35
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
max
#define max(a, b)
Definition: cfImp.cxx:41
MuonR4::PhiHoughTransformAlg::m_targetResoIntercept
DoubleProperty m_targetResoIntercept
Definition: PhiHoughTransformAlg.h:107
MuonR4::HoughEventData_impl::peakFinder
std::unique_ptr< peakFinder_t > peakFinder
Definition: HoughEventData.h:37
MuonR4::HoughEventData_impl::phiHitsOnMax
size_t phiHitsOnMax
Definition: HoughEventData.h:67
MuonR4::HoughEventData_impl::searchSpaceTanAngle
std::pair< double, double > searchSpaceTanAngle
Definition: HoughEventData.h:65
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:70
MuonR4::PhiHoughTransformAlg::m_geoCtxKey
SG::ReadHandleKey< ActsGeometryContext > m_geoCtxKey
Definition: PhiHoughTransformAlg.h:102
MuonR4::PhiHoughTransformAlg::m_targetResoTanPhi
DoubleProperty m_targetResoTanPhi
Definition: PhiHoughTransformAlg.h:105
MuonR4::PhiHoughTransformAlg::m_nBinsTanPhi
IntegerProperty m_nBinsTanPhi
Definition: PhiHoughTransformAlg.h:117
MuonR4::PhiHoughTransformAlg::m_minSigmasSearchIntercept
DoubleProperty m_minSigmasSearchIntercept
Definition: PhiHoughTransformAlg.h:113
HoughHelperFunctions.h
xAOD::etaMax
etaMax
Definition: HIEventShape_v2.cxx:46
MuonR4::HoughHelpers::Phi::houghParamStrip
double houghParamStrip(double tanPhi, const MuonR4::HoughHitType &dc)
straight line parametrisation for strip detector measurements, in the x-direction
Definition: HoughHelperFunctions.cxx:31
MuonR4::ActsPeakFinderForMuonCfg
Acts::HoughTransformUtils::PeakFinders::IslandsAroundMaxConfig ActsPeakFinderForMuonCfg
Definition: MuonHoughDefs.h:26
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
SG::ReadHandleKey< ContainerType >
MuonR4::PhiHoughTransformAlg::m_nBinsIntercept
IntegerProperty m_nBinsIntercept
Definition: PhiHoughTransformAlg.h:119
MuonR4::PhiHoughTransformAlg::preProcessMaximum
StatusCode preProcessMaximum(const ActsGeometryContext &gctx, const MuonR4::HoughMaximum &maximum, HoughEventData &data) const
pre-processing for a given input eta-maximum Counts potential phi-hits and defines the search space
Definition: PhiHoughTransformAlg.cxx:111
x
#define x
MuonR4::HoughMaximum::getHitsInMax
const std::vector< HitType > & getHitsInMax() const
getter
Definition: HoughMaximum.h:46
ReadCondHandle.h
AthReentrantAlgorithm
An algorithm that can be simultaneously executed in multiple threads.
Definition: AthReentrantAlgorithm.h:83
MuonR4::PhiHoughTransformAlg::findRankedSegmentSeeds
std::vector< MuonR4::ActsPeakFinderForMuon::Maximum > findRankedSegmentSeeds(HoughEventData &data, const MuonR4::HoughMaximum &maximum) const
perform a hough search for the most promising phi extension of an eta-maximum Performs a local hough ...
Definition: PhiHoughTransformAlg.cxx:158
MuonR4::PhiHoughTransformAlg::countIncompatibleEtaHits
int countIncompatibleEtaHits(const MuonR4::ActsPeakFinderForMuon::Maximum &phiMaximum, const MuonR4::HoughMaximum &etaMaximum) const
helper to count the number of eta measurements that would be discarded for a given phi extension cand...
Definition: PhiHoughTransformAlg.cxx:73
MuonR4::HoughHelpers::Phi::houghWidthStrip
double houghWidthStrip(double tanPhi, const MuonR4::HoughHitType &dc, double targetReso)
Uncertainty parametrisation for strip measurements.
Definition: HoughHelperFunctions.cxx:34
MuonR4::HoughEventData_impl::searchSpaceIntercept
std::pair< double, double > searchSpaceIntercept
Definition: HoughEventData.h:63
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
MuonR4::HoughMaximum::parentBucket
const SpacePointBucket * parentBucket() const
getter
Definition: HoughMaximum.h:51
MuonChamber.h
MuonR4::PhiHoughTransformAlg::m_minSigmasSearchTanPhi
DoubleProperty m_minSigmasSearchTanPhi
Definition: PhiHoughTransformAlg.h:110
python.utils.best
def best(iterable, priorities=[3, 2, 1, -1, 0])
Definition: DataQuality/DQUtils/python/utils.py:50
AnalysisUtils::copy_if
Out copy_if(In first, const In &last, Out res, const Pred &p)
Definition: IFilterUtils.h:30
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
SG::VarHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:103
MuonR4::HoughEventData_impl::currAxisRanges
Acts::HoughTransformUtils::HoughAxisRanges currAxisRanges
Definition: HoughEventData.h:61
MuonR4::SegmentFit::ParamDefs::x0
@ x0
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
ActsGeometryContext
Include the GeoPrimitives which need to be put first.
Definition: ActsGeometryContext.h:27
min
#define min(a, b)
Definition: cfImp.cxx:40
MuonR4::SpacePoint
The muon space point is the combination of two uncalibrated measurements one of them measures the eta...
Definition: MuonSpectrometer/MuonPhaseII/Event/MuonSpacePoint/MuonSpacePoint/SpacePoint.h:18
MuonR4::PhiHoughTransformAlg::m_maxEtaHolesOnMax
IntegerProperty m_maxEtaHolesOnMax
Definition: PhiHoughTransformAlg.h:122
PhiHoughTransformAlg.h
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:221
MuonR4::PhiHoughTransformAlg::m_recoverSinglePhiWithBS
BooleanProperty m_recoverSinglePhiWithBS
Definition: PhiHoughTransformAlg.h:125
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
MuonR4::HoughMaximum::getCounts
double getCounts() const
getter
Definition: HoughMaximum.h:43
WriteCaloSwCorrections.cfg
cfg
Definition: WriteCaloSwCorrections.py:23
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
MuonR4
This header ties the generic definitions in this package.
Definition: HoughEventData.h:16
MuonR4::PhiHoughTransformAlg::execute
virtual StatusCode execute(const EventContext &ctx) const override
Definition: PhiHoughTransformAlg.cxx:208
python.SystemOfUnits.mm
int mm
Definition: SystemOfUnits.py:83
SG::WriteHandle
Definition: StoreGate/StoreGate/WriteHandle.h:76
a
TList * a
Definition: liststreamerinfos.cxx:10
MuonR4::HoughMaximum
Data class to represent an eta maximum in hough space.
Definition: HoughMaximum.h:14
MuonR4::PhiHoughTransformAlg::m_maxima
SG::ReadHandleKey< EtaHoughMaxContainer > m_maxima
Definition: PhiHoughTransformAlg.h:97
unit
const PlainObject unit() const
This is a plugin that makes Eigen look like CLHEP & defines some convenience methods.
Definition: AmgMatrixBasePlugin.h:21
MuonR4::PhiHoughTransformAlg::m_downWeightMultiplePrd
BooleanProperty m_downWeightMultiplePrd
Definition: PhiHoughTransformAlg.h:128
MuonR4::HoughMaximum::interceptY
double interceptY() const
getter
Definition: HoughMaximum.h:40
MuonR4::PhiHoughTransformAlg::retrieveContainer
StatusCode retrieveContainer(const EventContext &ctx, const SG::ReadHandleKey< ContainerType > &key, const ContainerType *&contToPush) const
Helper method to fetch data from StoreGate.
Definition: PhiHoughTransformAlg.cxx:41
MuonR4::PhiHoughTransformAlg::recoverSinglePhiMax
std::unique_ptr< SegmentSeed > recoverSinglePhiMax(HoughEventData &data, const MuonR4::HoughMaximum &maximum) const
extend an eta maximum with just a single attached phi measurement.
Definition: PhiHoughTransformAlg.cxx:194
MuonR4::HoughEventData_impl::houghPlane
std::unique_ptr< HoughPlane > houghPlane
Definition: HoughEventData.h:35
MuonR4::PhiHoughTransformAlg::prepareHoughPlane
StatusCode prepareHoughPlane(HoughEventData &data) const
prepare the hough plane once per event.
Definition: PhiHoughTransformAlg.cxx:56
MuonR4::HoughEventData_impl::updateSearchWindow
static void updateSearchWindow(std::pair< double, double > &searchWindow, double value)
Updates a search space window to account for a value.
Definition: HoughEventData.h:29
MuonR4::HoughEventData_impl
Templated event data class for the phase-2 muon hough transform.
Definition: HoughEventData.h:22
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37