ATLAS Offline Software
Loading...
Searching...
No Matches
MdtIntersectGeometry.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
7#include <iostream>
8
10#include "GaudiKernel/MsgStream.h"
18#include "GeoModelKernel/throwExcept.h"
19// maxNTubesPerLayer is included via MdtChamberGeometry.h -> DriftCircle.h
20
21namespace Muon {
22
24 const MuonGM::MuonDetectorManager* detMgr, const MdtCondDbData* dbData) :
25 m_chid(chid), m_dbData(dbData), m_idHelperSvc(idHelperSvc) {
26 init(detMgr, msg);
27 }
28
30
32 const Amg::Vector3D& pos, const Amg::Vector3D& dir ) const {
33 MuonStationIntersect intersect;
34 if (!m_mdtGeometry) {
35 MsgStream log(Athena::getMessageSvc(), "MdtIntersectGeometry");
36 log << MSG::WARNING << "MdtIntersectGeometry::intersection() - MdtIntersectGeometry not correctly initialized "
37 << m_idHelperSvc->mdtIdHelper().print_to_string(m_chid) << endmsg;
38 return intersect;
39 }
40
41 Amg::Vector3D lpos = transform() * pos;
42 Amg::Vector3D ldir = (transform().linear() * dir).unit();
43
44 double dxdy = std::abs(ldir.y()) > 0.001 ? ldir.x() / ldir.y() : 1000.;
45
46 double lineAngle = std::atan2(ldir.z(), ldir.y());
47 TrkDriftCircleMath::LocVec2D linePos(lpos.y(), lpos.z());
48 TrkDriftCircleMath::Line line(linePos, lineAngle);
49 const TrkDriftCircleMath::DCVec dcs = m_mdtGeometry->tubesPassedByLine(line);
50
52
53 const MuonGM::MdtReadoutElement* detElMl0 = m_hashMl0.is_valid() ? detMgr->getMdtReadoutElement (m_hashMl0) : nullptr;
54 const MuonGM::MdtReadoutElement* detElMl1 = m_hashMl1.is_valid() ? detMgr->getMdtReadoutElement (m_hashMl1) : nullptr;
55
56 TrkDriftCircleMath::DCCit dit = dcs.begin();
57 TrkDriftCircleMath::DCCit dit_end = dcs.end();
58 for (; dit != dit_end; ++dit) {
59 const TrkDriftCircleMath::MdtId& mdtId = dit->id();
60
61 double xint = dxdy * (dit->position().x() - lpos.y()) + lpos.x();
62 Identifier tubeid = m_idHelperSvc->mdtIdHelper().channelID(m_chid, mdtId.ml() + 1, mdtId.lay() + 1, mdtId.tube() + 1);
63 if (m_deadTubesML.find(m_idHelperSvc->mdtIdHelper().multilayerID(tubeid)) != m_deadTubesML.end()) {
64 if (std::find(m_deadTubes.begin(), m_deadTubes.end(), tubeid) != m_deadTubes.end()) continue;
65 }
66 double distWall = std::abs(xint) - 0.5 * tubeLength(detElMl0, detElMl1,
67 mdtId.ml(), mdtId.lay(), mdtId.tube());
68 intersects.emplace_back(tubeid, dit->dr(), distWall);
69 }
70 intersect.setTubeIntersects(std::move(intersects));
71
72 return intersect;
73 }
74
76 const MuonGM::MdtReadoutElement* detElMl1,
77 const int ml, const int layer, const int tube) const {
78#ifndef NDEBUG
79 if (ml < 0 || ml > 1){
80 THROW_EXCEPTION(__func__<<"() got called with ml="<<ml<<" which is definetly out of range");
81 }
82 if (layer < 0 || layer > 3) {
83 THROW_EXCEPTION(__func__<<"() got called with layer="<<layer<<" which is definetly out of range");
84 }
85 if (tube < 0 || tube >= int(MdtIdHelper::maxNTubesPerLayer)){
86 THROW_EXCEPTION(__func__<<"() got called with tube="<<tube<<" which is definetly out of range");
87 }
88#endif
89 // shift by one to account for MuonGeoModel scheme
90 int theTube = tube + 1;
91 int theLayer = layer + 1;
92 // handle case where first ml is dead
93 if (ml == 1 && !detElMl1) return detElMl0->getActiveTubeLength(theLayer, theTube);
94 if (ml == 0)
95 return detElMl0->getActiveTubeLength(theLayer, theTube);
96 else
97 return detElMl1->getActiveTubeLength(theLayer, theTube);
98 }
99
101 /* calculate chamber geometry
102 it takes as input:
103 distance between the first and second tube in the chamber within a layer along the tube layer (tube distance)
104 distance between the first tube in the first layer and the first tube in the second layer along the tube layer (tube stagering)
105 distance between the first and second layer perpendicular to the tube layers (layer distance)
106 position of the first hit in ml 0 and ml 1 (2D in plane)
107 total number of multilayers
108 total number of layers
109 total number of tubes per layer for each multilayer
110 an identifier uniquely identifying the chamber
111 */
112
113 // get id
114 int eta = m_idHelperSvc->mdtIdHelper().stationEta(m_chid);
115 int phi = m_idHelperSvc->mdtIdHelper().stationPhi(m_chid);
116 int name = m_idHelperSvc->mdtIdHelper().stationName(m_chid);
117 // get detEL for first ml (always there)
118 Identifier firstIdml0 = m_idHelperSvc->mdtIdHelper().channelID(name, eta, phi, 1, 1, 1);
119 Identifier firstIdml1;
120
121 const MuonGM::MdtReadoutElement* detElMl0 = detMgr->getMdtReadoutElement(firstIdml0);
122 const MuonGM::MdtReadoutElement* detElMl1 = nullptr;
123
124 if (!detElMl0) {
125 msg << MSG::WARNING << "MdtIntersectGeometry::init() - failed to get readout element for ML0" << endmsg;
126 return;
127 }
128
129 // number of multilayers in chamber
130 int nml = detElMl0->nMDTinStation();
131
132 // treament of chambers with two ml
133 if (nml == 2) {
134 firstIdml1 = m_idHelperSvc->mdtIdHelper().channelID(name, eta, phi, 2, 1, 1);
135 detElMl1 = detMgr->getMdtReadoutElement(firstIdml1);
136 }
137
138 // if one of the two ml is dead treat the chamber as a single ML station
139 // if both are dead give a WARNING
140 // check status of the two multilayers using the MdtCondDbData if it exists
141 // otherwise (i.e. online) they are treated as both good by default
142 bool goodMl0{false}, goodMl1{false};
143 if (m_dbData) {
144 goodMl0 = m_dbData->isGoodMultilayer(firstIdml0);
145 goodMl1 = detElMl1 ? m_dbData->isGoodMultilayer(firstIdml1) : false;
146 } else {
147 goodMl0 = true;
148 goodMl1 = true;
149 }
150 int firstMlIndex = 1;
151 if (goodMl0 && !goodMl1) {
152 nml = 1;
153 detElMl1 = nullptr;
154 } else if (!goodMl0 && goodMl1) {
155 nml = 1;
156 // swap detEl1 and detEl0
157 detElMl0 = detElMl1;
158 detElMl1 = nullptr;
159 firstIdml0 = firstIdml1;
160 firstMlIndex = 2;
161 } else if (!goodMl0 && !goodMl1) {
162 msg << MSG::WARNING << "MdtIntersectGeometry::init() - neither multilayer is good" << endmsg;
163 return;
164 }
166
167 // number of layers and tubes
168 int nlay = detElMl0->getNLayers();
169 int ntube0 = detElMl0->getNtubesperlayer();
170 int ntube1 = detElMl1 ? detElMl1->getNtubesperlayer() : 0;
171
172 // position first tube in ml 0 and 1
173 Amg::Vector3D firstTubeMl0 = transform() * (detElMl0->tubePos(firstIdml0));
174 Amg::Vector3D firstTubeMl1 = detElMl1 ? transform() * (detElMl1->tubePos(firstIdml1)) : Amg::Vector3D{0., 0., 0.};
175
176 TrkDriftCircleMath::LocVec2D firstTube0(firstTubeMl0.y(), firstTubeMl0.z());
177 TrkDriftCircleMath::LocVec2D firstTube1(firstTubeMl1.y(), firstTubeMl1.z());
178
179 // position second tube in ml 0
180 Identifier secondIdml0 = m_idHelperSvc->mdtIdHelper().channelID(name, eta, phi, firstMlIndex, 1, 2);
181 Amg::Vector3D secondTubeMl0 = transform() * (detElMl0->tubePos(secondIdml0));
182
183 fillDeadTubes(detElMl0, msg);
184 if (detElMl1) fillDeadTubes(detElMl1, msg);
185
186 // position first tube in second layer ml 0
187 Identifier firstIdml0lay1 = m_idHelperSvc->mdtIdHelper().channelID(name, eta, phi, firstMlIndex, 2, 1);
188 Amg::Vector3D firstTubeMl0lay1 = transform() * (detElMl0->tubePos(firstIdml0lay1));
189
190 double tubeDist = (secondTubeMl0 - firstTubeMl0).y(); // distance between tube in a given layer
191 double tubeStage = (firstTubeMl0lay1 - firstTubeMl0).y(); // tube stagering distance
192 double layDist = (firstTubeMl0lay1 - firstTubeMl0).z(); // distance between layers
193
194 m_mdtGeometry = std::make_unique<TrkDriftCircleMath::MdtChamberGeometry>(
195 m_chid, m_idHelperSvc, nml, nlay, ntube0, ntube1, firstTube0, firstTube1, tubeDist, tubeStage, layDist, detElMl0->center().theta());
196
197 // finally if the first ml is dead, configure the MdtChamberGeometry accordingly
198 if (!goodMl0 && goodMl1) m_mdtGeometry->isSecondMultiLayer(true);
199
200 m_hashMl0 = detElMl0->detectorElementHash();
201 if (detElMl1) m_hashMl1 = detElMl1->detectorElementHash();
202 }
203 std::shared_ptr<const TrkDriftCircleMath::MdtChamberGeometry> MdtIntersectGeometry::mdtChamberGeometry() const { return m_mdtGeometry; }
205 if ((mydetEl->getStationName()).find("BMG") != std::string::npos) {
206 PVConstLink cv = mydetEl->getMaterialGeom(); // it is "Multilayer"
207 int nGrandchildren = cv->getNChildVols();
208 if (nGrandchildren <= 0) return;
209
210 std::vector<int> tubes;
211 geoGetIds([&](int id) { tubes.push_back(id); }, &*cv);
212 std::sort(tubes.begin(), tubes.end());
213
214 Identifier detElId = mydetEl->identify();
215
216 int name = m_idHelperSvc->mdtIdHelper().stationName(detElId);
217 int eta = m_idHelperSvc->mdtIdHelper().stationEta(detElId);
218 int phi = m_idHelperSvc->mdtIdHelper().stationPhi(detElId);
219 int ml = m_idHelperSvc->mdtIdHelper().multilayer(detElId);
220
221 std::vector<int>::iterator it = tubes.begin();
222 for (int layer = 1; layer <= mydetEl->getNLayers(); layer++) {
223 for (int tube = 1; tube <= mydetEl->getNtubesperlayer(); tube++) {
224 int want_id = layer * MdtIdHelper::maxNTubesPerLayer + tube;
225 if (it != tubes.end() && *it == want_id) {
226 ++it;
227 } else {
228 it = std::lower_bound(tubes.begin(), tubes.end(), want_id);
229 if (it != tubes.end() && *it == want_id) {
230 ++it;
231 } else {
232 Identifier deadTubeId = m_idHelperSvc->mdtIdHelper().channelID(name, eta, phi, ml, layer, tube);
233 Identifier deadTubeMLId = m_idHelperSvc->mdtIdHelper().multilayerID(deadTubeId);
234 m_deadTubes.push_back(deadTubeId);
235 m_deadTubesML.insert(deadTubeMLId);
236 if (msg.level() == MSG::VERBOSE)
237 msg << MSG::VERBOSE << " MdtIntersectGeometry: adding dead tube (" << tube << "), layer(" << layer
238 << "), phi(" << phi << "), eta(" << eta << "), name(" << name << ") and adding multilayerId("
239 << deadTubeMLId << ")." << endmsg;
240 }
241 }
242 }
243 }
244 }
245 }
246
247} // namespace Muon
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
const PlainObject unit() const
This is a plugin that makes Eigen look like CLHEP & defines some convenience methods.
#define endmsg
Visitor to collect all IDs under a GeoModel node.
void geoGetIds(FUNCTION f, const GeoGraphNode *node, int depthLimit=1)
Template helper for running the visitor.
Definition GeoGetIds.h:82
double tubeLength
#define y
#define x
#define z
static constexpr int maxNTubesPerLayer
The maxNTubesPerLayer represents the absolute maximum of tubes which are built into a single multilay...
Definition MdtIdHelper.h:68
unsigned int nMDTinStation() const
How many MDT chambers are in the station.
double getActiveTubeLength(const int tubeLayer, const int tube) const
Amg::Vector3D tubePos(const Identifier &id) const
Returns the global position of the given tube.
int getNLayers() const
Returns the number of tube layers inside the multilayer.
int getNtubesperlayer() const
Returns the number of tubes in each tube layer.
virtual const Amg::Vector3D & center(const Identifier &) const override final
Return the center of the surface associated with this identifier In the case of silicon it returns th...
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
const MdtReadoutElement * getMdtReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
IdentifierHash detectorElementHash() const
Returns the IdentifierHash of the detector element.
Identifier identify() const override final
Returns the ATLAS Identifier of the MuonReadOutElement.
Interface for Helper service that creates muon Identifiers and can be used to print Identifiers.
std::set< Identifier > m_deadTubesML
double tubeLength(const MuonGM::MdtReadoutElement *detElMl0, const MuonGM::MdtReadoutElement *detElMl1, const int ml, const int layer, const int tube) const
std::shared_ptr< const TrkDriftCircleMath::MdtChamberGeometry > mdtChamberGeometry() const
const MdtCondDbData * m_dbData
const Amg::Transform3D & transform() const
std::vector< Identifier > m_deadTubes
const IMuonIdHelperSvc * m_idHelperSvc
void fillDeadTubes(const MuonGM::MdtReadoutElement *mydetEl, MsgStream &msg)
void init(const MuonGM::MuonDetectorManager *detMgr, MsgStream &msg)
std::shared_ptr< TrkDriftCircleMath::MdtChamberGeometry > m_mdtGeometry
MuonStationIntersect intersection(const MuonGM::MuonDetectorManager *detMgr, const Amg::Vector3D &pos, const Amg::Vector3D &dir) const override
MdtIntersectGeometry(MsgStream &msg, const Identifier &chid, const IMuonIdHelperSvc *idHelperSvc, const MuonGM::MuonDetectorManager *detMgr, const MdtCondDbData *dbData)
std::vector< MuonTubeIntersect > TubeIntersects
Implementation of 2 dimensional vector class.
Definition LocVec2D.h:16
singleton-like access to IMessageSvc via open function and helper
Eigen::Matrix< double, 3, 1 > Vector3D
IMessageSvc * getMessageSvc(bool quiet=false)
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
DCVec::const_iterator DCCit
std::vector< DriftCircle > DCVec
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
MsgStream & msg
Definition testRead.cxx:32
#define THROW_EXCEPTION(MESSAGE)
Definition throwExcept.h:10