ATLAS Offline Software
Loading...
Searching...
No Matches
MDTSimulation.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "MDTSimulation.h"
9#include <cmath>
10#include <vector>
11
12
13namespace L0Muon {
14
16 ATH_MSG_DEBUG("Initializing " << name() << "...");
17 ATH_CHECK(m_mdtDriftCircleKey.initialize());
18 ATH_CHECK(m_barrelCandidateKey.initialize());
19 ATH_CHECK(m_regionSelector.retrieve());
20 ATH_CHECK(m_idHelperSvc.retrieve());
21 ATH_CHECK(m_geoCtxKey.initialize());
22 ATH_CHECK(m_csfSegmentFinder.retrieve());
24 ATH_CHECK(m_ptEstimationTool.retrieve());
25
26 return StatusCode::SUCCESS;
27 }
28
29 StatusCode MDTSimulation::execute(const EventContext& ctx) const {
30
31 const RPCCandDataContainer* barrelCandidates{nullptr};
32 ATH_CHECK(SG::get(barrelCandidates, m_barrelCandidateKey, ctx));
33
34 const ActsTrk::GeometryContext* geoCtx{nullptr};
35 ATH_CHECK(SG::get(geoCtx, m_geoCtxKey, ctx));
36
37 const ActsTrk::GeometryContext& gctx = *geoCtx;
38 std::vector<float> z_positions, r_positions;
39
40
41
42 for(const L0Muon::RPCCandData* cand : *barrelCandidates) {
43
44 float m=0, b=0;
45
46 if (!fitRPC(*cand, m, b, z_positions, r_positions)) {
47 ATH_MSG_DEBUG("RPC fit failed for this candidate");
48 continue; // do NOT abort event
49 }
50
51 std::vector<const xAOD::MdtDriftCircle*> mdtHits;
52 ATH_CHECK(collectMDTHits(ctx, gctx, cand->eta(), cand->phi(), mdtHits, m, b));
53
54 // Split hits by station
55 std::vector<const xAOD::MdtDriftCircle*> biHits;
56 std::vector<const xAOD::MdtDriftCircle*> bmHits;
57 std::vector<const xAOD::MdtDriftCircle*> boHits;
58
59
60 for (const xAOD::MdtDriftCircle* dc : mdtHits) {
61 if (!dc) continue;
62
63 const Identifier id = dc->identify();
64 const auto& idh = m_idHelperSvc->mdtIdHelper();
65 const std::string st = idh.stationNameString(idh.stationName(id));
66
67 if (st.rfind("BI", 0) == 0) {
68 biHits.push_back(dc);
69 } else if (st.rfind("BM", 0) == 0) {
70 bmHits.push_back(dc);
71 } else if (st.rfind("BO", 0) == 0) {
72 boHits.push_back(dc);
73 }
74 }
75
76
77 // Require at least two stations with enough hits
78 int nStationsWithEnoughHits = 0;
79 if (biHits.size() >= 3) ++nStationsWithEnoughHits;
80 if (bmHits.size() >= 3) ++nStationsWithEnoughHits;
81 if (boHits.size() >= 3) ++nStationsWithEnoughHits;
82
83 if (nStationsWithEnoughHits < 2) {
84 ATH_MSG_DEBUG("Bad candidate: fewer than 2 stations with enough MDT hits");
85 continue;
86 } else {
87 ATH_MSG_DEBUG("Good candidate");
88 }
89
90 // Run the segment finder independently for each station
91 std::vector<L0MDT::Segment> biSegmentsCSF;
92 std::vector<L0MDT::Segment> bmSegmentsCSF;
93 std::vector<L0MDT::Segment> boSegmentsCSF;
94
95 std::vector<L0MDT::Segment> biSegmentsLEG;
96 std::vector<L0MDT::Segment> bmSegmentsLEG;
97 std::vector<L0MDT::Segment> boSegmentsLEG;
98
99
100 if (biHits.size() >= 2) {
101 ATH_CHECK(m_csfSegmentFinder->findSegments(biHits, gctx, m, b, biSegmentsCSF));
102 ATH_CHECK(m_legendreSegmentFinder->findSegments(biHits, gctx, m, b, biSegmentsLEG));
103 }
104 if (bmHits.size() >= 2) {
105 ATH_CHECK(m_csfSegmentFinder->findSegments(bmHits, gctx, m, b, bmSegmentsCSF));
106 ATH_CHECK(m_legendreSegmentFinder->findSegments(bmHits, gctx, m, b, bmSegmentsLEG));
107 }
108 if (boHits.size() >= 2) {
109 ATH_CHECK(m_csfSegmentFinder->findSegments(boHits, gctx, m, b, boSegmentsCSF));
110 ATH_CHECK(m_legendreSegmentFinder->findSegments(boHits, gctx, m, b, boSegmentsLEG));
111 }
112
113
114 ATH_MSG_DEBUG("CSF segment summary: "
115 << " BI=" << biSegmentsCSF.size()
116 << " BM=" << bmSegmentsCSF.size()
117 << " BO=" << boSegmentsCSF.size());
118
119
120 ATH_MSG_DEBUG("LEG segment summary: "
121 << " BI=" << biSegmentsLEG.size()
122 << " BM=" << bmSegmentsLEG.size()
123 << " BO=" << boSegmentsLEG.size());
124
125 const L0MDT::Segment* biSeg = biSegmentsCSF.empty() ? nullptr : &biSegmentsCSF.front();
126 const L0MDT::Segment* bmSeg = bmSegmentsCSF.empty() ? nullptr : &bmSegmentsCSF.front();
127 const L0MDT::Segment* boSeg = boSegmentsCSF.empty() ? nullptr : &boSegmentsCSF.front();
128
129 const auto ptResult = m_ptEstimationTool->estimatePt(biSeg, bmSeg, boSeg);
130
131 if (ptResult) {
132 ATH_MSG_DEBUG("pT estimate | "
133 << "nStations=" << ptResult->nStations
134 << " pt=" << ptResult->pt
135 << " deltaBeta=" << ptResult->deltaBeta
136 << " sagitta=" << ptResult->sagitta
137 << " leverArm=" << ptResult->leverArm);
138 } else {
139 ATH_MSG_DEBUG("pT estimate not available for this candidate");
140 }
141
142 }
143
144 return StatusCode::SUCCESS;
145 }
146
147
148 bool MDTSimulation::fitRPC(const L0Muon::RPCCandData& cand,float& m, float& b, std::vector<float>& z_positions, std::vector<float>& r_positions) const {
149
150 float theta = 2.f * std::atan(std::exp(-cand.eta()));
151 float tanTheta = std::tan(theta);
152
153 z_positions.clear();
154 r_positions.clear();
155
156 for (int i = 0; i < 4; ++i) {
157 const float z_pos = cand.zPos(i);
158 z_positions.push_back(z_pos);
159 r_positions.push_back(z_pos * tanTheta);
160 }
161
162 size_t N = z_positions.size();
163 if (N < 1) return false; // nothing to fit
164
165 float sumZ=0, sumR=0, sumZZ=0, sumZR=0;
166 for (size_t i=0;i<N;++i) {
167 sumZ += z_positions[i];
168 sumR += r_positions[i];
169 sumZZ += z_positions[i]*z_positions[i];
170 sumZR += z_positions[i]*r_positions[i];
171 }
172
173 if (N>=2) {
174 float den = N*sumZZ - sumZ*sumZ;
175 if (den != 0) {
176 m = (N*sumZR - sumZ*sumR) / den;
177 b = (sumR - m*sumZ) / N;
178 }
179 } else {//if the RPC candidate has only one z position we provide the fit using IP
180 m = tanTheta;
181 b = 0.f;
182 }
183
184 return true;
185 }
186
187
188
189
190 StatusCode MDTSimulation::collectMDTHits(const EventContext& ctx, const ActsTrk::GeometryContext& gctx, float eta, float phi, std::vector<const xAOD::MdtDriftCircle*>& hits, float m, float b) const {
191
192
193 hits.clear();
194
195 const float dEta = 0.01f, dPhi = 0.01f;
196
197
198 RoiDescriptor roi(eta, eta-dEta, eta+dEta,
199 phi, phi-dPhi, phi+dPhi);
200 TrigRoiDescriptor trigROI(roi);
201
202
203 auto regSel = m_regionSelector->lookup(ctx);
204 if (!regSel) return StatusCode::FAILURE;
205
206 std::vector<IdentifierHash> hashList;
207 regSel->HashIDList(trigROI, hashList);
208
209
210 const xAOD::MdtDriftCircleContainer* driftCircles{};
211 ATH_CHECK(SG::get(driftCircles, m_mdtDriftCircleKey, ctx));
212
213 float windowSize = 5;
214
215 ATH_MSG_DEBUG("found n chamber hashes " << hashList.size());
217 IdContext modContext = m_idHelperSvc->mdtIdHelper().module_context();
218 for (const IdentifierHash& h : hashList) {
219 Identifier mId;
220 m_idHelperSvc->mdtIdHelper().get_id(h, mId, &modContext);
221 ATH_MSG_DEBUG("looking at chamber " << m_idHelperSvc->toString(mId));
222
223
224 if(!viewer.loadView(mId)){
225 continue;
226 }
227 for(const xAOD::MdtDriftCircle* dc : viewer){
228 const MuonGMR4::MdtReadoutElement* detEl = dc->readoutElement();
229 const float pitch = detEl->tubePitch();
230 const Amg::Transform3D& locToGlob= detEl->localToGlobalTransform(gctx,dc->measurementHash());
231 const Amg::Vector3D gpos = locToGlob* dc->localMeasurementPos() ;
232 float resZ = computeResidual(gpos, m, b);
233 if (std::abs(resZ) > windowSize * pitch) continue;
234
235 hits.push_back(dc);
236
237
238
239 }
240 }
241 return StatusCode::SUCCESS;
242 }
243
244
245 float MDTSimulation::computeResidual(const Amg::Vector3D& gpos, float m, float b) const {
246 float z_pred = (m!=0.f ? (gpos.perp() - b)/m : 0.f);
247 return gpos.z() - z_pred;
248 }
249
250
251
252} // namespace L0Muon
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
Scalar theta() const
theta method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x)
Header file for AthHistogramAlgorithm.
This class saves the "context" of an expanded identifier (ExpandedIdentifier) for compact or hash ver...
Definition IdContext.h:26
This is a "hash" representation of an Identifier.
Class describing a reconstructed MDT segment used by the L0Muon trigger.
float eta() const
get the kinematic parameters
Definition ICandData.cxx:28
ToolHandle< L0MDT::IL0MDTSegmentFinderTool > m_legendreSegmentFinder
virtual StatusCode initialize() override
float computeResidual(const Amg::Vector3D &gpos, float m, float b) const
Compute the residual between a MDT hit global position and the fit line.
virtual StatusCode execute(const EventContext &ctx) const override
ToolHandle< IRegSelTool > m_regionSelector
StatusCode collectMDTHits(const EventContext &ctx, const ActsTrk::GeometryContext &gctx, float eta, float phi, std::vector< const xAOD::MdtDriftCircle * > &hits, float m, float b) const
Collect MDT hits within a RoI around (eta, phi), keeping only those whose residual from the RPC fit l...
SG::ReadHandleKey< ActsTrk::GeometryContext > m_geoCtxKey
ToolHandle< L0MDT::IL0MDTSegmentFinderTool > m_csfSegmentFinder
SG::ReadHandleKey< xAOD::MdtDriftCircleContainer > m_mdtDriftCircleKey
ToolHandle< L0MDT::IPtEstimationTool > m_ptEstimationTool
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
bool fitRPC(const L0Muon::RPCCandData &cand, float &m, float &b, std::vector< float > &z_positions, std::vector< float > &r_positions) const
SG::ReadHandleKey< L0Muon::RPCCandDataContainer > m_barrelCandidateKey
float zPos(int index) const
Readout element to describe the Monitored Drift Tube (Mdt) chambers Mdt chambers usually comrpise out...
double tubePitch() const
Returns the pitch between 2 tubes in a layer.
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...
Describes the Region of Ineterest geometry It has basically 9 parameters.
nope - should be used for standalone also, perhaps need to protect the class def bits ifndef XAOD_ANA...
bool loadView(const Identifier &chamberId)
Loads the view matching the parsed identifier.
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
DataVector< RPCCandData > RPCCandDataContainer
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
@ Chamber
View ends if the moduleHash changes.
MdtDriftCircle_v1 MdtDriftCircle
MdtDriftCircleContainer_v1 MdtDriftCircleContainer