ATLAS Offline Software
Loading...
Searching...
No Matches
MuonLayerSegmentFinderTool.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
15#include <typeinfo>
16using namespace xAOD::P4Helpers;
17namespace {
18 const float OneOverSqrt12 = 1. / std::sqrt(12);
19}
20namespace Muon {
21 using namespace MuonStationIndex;
22
24 ATH_CHECK(m_idHelperSvc.retrieve());
25 ATH_CHECK(m_printer.retrieve());
27 ATH_CHECK(m_segmentMaker.retrieve());
28 ATH_CHECK(m_csc2dSegmentFinder.retrieve(DisableTool{!m_idHelperSvc->hasCSC() || m_csc2dSegmentFinder.empty()}));
29 ATH_CHECK(m_csc4dSegmentFinder.retrieve(DisableTool{!m_idHelperSvc->hasCSC() || m_csc4dSegmentFinder.empty()}));
30 ATH_CHECK(m_patternSegs.initialize(!m_patternSegs.empty()));
31 ATH_CHECK(m_segmentMatchingTool.retrieve(DisableTool{m_patternSegs.empty()}));
33 ATH_CHECK(m_clusterSegMakerNSW.retrieve(DisableTool{m_clusterSegMakerNSW.empty()|| !m_patternSegs.empty()}));
34
35 return StatusCode::SUCCESS;
36 }
37
39 const MuonLayerPrepRawData& layerPrepRawData, std::vector<std::shared_ptr<const Muon::MuonSegment> >& segments) const {
41 " Running segment finding in sector "
42 << intersection.layerSurface.sector << " region " << MuonStationIndex::regionName(intersection.layerSurface.regionIndex)
43 << " layer " << MuonStationIndex::layerName(intersection.layerSurface.layerIndex) << " intersection position: r "
44 << intersection.trackParameters->position().perp() << " z " << intersection.trackParameters->position().z() << " locX "
45 << intersection.trackParameters->parameters()[Trk::locX] << " locY " << intersection.trackParameters->parameters()[Trk::locY]
46 << " phi " << intersection.trackParameters->position().phi());
47
48 // run cluster hit based segment finding on PRDs
49 findClusterSegments(ctx, intersection, layerPrepRawData, segments);
50 ATH_MSG_VERBOSE(" findClusterSegments " << segments.size());
51
52 // run standard MDT/Trigger hit segment finding either from Hough or hits
53 findMdtSegments(intersection, layerPrepRawData, segments);
54 }
55
57 const MuonLayerPrepRawData& layerPrepRawData,
58 std::vector<std::shared_ptr<const Muon::MuonSegment>>& segments) const {
59 // calibrate what is already there
60 MuonLayerROTs layerROTs;
61 if (!m_muonPRDSelectionTool->calibrateAndSelect(intersection, layerPrepRawData, layerROTs)) {
62 ATH_MSG_WARNING("Failed to calibrate and select layer data");
63 return;
64 }
65
66 // get hits
67 using namespace MuonStationIndex;
68 TechnologyIndex clusterTech =
69 intersection.layerSurface.regionIndex == DetectorRegionIndex::Barrel ? TechnologyIndex::RPC : TechnologyIndex::TGC;
70 const std::vector<const MdtDriftCircleOnTrack*>& mdts = layerROTs.getMdts();
71 const std::vector<const MuonClusterOnTrack*>& clusters = layerROTs.getClusters(clusterTech);
72
73 findMdtSegments(intersection, mdts, clusters, segments);
74 }
75
77 const std::vector<const MdtDriftCircleOnTrack*>& mdts,
78 const std::vector<const MuonClusterOnTrack*>& clusters,
79 std::vector<std::shared_ptr<const Muon::MuonSegment>>& segments) const {
80 // require at least 2 MDT hits
81 if (mdts.size() <= 2) return;
82 // run segment finder
83 std::unique_ptr<Trk::SegmentCollection> segColl = std::make_unique<Trk::SegmentCollection>(SG::VIEW_ELEMENTS);
84 m_segmentMaker->find(intersection.trackParameters->position(), intersection.trackParameters->momentum(), mdts, clusters,
85 !clusters.empty(), segColl.get(), intersection.trackParameters->momentum().mag());
86
87 for (Trk::Segment* tseg : *segColl) {
88 MuonSegment* mseg = dynamic_cast<MuonSegment*>(tseg);
89 ATH_MSG_DEBUG(" " << m_printer->print(*mseg));
90 segments.emplace_back(mseg);
91 }
92 }
93
95 const MuonLayerPrepRawData& layerPrepRawData,
96 std::vector<std::shared_ptr<const Muon::MuonSegment>>& segments) const {
97 // if there are CSC hits run CSC segment finding
98 if (!layerPrepRawData.cscs.empty()) findCscSegments(ctx, layerPrepRawData, segments);
99
100 // No need to call the NSW segment finding
101 if (layerPrepRawData.mms.empty() && layerPrepRawData.stgcs.empty()) return;
102
103 // NSW segment finding
104 MuonLayerROTs layerROTs;
105 if (!m_muonPRDSelectionTool->calibrateAndSelect(intersection, layerPrepRawData, layerROTs)) {
106 ATH_MSG_WARNING("Failed to calibrate and select layer data");
107 return;
108 }
109
110 ATH_MSG_DEBUG(" MM prds " << layerPrepRawData.mms.size() << " STGC prds " << layerPrepRawData.stgcs.size());
111
112 // get STGC and MM clusters
113 const std::vector<const MuonClusterOnTrack*>& clustersSTGC = layerROTs.getClusters(TechnologyIndex::STGC);
114 const std::vector<const MuonClusterOnTrack*>& clustersMM = layerROTs.getClusters(TechnologyIndex::MM);
115
117 NSWSegmentCache cache{};
118
119
120 if (!clustersSTGC.empty()) {
121 ATH_MSG_DEBUG(" STGC clusters " << clustersSTGC.size());
122 std::transform(clustersSTGC.begin(), clustersSTGC.end(), std::back_inserter(cache.inputClust),
123 [](const Muon::MuonClusterOnTrack* cl){ return std::unique_ptr<Muon::MuonClusterOnTrack>{cl->clone()};});
124
125 }
126 if (!clustersMM.empty()) {
127 ATH_MSG_DEBUG(" MM clusters " << clustersMM.size());
128 std::transform(clustersMM.begin(), clustersMM.end(), std::back_inserter(cache.inputClust),
129 [](const Muon::MuonClusterOnTrack* cl){ return std::unique_ptr<Muon::MuonClusterOnTrack>{cl->clone()};});
130 }
131 if (cache.inputClust.empty()) return;
132
133
134 if (!m_patternSegs.empty()) {
135 std::set<Identifier> needed_rios{};
136 for (std::unique_ptr<const MuonClusterOnTrack>& clus : cache.inputClust) {
137 needed_rios.insert(clus->identify());
138 }
139 SG::ReadHandle<Trk::SegmentCollection> input_segs{m_patternSegs, ctx};
140 for (const Trk::Segment *trk_seg : *input_segs) {
141 const MuonSegment *seg = dynamic_cast<const Muon::MuonSegment *>(trk_seg);
142 // Initial check that the segments are on the same detector side
143 if (intersection.trackParameters->associatedSurface().center().z() * seg->globalPosition().z() < 0) continue;
144
146 bool hasNSW{false};
147 for (size_t n = 0; !hasNSW && n < seg->numberOfContainedROTs(); ++n) {
148 const MuonClusterOnTrack *clus = dynamic_cast<const MuonClusterOnTrack *>(seg->rioOnTrack(n));
149 hasNSW |= (clus && needed_rios.count(clus->identify()));
150 }
152 if (!hasNSW) continue;
154 if (m_segmentMatchingTool->match(ctx, intersection, *seg)) segments.emplace_back(seg->clone());
155 }
158 return;
159 }
160
161 m_clusterSegMakerNSW->find(ctx, cache);
162
163 for (std::unique_ptr<MuonSegment>& seg : cache.constructedSegs) {
164 ATH_MSG_DEBUG(" NSW segment " << m_printer->print(*seg));
165 segments.emplace_back(std::move(seg));
166 }
167 }
168
169 void MuonLayerSegmentFinderTool::findCscSegments(const EventContext& ctx, const MuonLayerPrepRawData& layerPrepRawData,
170 std::vector<std::shared_ptr<const Muon::MuonSegment>>& segments) const {
171 // run 2d segment finder
172 std::unique_ptr<MuonSegmentCombinationCollection> combi2D = m_csc2dSegmentFinder->find(layerPrepRawData.cscs, ctx);
173 if (!combi2D) return;
174
175 // run 4d segment finder
176 std::unique_ptr<MuonSegmentCombinationCollection> combi4D = m_csc4dSegmentFinder->find(*combi2D, ctx);
177 if (!combi4D) return;
178
179 // extract segments and clean-up memory
180 for (auto com : *combi4D) {
181 const Muon::MuonSegmentCombination& combi = *com;
182 unsigned int nstations = combi.numberOfStations();
183
184 // loop over chambers in combi and extract segments
185 for (unsigned int i = 0; i < nstations; ++i) {
186 // loop over segments in station
188
189 // check if not empty
190 if (!segs || segs->empty()) continue;
191 // loop over new segments, copy them into collection
192 for (std::unique_ptr<MuonSegment>& seg_it : *segs) {
193 ATH_MSG_DEBUG(" " << m_printer->print(*seg_it));
194 segments.emplace_back(std::move(seg_it));
195 }
196 }
197 }
198 }
201 std::vector<std::shared_ptr<const Muon::MuonSegment> >& segments) const {
202
203 if(m_houghDataPerSectorVecKey.empty()) return;
204 unsigned int nprevSegments = segments.size(); // keep track of what is already there
205 int sector = intersection.layerSurface.sector;
206 MuonStationIndex::DetectorRegionIndex regionIndex = intersection.layerSurface.regionIndex;
207 MuonStationIndex::LayerIndex layerIndex = intersection.layerSurface.layerIndex;
208
209 // get hough data
210 SG::ReadHandle houghDataPerSectorVec{m_houghDataPerSectorVecKey, ctx};
211 if (!houghDataPerSectorVec.isValid()) {
212 ATH_MSG_ERROR("Hough data per sector vector not found");
213 return;
214 }
215
216 // sanity check
217 if (static_cast<int>(houghDataPerSectorVec->vec.size()) <= sector - 1) {
218 ATH_MSG_WARNING(" MuonLayerHoughTool::HoughDataPerSectorVec smaller than sector "
219 << houghDataPerSectorVec->vec.size() << " sector " << sector);
220 return;
221 }
222
223 // get hough maxima in the layer
224 unsigned int sectorLayerHash = MuonStationIndex::sectorLayerHash(regionIndex, layerIndex);
225 const MuonLayerHoughTool::HoughDataPerSector& houghDataPerSector = houghDataPerSectorVec->vec[sector - 1];
226 ATH_MSG_DEBUG(" findMdtSegmentsFromHough: sector "
227 << sector << " " << MuonStationIndex::regionName(regionIndex) << " "
228 << MuonStationIndex::layerName(layerIndex) << " sector hash " << sectorLayerHash << " houghData "
229 << houghDataPerSectorVec->vec.size() << " " << houghDataPerSector.maxVec.size());
230
231 // sanity check
232 if (houghDataPerSector.maxVec.size() <= sectorLayerHash) {
233 ATH_MSG_WARNING(" houghDataPerSector.maxVec.size() smaller than hash " << houghDataPerSector.maxVec.size()
234 << " hash " << sectorLayerHash);
235 return;
236 }
237 const MuonLayerHoughTool::MaximumVec& maxVec = houghDataPerSector.maxVec[sectorLayerHash];
238
239 // get local coordinates in the layer frame
240 bool barrelLike = intersection.layerSurface.regionIndex == DetectorRegionIndex::Barrel;
241
242 float phi = intersection.trackParameters->position().phi();
243
244 // in the endcaps take the r in the sector frame from the local position of the extrapolation
245 float r = barrelLike ? m_muonSectorMapping.transformRToSector(intersection.trackParameters->position().perp(), phi,
246 intersection.layerSurface.sector, true)
247 : intersection.trackParameters->parameters()[Trk::locX];
248
249 float z = intersection.trackParameters->position().z();
250 float errx = Amg::error(*intersection.trackParameters->covariance(), Trk::locX);
251 float x = barrelLike ? r : z;
252 float y = barrelLike ? z : r;
253 float theta = std::atan2(x, y);
254
255 ATH_MSG_DEBUG(" Got Hough maxima " << maxVec.size() << " extrapolated position in Hough space (" << x << "," << y
256 << ") error " << errx << " "
257 << " angle " << theta);
258
259 // lambda to handle calibration and selection of MDTs
260 std::vector<std::unique_ptr<const Trk::MeasurementBase>> garbage;
261 auto handleMdt = [this, intersection, &garbage](const MdtPrepData& prd, std::vector<const MdtDriftCircleOnTrack*>& mdts) {
262 const MdtDriftCircleOnTrack* mdt = m_muonPRDSelectionTool->calibrateAndSelect(intersection, prd);
263 if (!mdt) return;
264 mdts.push_back(mdt);
265 garbage.emplace_back(mdt);
266 };
267
268
269 // lambda to handle calibration and selection of clusters
270 auto handleCluster = [this, intersection,&garbage](const MuonCluster& prd,
271 std::vector<const MuonClusterOnTrack*>& clusters) {
272 const MuonClusterOnTrack* cluster = m_muonPRDSelectionTool->calibrateAndSelect(intersection, prd);
273 if (!cluster) return;
274 clusters.push_back(cluster);
275 garbage.emplace_back(cluster);
276 };
277
278
279 // loop over maxima and associate them to the extrapolation
280 MuonLayerHoughTool::MaximumVec::const_iterator mit = maxVec.begin();
281 MuonLayerHoughTool::MaximumVec::const_iterator mit_end = maxVec.end();
282 for (; mit != mit_end; ++mit) {
283 const MuonHough::MuonLayerHough::Maximum& maximum = **mit;
284 float residual = maximum.pos - y;
285 float residualTheta = maximum.theta - theta;
286 float refPos = (maximum.hough != nullptr) ? maximum.hough->m_descriptor.referencePosition : 0;
287 float maxwidth = (maximum.binposmax - maximum.binposmin);
288 if (maximum.hough) maxwidth *= maximum.hough->m_binsize;
289 float pull = residual / std::hypot(errx , maxwidth * OneOverSqrt12);
290
291
292 ATH_MSG_DEBUG(" Hough maximum " << maximum.max << " position (" << refPos << "," << maximum.pos
293 << ") residual " << residual << " pull " << pull << " angle " << maximum.theta
294 << " residual " << residualTheta);
295
296 // select maximum
297 if (std::abs(pull) > 5) continue;
298
299 // loop over hits in maximum and add them to the hit list
300 std::vector<const MdtDriftCircleOnTrack*> mdts;
301 std::vector<const MuonClusterOnTrack*> clusters;
302 for (const auto& hit : maximum.hits) {
303
304 // treat the case that the hit is a composite TGC hit
305 if (hit->tgc) {
306 for (const auto& prd : hit->tgc->etaCluster) {
307 handleCluster(*prd, clusters);
308 }
309 } else if (hit->prd) {
310 Identifier id = hit->prd->identify();
311 if (m_idHelperSvc->isMdt(id))
312 handleMdt(static_cast<const MdtPrepData&>(*hit->prd), mdts);
313 else
314 handleCluster(static_cast<const MuonCluster&>(*hit->prd), clusters);
315 }
316 }
317
318 // get phi hits
319 const MuonLayerHoughTool::PhiMaximumVec& phiMaxVec =
320 houghDataPerSector.phiMaxVec[toInt(intersection.layerSurface.regionIndex)];
321 ATH_MSG_DEBUG(" Got Phi Hough maxima " << phiMaxVec.size() << " phi " << phi);
322
323 // loop over maxima and associate them to the extrapolation
324 MuonLayerHoughTool::PhiMaximumVec::const_iterator pit = phiMaxVec.begin();
325 MuonLayerHoughTool::PhiMaximumVec::const_iterator pit_end = phiMaxVec.end();
326 for (; pit != pit_end; ++pit) {
327 const MuonHough::MuonPhiLayerHough::Maximum& maximum = **pit;
328 const float residual = deltaPhi( maximum.pos, phi);
329
330 ATH_MSG_DEBUG(" Phi Hough maximum " << maximum.max << " phi " << maximum.pos << ") angle "
331 << maximum.pos << " residual " << residual);
332
333 for (const auto& phi_hit : maximum.hits) {
334 // treat the case that the hit is a composite TGC hit
335 if (phi_hit->tgc) {
336 Identifier id = phi_hit->tgc->phiCluster.front()->identify();
337 if (m_idHelperSvc->layerIndex(id) != intersection.layerSurface.layerIndex) continue;
338 for (const auto& prd : phi_hit->tgc->phiCluster) handleCluster(*prd, clusters);
339 } else if (phi_hit->prd) {
340 Identifier id = phi_hit->prd->identify();
341 if (m_idHelperSvc->layerIndex(id) != intersection.layerSurface.layerIndex) continue;
342 handleCluster(static_cast<const MuonCluster&>(*phi_hit->prd), clusters);
343 }
344 }
345 }
346
347 // call segment finder
348 ATH_MSG_DEBUG(" Got hits: mdts " << mdts.size() << " clusters " << clusters.size());
349 findMdtSegments(intersection, mdts, clusters, segments);
350
351 // clean-up memory
352 garbage.clear();
353 ATH_MSG_DEBUG(" Done maximum: new segments " << segments.size() - nprevSegments);
354 }
355 ATH_MSG_DEBUG(" Done with layer: new segments " << segments.size() - nprevSegments);
356 }
357
358} // namespace Muon
Scalar phi() const
phi method
Scalar theta() const
theta method
#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 y
#define x
#define z
Base class for Muon cluster RIO_OnTracks.
This is the common class for 3D segments used in the muon spectrometer.
const Trk::RIO_OnTrack * rioOnTrack(unsigned int) const
returns the RIO_OnTrack (also known as ROT) objects depending on the integer
virtual MuonSegment * clone() const override final
needed to avoid excessive RTTI
virtual const Amg::Vector3D & globalPosition() const override final
global position
This class represents the corrected MDT measurements, where the corrections include the effects of wi...
Class to represent measurements from the Monitored Drift Tubes.
Definition MdtPrepData.h:33
Base class for Muon cluster RIO_OnTracks.
HoughDataPerSec HoughDataPerSector
HoughDataPerSec::PhiMaximumVec PhiMaximumVec
HoughDataPerSec::MaximumVec MaximumVec
struct holding RIO_OnTracks for a given layer
const std::vector< const MuonClusterOnTrack * > & getClusters(MuonStationIndex::TechnologyIndex tech) const
access calibrated MuonClusters for a given technolgy
const std::vector< const MdtDriftCircleOnTrack * > & getMdts() const
access calibrated MDT's
ToolHandle< IMuonNSWSegmentFinderTool > m_clusterSegMakerNSW
ToolHandle< Muon::IMuonLayerSegmentMatchingTool > m_segmentMatchingTool
ToolHandle< IMuonPRDSelectionTool > m_muonPRDSelectionTool
ToolHandle< IMuonSegmentMaker > m_segmentMaker
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
const Muon::MuonSectorMapping m_muonSectorMapping
SG::ReadHandleKey< Muon::HoughDataPerSectorVec > m_houghDataPerSectorVecKey
Use the hough data to find sectors in the speectrometer traversed by a muon.
void findCscSegments(const EventContext &ctx, const MuonLayerPrepRawData &layerPrepRawData, std::vector< std::shared_ptr< const Muon::MuonSegment > > &segments) const
find csc segments
void findMdtSegmentsFromHough(const EventContext &ctx, const MuonSystemExtension::Intersection &intersection, std::vector< std::shared_ptr< const Muon::MuonSegment > > &segments) const override
void findClusterSegments(const EventContext &ctx, const MuonSystemExtension::Intersection &intersection, const MuonLayerPrepRawData &layerPrepRawData, std::vector< std::shared_ptr< const Muon::MuonSegment > > &segments) const
find segments from PRD clusters
PublicToolHandle< MuonEDMPrinterTool > m_printer
ToolHandle< ICscSegmentFinder > m_csc4dSegmentFinder
void find(const EventContext &ctx, const MuonSystemExtension::Intersection &intersection, const MuonLayerPrepRawData &layerPrepRawData, std::vector< std::shared_ptr< const Muon::MuonSegment > > &segments) const override
IMuonLayerSegmentFinderTool interface: find.
SG::ReadHandleKey< Trk::SegmentCollection > m_patternSegs
Do not rebuild the segments if the segment is already built upstream.
void findMdtSegments(const MuonSystemExtension::Intersection &intersection, const MuonLayerPrepRawData &layerPrepRawData, std::vector< std::shared_ptr< const Muon::MuonSegment > > &segments) const
find mdt segments from hits in the layer
ToolHandle< ICscSegmentFinder > m_csc2dSegmentFinder
Class to hold a set of MuonSegments belonging together.
std::vector< std::unique_ptr< MuonSegment > > SegmentVec
SegmentVec * stationSegments(unsigned int index) const
Access to segments in a given station.
unsigned int numberOfStations() const
Number of stations with segment.
This is the common class for 3D segments used in the muon spectrometer.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
Base class for all TrackSegment implementations, extends the common MeasurementBase.
std::vector< std::string > intersection(std::vector< std::string > &v1, std::vector< std::string > &v2)
int r
Definition globals.cxx:22
double error(const Amg::MatrixX &mat, int index)
return diagonal error of the matrix caller should ensure the matrix is symmetric and the index is in ...
const std::string & layerName(LayerIndex index)
convert LayerIndex into a string
TechnologyIndex
enum to classify the different layers in the muon spectrometer
DetectorRegionIndex
enum to classify the different layers in the muon spectrometer
constexpr int toInt(const EnumType enumVal)
unsigned int sectorLayerHash(DetectorRegionIndex detectorRegionIndex, LayerIndex layerIndex)
create a hash out of region and layer
const std::string & regionName(DetectorRegionIndex index)
convert DetectorRegionIndex into a string
LayerIndex
enum to classify the different layers in the muon spectrometer
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
@ locY
local cartesian
Definition ParamDefs.h:38
@ locX
Definition ParamDefs.h:37
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
struct representing the maximum in the hough space
RegionDescriptor m_descriptor
RegionPhiMaximumVec phiMaxVec
RegionMaximumVec maxVec
Struct to hold all PrepRawData collections in a given layer.
std::vector< const CscPrepDataCollection * > cscs
std::vector< const MMPrepDataCollection * > mms
std::vector< const sTgcPrepDataCollection * > stgcs