ATLAS Offline Software
Loading...
Searching...
No Matches
MuonDetDescr/MuonGeoModelTest/src/NSWGeoPlottingAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4#include "NSWGeoPlottingAlg.h"
5
6#include <cmath>
7#include <format>
8
9#include "GaudiKernel/SystemOfUnits.h"
14#include "TFile.h"
15#include "TGraph.h"
16#include "TH1.h"
17#include "TH2D.h"
19#include "TrkSurfaces/Surface.h"
20
21namespace {
22std::string to_string(const Amg::Vector3D& v) {
23 std::stringstream sstr{};
24 sstr << "[x,y,z]=(" << v.x() << "," << v.y() << "," << v.z()
25 << ") [theta/eta/phi]=(" << (v.theta() / Gaudi::Units::degree) << ","
26 << v.eta() << "," << v.phi() << ")";
27 return sstr.str();
28}
29
30} // namespace
31namespace MuonGM{
33 auto out_file = std::make_unique<TFile>(m_outFile.value().c_str(), "RECREATE");
34 if (!out_file || !out_file->IsOpen() || out_file->IsZombie()) {
35
36 ATH_MSG_FATAL("Failed to create the output file " << m_outFile);
37 return StatusCode::FAILURE;
38 }
39 out_file->mkdir("SinglePads");
40 out_file->mkdir("ActiveSurfaces");
41 const MmIdHelper& mm_helper = m_idHelperSvc->mmIdHelper();
42 const sTgcIdHelper& st_helper = m_idHelperSvc->stgcIdHelper();
43 for (auto& id_graph : m_nswPads) {
44 std::unique_ptr<TGraph>& graph = id_graph.second;
45 const Identifier& id = id_graph.first;
46 bool is_mm = m_idHelperSvc->isMM(id);
47 const int stEta = m_idHelperSvc->stationEta(id);
48 const int ml = is_mm ? mm_helper.multilayer(id) : st_helper.multilayer(id);
49 const int lay = is_mm ? mm_helper.gasGap(id) : st_helper.gasGap(id);
50 const std::string ch_name =
51 (is_mm ? mm_helper.stationNameString(m_idHelperSvc->stationName(id))
52 : st_helper.stationNameString(m_idHelperSvc->stationName(id))) +
53 std::to_string(std::abs(stEta)) + (stEta > 0 ? "A" : "C") +
54 std::to_string(m_idHelperSvc->stationPhi(id)) + "W" +
55 std::to_string(ml) + "L" + std::to_string(lay);
56 TDirectory* dir = out_file->GetDirectory("SinglePads");
57 dir->WriteObject(graph.get(), ch_name.c_str());
58 graph.reset();
59 const int signed_lay = layerId(id);
60 std::unique_ptr<TGraph>& lay_graph = m_nswLayers[signed_lay];
61 if (!lay_graph)
62 continue;
63 std::string lay_name = std::string{is_mm ? "MMG" : "STG"} + "W" +
64 std::to_string(ml) + (stEta > 0 ? "A" : "C") +
65 std::to_string(lay);
66 out_file->WriteObject(lay_graph.get(), lay_name.c_str());
67 lay_graph.reset();
68 std::unique_ptr<TH1>& active_area = m_nswActiveAreas[signed_lay];
69 if (!active_area)
70 continue;
71 dir = out_file->GetDirectory("ActiveSurfaces");
72
73 dir->WriteObject(active_area.get(), lay_name.c_str());
74 active_area.reset();
75 }
76 return StatusCode::SUCCESS;
77}
79 ATH_CHECK(m_DetectorManagerKey.initialize());
80 ATH_CHECK(m_idHelperSvc.retrieve());
83 return StatusCode::SUCCESS;
84}
85StatusCode NSWGeoPlottingAlg::execute(const EventContext& ctx) {
86 if (m_alg_run)
87 return StatusCode::SUCCESS;
88 ATH_MSG_INFO("Executing NSWGeoPlottingAlg for the first time");
89
90 const MuonGM::MuonDetectorManager* detMgr{nullptr};
91
93
94 for (auto& id_graph : m_nswPads) {
95 const Identifier& id = id_graph.first;
96 std::unique_ptr<TGraph>& pad_graph = id_graph.second;
97 const bool is_mm = m_idHelperSvc->isMM(id);
98 const int signed_lay = layerId(id);
99 std::unique_ptr<TGraph>& wheel_graph = m_nswLayers[signed_lay];
100
101 const MuonGM::MMReadoutElement* mm_roe =
102 is_mm ? detMgr->getMMReadoutElement(id) : nullptr;
103 const MuonGM::sTgcReadoutElement* st_roe =
104 is_mm ? nullptr : detMgr->getsTgcReadoutElement(id);
105
106 const MuonGM::MuonChannelDesign* design =
107 // cppcheck-suppress nullPointer; https://trac.cppcheck.net/ticket/14369
108 is_mm ? mm_roe->getDesign(id) : st_roe->getDesign(id);
109
110 const Trk::TrkDetElementBase* roe =
111 (mm_roe ? static_cast<const Trk::TrkDetElementBase*>(mm_roe)
112 : static_cast<const Trk::TrkDetElementBase*>(st_roe));
113 auto fill_graphs = [&](const Amg::Vector2D& locPos, int strip) {
114 if ((is_mm || std::abs(locPos.y()) < 1.e-3) &&
115 design->channelNumber(locPos) != strip) {
116 ATH_MSG_ALWAYS(" Backmapping of the strip number did not work for "
117 << m_idHelperSvc->toString(id) << " local pos: "
118 << locPos.x() << " " << locPos.y() << " "
119 << " " << design->channelNumber(locPos) << " vs. "
120 << strip);
121 return false;
122 }
123
124 Amg::Vector3D globPos{Amg::Vector3D::Zero()};
125 roe->surface(id).localToGlobal(locPos, Amg::Vector3D::Zero(), globPos);
126 if (pad_graph)
127 pad_graph->SetPoint(pad_graph->GetN(), globPos.x(), globPos.y());
128 if (wheel_graph)
129 wheel_graph->SetPoint(wheel_graph->GetN(), globPos.x(), globPos.y());
130
131 return true;
132 };
133 const MmIdHelper& id_helper = m_idHelperSvc->mmIdHelper();
134 auto global_points = [&](const Identifier& id, Amg::Vector3D& left,
135 Amg::Vector3D& center, Amg::Vector3D& right) {
136 Amg::Vector2D l_cen{Amg::Vector2D::Zero()}, l_left{Amg::Vector2D::Zero()},
137 l_right{Amg::Vector2D::Zero()};
138 const MuonGM::MuonChannelDesign* design = nullptr;
139 if (mm_roe)
140 design = mm_roe->getDesign(id);
141 else if (st_roe)
142 design = st_roe->getDesign(id);
143 if (!design)[[unlikely]]{
144 ATH_MSG_ERROR("'design' is a nullptr");
145 return StatusCode::FAILURE;
146 }
147 const int chan = id_helper.channel(id);
148 design->leftEdge(chan, l_left);
149 design->center(chan, l_cen);
150 design->rightEdge(chan, l_right);
151
152 roe->surface(id).localToGlobal(l_left, Amg::Vector3D::Zero(), left);
153 roe->surface(id).localToGlobal(l_cen, Amg::Vector3D::Zero(), center);
154 roe->surface(id).localToGlobal(l_right, Amg::Vector3D::Zero(), right);
155 return StatusCode::SUCCESS;
156 };
157
158 const int n_strips =
159 // cppcheck-suppress nullPointer; https://trac.cppcheck.net/ticket/14369
160 (is_mm ? mm_roe->numberOfStrips(id) : st_roe->numberOfStrips(id));
161 for (int strip = design->numberOfMissingBottomStrips() + 1;
162 strip <= n_strips; strip += 1) {
163 {
164 Amg::Vector2D locPos{Amg::Vector2D::Zero()};
165 if (design->leftEdge(strip, locPos) && !fill_graphs(locPos, strip))
166 ATH_MSG_DEBUG("left edge -- channel " << m_idHelperSvc->toString(id)
167 << " does not have strip "
168 << strip << "... Why?");
169 }
170 {
171 Amg::Vector2D locPos{Amg::Vector2D::Zero()};
172 if (design->center(strip, locPos) && !fill_graphs(locPos, strip))
173 ATH_MSG_DEBUG("center -- channel " << m_idHelperSvc->toString(id)
174 << " does not have strip " << strip
175 << "... Why?");
176 }
177 {
178 Amg::Vector2D locPos{Amg::Vector2D::Zero()};
179 if (design->rightEdge(strip, locPos) && !fill_graphs(locPos, strip))
180 ATH_MSG_DEBUG("right edge -- channel " << m_idHelperSvc->toString(id)
181 << " does not have strip "
182 << strip << "... Why?");
183 }
184 }
185 auto uv_intersects = [&]() {
187 if (design->hasStereoAngle() || m_idHelperSvc->issTgc(id))
188 return StatusCode::SUCCESS;
189 const int gap = id_helper.gasGap(id);
190 const int ml = id_helper.multilayer(id);
191 if ((ml == 1 && gap == 2) || (ml == 2 && gap == 4))
192 return StatusCode::SUCCESS;
193
194 for (int strip = design->numberOfMissingBottomStrips() + 1;
195 strip <= n_strips; strip += 1) {
196 const int u_gap = ml == 1 ? 3 : 1;
197 const int v_gap = ml == 1 ? 4 : 2;
198 const Identifier x_id = id_helper.channelID(id, ml, gap, strip);
199 const Identifier u_id = id_helper.channelID(id, ml, u_gap, strip);
200 const Identifier v_id = id_helper.channelID(id, ml, v_gap, strip);
201 Amg::Vector3D x_center{Amg::Vector3D::Zero()},
202 u_center{Amg::Vector3D::Zero()}, v_center{Amg::Vector3D::Zero()};
203 Amg::Vector3D x_left{Amg::Vector3D::Zero()},
204 u_left{Amg::Vector3D::Zero()}, v_left{Amg::Vector3D::Zero()};
205 Amg::Vector3D x_right{Amg::Vector3D::Zero()},
206 u_right{Amg::Vector3D::Zero()}, v_right{Amg::Vector3D::Zero()};
207
208 StatusCode sc = global_points(x_id, x_left, x_center, x_right);
209 if(sc.isFailure()) return StatusCode::FAILURE;
210 sc = global_points(u_id, u_left, u_center, u_right);
211 if(sc.isFailure()) return StatusCode::FAILURE;
212 sc = global_points(v_id, v_left, v_center, v_right);
213 if(sc.isFailure()) return StatusCode::FAILURE;
214
215 const Amg::Vector3D x_dir = (x_right - x_left).unit();
216 const Amg::Vector3D v_dir = (v_left - v_right).unit();
217 const Amg::Vector3D u_dir = (u_left - u_right).unit();
218
219 std::optional<double> uv_isect =
220 Amg::intersect<3>(v_center, v_dir, u_center, u_dir);
221
222 if (!uv_isect) {
223 ATH_MSG_ERROR("Failed to intersect the uv strips for identifiers "
224 << std::endl
225 << " *** " << m_idHelperSvc->toString(u_id) << " "
226 << to_string(u_dir) << std::endl
227 << " *** " << m_idHelperSvc->toString(v_id) << " "
228 << to_string(v_dir));
229 return StatusCode::FAILURE;
230 }
231 const Amg::Vector3D uv_ipoint = u_center + (*uv_isect) * u_dir;
232 const Amg::Vector2D cen_diff = (uv_ipoint - x_center).block<2, 1>(0, 0);
233 if (cen_diff.dot(cen_diff) > std::numeric_limits<float>::epsilon()) {
234 ATH_MSG_ERROR("Expect that the uv strips "
235 << std::endl
236 << " *** " << m_idHelperSvc->toString(u_id) << " "
237 << to_string(u_dir) << std::endl
238 << " *** " << m_idHelperSvc->toString(v_id) << " "
239 << to_string(v_dir)
240 << " intersect at the center of the corresponding x "
241 "strip. But they don't. "
242 << std::endl
243 << to_string(uv_ipoint) << std::endl
244 << " vs." << std::endl
245 << to_string(x_center));
246 }
247 ATH_MSG_DEBUG("Intersection of uv is in " << to_string(uv_ipoint) << " "
248 << to_string(x_center));
249
250 std::optional<double> ux_isect =
251 Amg::intersect<3>(u_center, u_dir, x_center, x_dir);
252 if (!ux_isect) {
253 ATH_MSG_ERROR("Failed to intersect the ux strips for identifiers "
254 << std::endl
255 << " *** " << m_idHelperSvc->toString(v_id) << " "
256 << to_string(u_dir) << std::endl
257 << " *** " << m_idHelperSvc->toString(x_id) << " "
258 << to_string(x_dir));
259 return StatusCode::FAILURE;
260 }
261 ATH_MSG_DEBUG("Intersection of xu is in "
262 << to_string(x_center + (*ux_isect) * x_dir) << " "
263 << to_string(x_center));
264
265 std::optional<double> vx_isect =
266 Amg::intersect<3>(v_center, v_dir, x_center, x_dir);
267 if (!ux_isect) {
268 ATH_MSG_ERROR("Failed to intersect the vx strips for identifiers "
269 << std::endl
270 << " *** " << m_idHelperSvc->toString(v_id) << " "
271 << to_string(v_dir) << std::endl
272 << " *** " << m_idHelperSvc->toString(x_id) << " "
273 << to_string(x_dir));
274 return StatusCode::FAILURE;
275 }
276 ATH_MSG_DEBUG("Intersection of vu is in "
277 << to_string(x_center + (*vx_isect) * x_dir) << " "
278 << to_string(x_center));
279 }
280 return StatusCode::SUCCESS;
281 };
282 if (false)
283 ATH_CHECK(uv_intersects());
284
285 std::unique_ptr<TH1>& surface_histo = m_nswActiveAreas[signed_lay];
286 if (!surface_histo) {
287 ATH_MSG_WARNING("No surface histo has been made for "
288 << m_idHelperSvc->toString(id) << " " << signed_lay);
289 continue;
290 }
291 const Amg::Vector3D& surf_cent = roe->center(id);
292 double d = std::max(std::max(design->xSize(), design->maxYSize()),
293 design->minYSize());
294 for (double x = surf_cent.x() - d; x <= surf_cent.x() + d; x += 1) {
295 for (double y = surf_cent.y() - d; y <= surf_cent.y() + d; y += 1) {
296 const Amg::Vector3D glob_pos{x, y, surf_cent.z()};
297 Amg::Vector2D lpos{Amg::Vector2D::Zero()};
298 if (!roe->surface(id).globalToLocal(glob_pos, glob_pos, lpos))
299 continue;
300 if ((is_mm && mm_roe->insideActiveBounds(id, lpos, 10., 10.)) ||
301 (!is_mm && st_roe->surface(id).insideBounds(lpos, 10., 10.))
302
303 ) {
304 surface_histo->Fill(x, y);
305 }
306 }
307 }
308 }
309 m_alg_run = true;
310 return StatusCode::SUCCESS;
311}
313 const MuonGM::MuonDetectorManager* detMgr{nullptr};
314 ATH_CHECK(detStore()->retrieve(detMgr));
315 const MmIdHelper& id_helper = m_idHelperSvc->mmIdHelper();
316 for (const std::string station : {"MML", "MMS"}) {
317 for (int phi = id_helper.stationPhiMin();
318 phi <= id_helper.stationPhiMax(); ++phi) {
319 for (int eta = -2; eta <= 2; ++eta) {
320 if (eta == 0) {
321 continue;
322 }
323 bool is_valid{false};
324
325 const Identifier station_id = id_helper.elementID(station, eta, phi, is_valid);
326 if (!is_valid) {
327 continue;
328 }
329 for (int ml = id_helper.multilayerMin();
330 ml <= id_helper.multilayerMax(); ++ml) {
331 const Identifier module_id = id_helper.multilayerID(station_id, ml);
332 for (int i_layer = 1; i_layer <= 4; ++i_layer) {
333 const Identifier id =
334 id_helper.channelID(module_id, ml, i_layer, 10);
335 m_nswPads[id] = std::make_unique<TGraph>();
337 int signed_layer = layerId(id);
338 if (!m_nswLayers[signed_layer]) {
339 m_nswLayers[signed_layer] = std::make_unique<TGraph>();
340 }
341 if (!m_nswActiveAreas[signed_layer]) {
342 m_nswActiveAreas[signed_layer] = std::make_unique<TH2D>(
343 std::to_string(m_nswActiveAreas.size()).c_str(),
344 "ActiveNSW;x [mm]; y [mm]", 1000, -5001, 5001., 1000,
345 -5001., 5001.);
346 }
347 }
348 }
349 }
350 }
351 }
352 return StatusCode::SUCCESS;
353}
355 int eta = m_idHelperSvc->stationEta(id);
356 if (m_idHelperSvc->issTgc(id)) {
357 const sTgcIdHelper& id_helper = m_idHelperSvc->stgcIdHelper();
358 int ml = id_helper.multilayer(id);
359 int lay = id_helper.gasGap(id);
360 int type = id_helper.channelType(id);
361 return (8 * (type == sTgcIdHelper::sTgcChannelTypes::Strip) + 4 * (ml - 1) +
362 (lay - 1)) *
363 (eta > 0 ? 1 : -1);
364 }
365 if (m_idHelperSvc->isMM(id)) {
366 const MmIdHelper& id_helper = m_idHelperSvc->mmIdHelper();
367 int ml = id_helper.multilayer(id);
368 int lay = id_helper.gasGap(id);
369 return (16 + 4 * (ml - 1) + (lay - 1)) * (eta > 0 ? 1 : -1);
370 }
371 return -666;
372}
374 const MuonGM::MuonDetectorManager* detMgr{nullptr};
375 ATH_CHECK(detStore()->retrieve(detMgr));
376 const sTgcIdHelper& id_helper = m_idHelperSvc->stgcIdHelper();
377 for (const std::string station : {"STS", "STL"}) {
378 for (int eta = id_helper.stationEtaMin(); eta <= id_helper.stationEtaMax();
379 ++eta) {
380 if (eta == 0)
381 continue;
382 for (int phi = id_helper.stationPhiMin();
383 phi <= id_helper.stationPhiMax(); ++phi) {
384 for (int ml = id_helper.multilayerMin();
385 ml <= id_helper.multilayerMax(); ++ml) {
386 bool is_valid{false};
387 Identifier station_id =
388 id_helper.elementID(station, eta, phi, is_valid);
389 if (!is_valid)
390 continue;
391 const Identifier module_id = id_helper.multilayerID(station_id, ml);
392 if (!detMgr->getsTgcReadoutElement(module_id))
393 continue;
394 for (int lay = 1; lay <= 4; ++lay) {
395 const Identifier strip_id = id_helper.channelID(
396 module_id, ml, lay, sTgcIdHelper::sTgcChannelTypes::Strip, 10);
397 const Identifier wire_id = id_helper.channelID(
398 module_id, ml, lay, sTgcIdHelper::sTgcChannelTypes::Wire, 10);
399 for (const Identifier& id : {strip_id, wire_id}) {
400 m_nswPads[id] = std::make_unique<TGraph>();
401 int signed_layer = layerId(id);
402 if (!m_nswLayers[signed_layer]) {
403 m_nswLayers[signed_layer] = std::make_unique<TGraph>();
404 }
405 if (!m_nswActiveAreas[signed_layer]) {
406 m_nswActiveAreas[signed_layer] = std::make_unique<TH2D>(
407 std::to_string(m_nswActiveAreas.size()).c_str(),
408 "ActiveNSW;x [mm]; y [mm]", 1000, -5001, 5001., 1000,
409 -5001., 5001.);
410 }
411 }
412 }
413 }
414 }
415 }
416 }
417 return StatusCode::SUCCESS;
418}
419}
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_ALWAYS(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_INFO(x,...)
#define ATH_MSG_FATAL(x,...)
detray::unit< scalar_t > unit
static std::string to_string(const std::vector< T > &v)
static Double_t sc
#define y
#define x
const ServiceHandle< StoreGateSvc > & detStore() const
TGraph * graph(std::string_view graphName, std::string_view tDir="", std::string_view stream="")
Simplify the retrieval of registered TGraphs.
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channel) const
Identifier elementID(int stationName, int stationEta, int stationPhi) const
Identifier multilayerID(const Identifier &channeldID) const
int channel(const Identifier &id) const override
static int stationPhiMin()
int gasGap(const Identifier &id) const override
get the hashes
static int multilayerMin()
static int multilayerMax()
static int stationPhiMax()
int multilayer(const Identifier &id) const
An MMReadoutElement corresponds to a single STGC module; therefore typicaly a barrel muon station con...
virtual int numberOfStrips(const Identifier &layerId) const override final
number of strips per layer
bool insideActiveBounds(const Identifier &id, const Amg::Vector2D &locpos, double tol1=0., double tol2=0.) const
boundary check Wrapper Trk::PlaneSurface::insideBounds() taking into account the passivated width
const MuonChannelDesign * getDesign(const Identifier &id) const
returns the MuonChannelDesign class for the given identifier
virtual const Trk::PlaneSurface & surface() const override
access to chamber surface (phi orientation), uses the first gas gap
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
const MMReadoutElement * getMMReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
const sTgcReadoutElement * getsTgcReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
std::map< int, std::unique_ptr< TGraph > > m_nswLayers
Map showing the edges of the 16 layers of the NSW.
std::map< Identifier, std::unique_ptr< TGraph > > m_nswPads
Map containing each PCB of the NSW seperately.
StatusCode execute(const EventContext &ctx) override
Execute method.
std::map< int, std::unique_ptr< TH1 > > m_nswActiveAreas
Map showing the active areas of the NSW to show the passivation.
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_DetectorManagerKey
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
An sTgcReadoutElement corresponds to a single STGC module; therefore typicaly a barrel muon station c...
const MuonChannelDesign * getDesign(const Identifier &id) const
returns the MuonChannelDesign class for the given identifier
virtual int numberOfStrips(const Identifier &layerId) const override final
number of strips per layer
const std::string & stationNameString(const Identifier &id) const
virtual bool insideBounds(const Amg::Vector2D &locpos, double tol1=0., double tol2=0.) const override
This method calls the inside() method of the Bounds.
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const =0
Specified by each surface type: GlobalToLocal method without dynamic memory allocation - boolean chec...
virtual void localToGlobal(const Amg::Vector2D &locp, const Amg::Vector3D &mom, Amg::Vector3D &glob) const =0
Specified by each surface type: LocalToGlobal method without dynamic memory allocation.
This is the base class for all tracking detector elements with read-out relevant information.
virtual const Amg::Vector3D & center() const =0
Return the center of the element.
virtual const Surface & surface() const =0
Return surface associated with this detector element.
int multilayer(const Identifier &id) const
static int stationPhiMax()
int channelType(const Identifier &id) const
Identifier elementID(int stationName, int stationEta, int stationPhi) const
static int multilayerMax()
static int stationPhiMin()
static int stationEtaMin()
static int multilayerMin()
static int stationEtaMax()
int gasGap(const Identifier &id) const override
get the hashes
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channelType, int channel) const
Identifier multilayerID(const Identifier &channeldID) const
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.
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
Ensure that the Athena extensions are properly loaded.
Definition GeoMuonHits.h:27
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
#define unlikely(x)
bool center(int channel, Amg::Vector2D &pos) const
STRIPS ONLY: Returns the center on the strip.
bool leftEdge(int channel, Amg::Vector2D &pos) const
STRIPS ONLY: Returns the left edge of the strip.
int numberOfMissingBottomStrips() const
Returns the number of missing bottom strips.
bool rightEdge(int channel, Amg::Vector2D &pos) const
STRIPS ONLY: Returns the right edge of the strip.
double hasStereoAngle() const
returns whether the stereo angle is non-zero
int channelNumber(const Amg::Vector2D &pos) const
calculate local channel number, range 1=nstrips like identifiers. Returns -1 if out of range