ATLAS Offline Software
MuonStationTypeBuilder.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 // Muon
8 // MuonSpectrometer include
12 // Amg
15 
16 // Trk
17 #include <fstream>
18 
19 #include "GeoModelKernel/GeoBox.h"
20 #include "GeoModelKernel/GeoShape.h"
21 #include "GeoModelKernel/GeoShapeShift.h"
22 #include "GeoModelKernel/GeoShapeSubtraction.h"
23 #include "GeoModelKernel/GeoShapeUnion.h"
24 #include "GeoModelKernel/GeoSimplePolygonBrep.h"
25 #include "GeoModelKernel/GeoTrd.h"
26 #include "GeoModelKernel/GeoTube.h"
27 #include "GeoModelKernel/GeoTubs.h"
28 #include "GeoModelKernel/GeoVPhysVol.h"
41 #include "TrkGeometry/DiscLayer.h"
44 #include "TrkGeometry/Material.h"
47 #include "TrkGeometry/PlaneLayer.h"
52 #include "TrkSurfaces/DiscBounds.h"
66 
67 // stl
68 #include <cmath> //for std::abs
69 #include <map>
70 
72  static const InterfaceID IID_IMuonStationTypeBuilder("MuonStationTypeBuilder", 1, 0);
73  return IID_IMuonStationTypeBuilder;
74 }
75 
76 
77 
78 // constructor
80  const std::string& n,
81  const IInterface* p)
82  : AthAlgTool(t, n, p) {
83  declareInterface<Muon::MuonStationTypeBuilder>(this);
84 }
85 
86 // Athena standard methods
87 // initialize
89  // Retrieve the tracking volume array creator
90  // -------------------------------------------
91  ATH_CHECK(m_trackingVolumeArrayCreator.retrieve());
92  ATH_MSG_INFO("Retrieved tool " << m_trackingVolumeArrayCreator);
93 
94  // default (trivial) muon material properties
95  m_muonMaterial = std::make_unique<Trk::Material>(10e10, 10e10, 0., 0., 0.);
96  if (!m_muonMaterial) {
97  ATH_MSG_FATAL("Could not create the material in " << name()
98  << " initialize()");
99  return StatusCode::FAILURE;
100  }
101 
102  ATH_MSG_INFO( " initialize() successful");
103 
104  return StatusCode::SUCCESS;
105 }
106 
107 std::vector<std::unique_ptr<Trk::Layer>> Muon::MuonStationTypeBuilder::processBoxComponentsArbitrary(const GeoVPhysVol* mv,
108  const Trk::CuboidVolumeBounds& envelope,
109  Cache& /*cache*/) const {
110  ATH_MSG_DEBUG( " processing station components for "<< mv->getLogVol()->getName());
112 
113  std::vector<std::unique_ptr<Trk::Layer>> lays{};
114 
115  // initial solution : single layer collecting all material ; TODO : resolve
116  // sensitive layers and spacers use envelope to define layer bounds
117  auto layBounds = std::make_shared<Trk::RectangleBounds>(envelope.halflengthY(), envelope.halflengthZ());
118  // calculate layer area
119  double layArea= area(*layBounds);
120  // use area to blend station material
121  Trk::MaterialProperties box_mat;
122  m_volumeConverter.collectMaterial(mv, box_mat, layArea);
123  Trk::HomogeneousLayerMaterial boxMaterial(box_mat, 0.);
124 
125  auto layer = std::make_unique<Trk::PlaneLayer>(Amg::Transform3D::Identity(), layBounds,
126  boxMaterial, 2 * envelope.halflengthX());
127 
128  lays.push_back(std::move(layer));
129 
130  return lays;
131 }
132 
133 std::unique_ptr<Trk::TrackingVolumeArray>
135  const Trk::CuboidVolumeBounds& envelope,
136  Cache& cache) const {
137  ATH_MSG_DEBUG( " processing station components for "
138  << mv->getLogVol()->getName());
140 
141  constexpr double tolerance{0.001};
142 
143  // loop over children volumes: check if compatible with binning in X (
144  // detect overlap of sensitive volumes )
145  std::vector<std::pair<double, double>> xVol;
146  double xpos{0}, xh{0};
147  for (const auto& [cv, transf] : geoGetVolumes(mv)) {
148  const GeoLogVol* clv = cv->getLogVol();
149  // consider sensitive volumes only
150  std::string name = clv->getName();
151  if (name.find("MDT") == std::string::npos && name.find("RPC") == std::string::npos){
152  continue;
153  }
154  xpos = transf.translation().x();
155  if (clv->getShape()->type() == "Trd") {
156  const GeoTrd* trd = dynamic_cast<const GeoTrd*>(clv->getShape());
157  xh = std::max(trd->getXHalfLength1(), trd->getXHalfLength2());
158  } else if (clv->getShape()->type() == "Box") {
159  const GeoBox* box = dynamic_cast<const GeoBox*>(clv->getShape());
160  xh = box->getXHalfLength();
161  } else {
162  xh = get_x_size(cv);
163  }
164  if (!xVol.size() || xpos > xVol.back().first)
165  xVol.push_back(std::make_pair(xpos, xh));
166  else {
167  std::vector<std::pair<double, double>>::iterator it = xVol.begin();
168  while (it != xVol.end() && xpos > (*it).first) {
169  ++it;
170  }
171  xVol.insert(it, std::make_pair(xpos, xh));
172  }
173  }
174 
175  double xl = xVol[0].second;
176  double xc = xVol[0].first;
177  for (const auto& xb : xVol) {
178  if (xb.first > xc && xb.first - xb.second < xc + xl) {
179  ATH_MSG_DEBUG("Inconsistent sensitive overlap");
180  return nullptr; // overlap of sensitive volumes : not suitable for
181  // x-binned array
182  }
183  xc = xb.first;
184  xl = xb.second;
185  }
186 
187  // loop over children volumes; ( make sure they do not exceed enveloping
188  // volume boundaries ?) split into connected subvolumes ( assume ordering
189  // along X unless otherwise )
190  std::vector<std::unique_ptr<Trk::Volume>> compVol;
191  std::vector<std::string> compName;
192  std::vector<const GeoVPhysVol*> compGeo;
193  std::vector<Amg::Transform3D> compTransf;
194  for (const auto& [cv, transf] : geoGetVolumes(mv)) {
195  const GeoLogVol* clv = cv->getLogVol();
196  std::unique_ptr<Trk::VolumeBounds> volBounds{};
197  std::unique_ptr<Trk::Volume> vol{};
198  if (clv->getShape()->type() == "Trd") {
199  const GeoTrd* trd = dynamic_cast<const GeoTrd*>(clv->getShape());
200  const double halfX1{trd->getXHalfLength1()}, halfX2{trd->getXHalfLength2()},
201  halfY1{trd->getYHalfLength1()}, halfY2{trd->getYHalfLength2()},
202  halfZ{trd->getZHalfLength()};
203  volBounds = std::make_unique<Trk::CuboidVolumeBounds>(std::max(halfX1, halfX2), std::max(halfY1, halfY2), halfZ);
204  } else if (clv->getShape()->type() == "Box") {
205  const GeoBox* box = dynamic_cast<const GeoBox*>(clv->getShape());
206  volBounds = m_geoShapeConverter.convert(box);
207  } else {
208  double xSize = get_x_size(cv);
209  ATH_MSG_VERBOSE("subvolume not box nor trapezoid, estimated x size:" << xSize);
210  volBounds = std::make_unique<Trk::CuboidVolumeBounds>(xSize, envelope.halflengthY(), envelope.halflengthZ());
211  }
212  vol = std::make_unique<Trk::Volume>(makeTransform(transf), volBounds.release());
213  ATH_MSG_VERBOSE("subvolume center:" << Amg::toString(vol->center()));
214  std::string cname = clv->getName();
215  const std::string& vname = mv->getLogVol()->getName();
216  int nameSize = vname.size() - 8;
217  if (cname.compare(0, nameSize, vname, 0, nameSize) == 0)
218  cname = cname.substr(nameSize, cname.size() - nameSize);
219  // order in X
220  if (compVol.empty() || vol->center().x() >= compVol.back()->center().x()) {
221  compVol.push_back(std::move(vol));
222  compName.push_back(cname);
223  compGeo.push_back(cv);
224  compTransf.push_back(transf);
225  } else {
226  std::vector<std::unique_ptr<Trk::Volume>>::iterator volIter = compVol.begin();
227  std::vector<std::string>::iterator nameIter = compName.begin();
228  std::vector<const GeoVPhysVol*>::iterator geoIter = compGeo.begin();
230  compTransf.begin();
231  while (vol->center().x() >= (*volIter)->center().x()) {
232  ++volIter;
233  ++nameIter;
234  ++geoIter;
235  ++transfIter;
236  }
237  compVol.insert(volIter, std::move(vol));
238  compName.insert(nameIter, cname);
239  compGeo.insert(geoIter, cv);
240  compTransf.insert(transfIter, transf);
241  }
242  } // loop over components
243 
244  // define enveloping volumes for each "technology"
245  std::vector<std::unique_ptr<Trk::TrackingVolume>> trkVols{};
246  double envX = envelope.halflengthX();
247  double envY = envelope.halflengthY();
248  double envZ = envelope.halflengthZ();
249  double currX = -envX;
250  double maxX = envX;
251  bool openSpacer{false}, openRpc{false};
252  std::vector<const GeoVPhysVol*> geoSpacer{}, geoRpc{};
253  std::vector<Amg::Transform3D> transfSpacer{}, transfRpc{};
254  double spacerlowXsize{0.}, spaceruppXsize{0.}, rpclowXsize{0.}, rpcuppXsize{0.};
255  std::vector<float> volSteps;
256  volSteps.push_back(-envX);
257  for (unsigned i = 0; i < compVol.size(); ++i) {
258  bool comp_processed = false;
259  const Trk::VolumeBounds& volBounds = compVol[i]->volumeBounds();
260  const Trk::CuboidVolumeBounds* compBounds = dynamic_cast<const Trk::CuboidVolumeBounds*>(&volBounds);
261  // check return to comply with coverity
262  if (!compBounds) {
263  ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<<" box station component does not return cuboid shape "
264  <<typeid(volBounds).name());
265  continue;
266  }
267  //
268  double lowX = compVol[i]->center().x() - compBounds->halflengthX();
269  double uppX = compVol[i]->center().x() + compBounds->halflengthX();
270 
272  if (lowX < currX && (compName[i].compare("RPC28") != 0 && compName[i].compare("RPC29") !=0)) {
273  ATH_MSG_WARNING(" clash between components in volume:" << compName[i] << "current:" << currX
274  << ": low edge of next volume:" << lowX);
275  }
276  if (uppX > maxX) {
277  ATH_MSG_WARNING(" clash between component and envelope:" << compName[i] << "upper:" << uppX << ">" << maxX);
278  }
279  // close Rpc if no further components
280  if (openRpc && compName[i].compare(0, 3, "RPC") != 0 && compName[i].compare(0, 3, "Ded") != 0) {
281  // low edge of current volume
282  double Xcurr = compVol[i]->center().x() - compBounds->halflengthX();
283  if (Xcurr >= currX + rpclowXsize + rpcuppXsize) {
284  auto rpcBounds = std::make_unique<Trk::CuboidVolumeBounds>(0.5 * (Xcurr - currX), envY, envZ);
285  Amg::Transform3D rpcTrf{Amg::getTranslateX3D(currX + rpcBounds->halflengthX())};
286  auto rpcVol = std::make_unique<Trk::Volume>(makeTransform(std::move(rpcTrf)),
287  rpcBounds.release());
288  std::unique_ptr<Trk::TrackingVolume> rpcTrkVol = processRpc(*rpcVol, geoRpc, transfRpc, cache);
289  trkVols.push_back(std::move(rpcTrkVol));
290  volSteps.push_back(Xcurr);
291  currX = Xcurr;
292  openRpc = false;
293  } else {
294  ATH_MSG_WARNING("clash in Rpc definition!");
295  }
296  }
297  // close spacer if no further components
298  if (openSpacer && compName[i].compare(0, 1, "C") != 0 && compName[i].compare(0, 2, "LB") != 0) {
299  // low edge of current volume
300  double Xcurr = compVol[i]->center().x() - compBounds->halflengthX();
301  if (Xcurr - currX - (spacerlowXsize + spaceruppXsize) >= -tolerance) {
302  auto spacerBounds = std::make_unique<Trk::CuboidVolumeBounds>(0.5 * (Xcurr - currX), envY, envZ);
303  Amg::Transform3D spacerTrf{Amg::getTranslateX3D(currX + spacerBounds->halflengthX())};
304  Trk::Volume spacerVol(makeTransform(std::move(spacerTrf)), spacerBounds.release());
305  std::unique_ptr<Trk::TrackingVolume> spacerTrkVol{processSpacer(spacerVol, geoSpacer, transfSpacer)};
306  trkVols.emplace_back(std::move(spacerTrkVol));
307  volSteps.push_back(Xcurr);
308  currX = Xcurr;
309  openSpacer = false;
310  } else {
311  ATH_MSG_WARNING("clash in spacer definition!");
312  }
313  }
314  if (compName[i].compare(0, 3, "RPC") == 0 || compName[i].compare(0, 3, "Ded") == 0) {
315  if (!openRpc) {
316  openRpc = true;
317  geoRpc.clear();
318  geoRpc.push_back(compGeo[i]);
319  transfRpc.clear();
320  transfRpc.push_back(compTransf[i]);
321  // establish temporary volume size
322  rpclowXsize = compVol[i]->center().x() - currX;
323  rpcuppXsize = compBounds->halflengthX();
324  // check clash at low edge
325  if (std::abs(rpclowXsize) < compBounds->halflengthX() - tolerance) {
326  ATH_MSG_WARNING("rpc low edge - not enough space");
327  }
328  } else {
329  geoRpc.push_back(compGeo[i]);
330  transfRpc.push_back(compTransf[i]);
331  // check temporary volume size
332  if (std::abs(compVol[i]->center().x() - currX) < compBounds->halflengthX() - tolerance) {
333  ATH_MSG_WARNING("rpc low edge - not enough space");
334  }
335  if (compVol[i]->center().x() + compBounds->halflengthX() > currX + rpclowXsize + rpcuppXsize) {
336  rpcuppXsize += (compVol[i]->center().x() + compBounds->halflengthX()) -
337  (currX + rpclowXsize + rpcuppXsize);
338  }
339  }
340  comp_processed = true;
341  }
342  if (compName[i].compare(0, 1, "C") == 0 || compName[i].compare(0, 2, "LB") == 0) {
343  if (!openSpacer) {
344  openSpacer = true;
345  geoSpacer.clear();
346  geoSpacer.push_back(compGeo[i]);
347  transfSpacer.clear();
348  transfSpacer.push_back(compTransf[i]);
349  // establish temporary volume size
350  spacerlowXsize = compVol[i]->center().x() - currX;
351  spaceruppXsize = compBounds->halflengthX();
352  // check clash at low edge
353  if (std::abs(spacerlowXsize) <
354  compBounds->halflengthX() - tolerance) {
355  ATH_MSG_WARNING("spacer low edge - not enough space:current:center:halfSize:"
356  << currX << "," << compVol[i]->center().x() << "," << compBounds->halflengthX());
357  }
358  } else {
359  geoSpacer.push_back(compGeo[i]);
360  transfSpacer.push_back(compTransf[i]);
361  // check temporary volume size
362  if (std::abs(compVol[i]->center().x() - currX) < compBounds->halflengthX() - tolerance) {
363  ATH_MSG_WARNING("spacer low edge - not enough space:current:center:halfSize:"
364  << currX << "," << compVol[i]->center().x() << "," << compBounds->halflengthX());
365  }
366  if (compVol[i]->center().x() + compBounds->halflengthX() > currX + spacerlowXsize + spaceruppXsize) {
367  spaceruppXsize += (compVol[i]->center().x() + compBounds->halflengthX()) -
368  (currX + spacerlowXsize + spaceruppXsize);
369  }
370  }
371  comp_processed = true;
372  }
373  if (compName[i].compare(0, 3, "MDT") == 0) {
374  std::unique_ptr<Trk::Volume> mdtVol;
375  // remove z shift in transform !! bugfix !!
376  double zShift = compVol[i]->transform().translation().z();
377  if (std::abs(zShift) > 0) {
378  ATH_MSG_DEBUG("unusual z shift for subvolume:" << zShift);
379  }
380  double boundHalfLengthX{0.};
381  if (lowX == currX) {
382  auto mdtBounds = std::make_unique<Trk::CuboidVolumeBounds>(compBounds->halflengthX(), envY, envZ);
383  boundHalfLengthX = mdtBounds->halflengthX();
384  mdtVol = std::make_unique<Trk::Volume>(makeTransform(Amg::getTranslateZ3D(-zShift) *compVol[i]->transform()),
385  mdtBounds.release());
386  } else {
387  if (std::abs(lowX - currX) > 0.002) {
388  ATH_MSG_DEBUG("Mdt volume size does not match the envelope:lowX,currX:"<< lowX << "," << currX);
389  ATH_MSG_DEBUG("adjusting Mdt volume ");
390  }
391  auto mdtBounds = std::make_unique<Trk::CuboidVolumeBounds>(compBounds->halflengthX() + 0.5 * (lowX - currX),
392  envY, envZ);
393  boundHalfLengthX = mdtBounds->halflengthX();
394  mdtVol = std::make_unique<Trk::Volume>(makeTransform(Amg::getTranslate3D(0.5 * (currX - lowX), 0., -zShift) *
395  compVol[i]->transform()),
396  mdtBounds.release());
397  }
398  double shiftSign = 1.;
399  if (std::abs(zShift) > 0.) {
400  const std::string& stName = mv->getLogVol()->getName();
401  if (stName.compare(0, 4, "BIR3") == 0 || stName.compare(0, 4, "BIR5") == 0 ||
402  stName.compare(0, 4, "BIR7") == 0 || stName.compare(0, 5, "BIR10") == 0) {
403  shiftSign = -1.;
404  }
405  }
406 
407  std::unique_ptr<Trk::TrackingVolume> mdtTrkVol{processMdtBox(*mdtVol, compGeo[i],
408  Amg::getTranslateZ3D(-zShift) * compTransf[i],
409  shiftSign * std::abs(zShift), cache)};
410  trkVols.push_back(std::move(mdtTrkVol));
411  currX += 2. * boundHalfLengthX;
412  volSteps.push_back(currX);
413  comp_processed = true;
414  zShift = 0.;
415  }
416  if (!comp_processed) {
417  ATH_MSG_WARNING("unknown technology:" << compName[i]);
418  }
419  } // end loop over station children
420 
421  // there may be a spacer still open
422  if (openSpacer) {
423  if (maxX >= currX + spacerlowXsize + spaceruppXsize) {
424  auto spacerBounds = std::make_unique<Trk::CuboidVolumeBounds>(0.5 * (maxX - currX), envY, envZ);
425  Amg::Transform3D spacerTrf{Amg::getTranslateX3D(currX + spacerBounds->halflengthX())};
426  Trk::Volume spacerVol(makeTransform(std::move(spacerTrf)),
427  spacerBounds.release());
428  std::unique_ptr<Trk::TrackingVolume> spacerTrkVol{processSpacer(spacerVol, geoSpacer, transfSpacer)};
429  trkVols.emplace_back(std::move(spacerTrkVol));
430  currX = maxX;
431  volSteps.push_back(currX);
432  openSpacer = false;
433  }
434  }
435  // there may be an Rpc still open
436  if (openRpc) {
437  if (maxX >= currX + rpclowXsize + rpcuppXsize) {
438  auto rpcBounds = std::make_unique<Trk::CuboidVolumeBounds>(0.5 * (maxX - currX), envY, envZ);
439  Amg::Transform3D rpcTrf{Amg::getTranslateX3D(currX + rpcBounds->halflengthX())};
440  auto rpcVol = std::make_unique<Trk::Volume>(makeTransform(std::move(rpcTrf)),
441  rpcBounds.release());
442  std::unique_ptr<Trk::TrackingVolume> rpcTrkVol{processRpc(*rpcVol, geoRpc, transfRpc, cache)};
443  trkVols.push_back(std::move(rpcTrkVol));
444  currX = maxX;
445  volSteps.push_back(currX);
446  openRpc = false;
447  } else {
448  ATH_MSG_WARNING("clash in Rpc definition!(last volume)");
449  }
450  }
451  // create VolumeArray (1DX)
452  std::unique_ptr<Trk::TrackingVolumeArray> components{};
453 
454  auto binUtility = std::make_unique<Trk::BinUtility>(volSteps, Trk::BinningOption::open, Trk::BinningValue::binX);
455  components.reset(m_trackingVolumeArrayCreator->cuboidVolumesArrayNav(Muon::release(trkVols), binUtility.release(), false));
456 
457 
458  return components;
459 }
460 
461 std::unique_ptr<Trk::TrackingVolumeArray>
463  const Trk::TrapezoidVolumeBounds& envelope,
464  Cache& cache) const {
465  ATH_MSG_DEBUG( " processing station components for " << mv->getLogVol()->getName());
467 
468  constexpr double tolerance{0.0001};
469 
470  // loop over children volumes; ( make sure they do not exceed enveloping
471  // volume boundaries ?) split into connected subvolumes ( assume ordering
472  // along X unless otherwise )
473  std::vector<std::unique_ptr<Trk::Volume>> compVol;
474  std::vector<std::string> compName;
475  std::vector<const GeoVPhysVol*> compGeo;
476  std::vector<Amg::Transform3D> compTransf;
477  for (const auto& [cv, transf]: geoGetVolumes(mv)) {
478  const GeoLogVol* clv = cv->getLogVol();
479  // retrieve volumes for components
480  std::unique_ptr<Trk::VolumeBounds> bounds{};
481  Amg::Transform3D boxTrf{transf};
482  if (clv->getShape()->type() == "Trd") {
483  const GeoTrd* trd = dynamic_cast<const GeoTrd*>(clv->getShape());
484  const double halfX1 = trd->getXHalfLength1();
485  const double halfX2 = trd->getXHalfLength2();
486  const double halfY1 = trd->getYHalfLength1();
487  const double halfY2 = trd->getYHalfLength2();
488  const double halfZ = trd->getZHalfLength();
489  if (halfX1 == halfX2 && halfY1 == halfY2)
490  bounds = std::make_unique<Trk::CuboidVolumeBounds>(std::max(halfX1, halfX2),
491  std::max(halfY1, halfY2), halfZ);
492  if (halfX1 == halfX2 && halfY1 != halfY2) {
493  boxTrf = boxTrf * Amg::getRotateY3D(M_PI_2) *
494  Amg::getRotateZ3D(M_PI_2);
495  bounds = std::make_unique<Trk::TrapezoidVolumeBounds>(halfY1, halfY2,
496  halfZ, halfX1);
497  }
498  if (halfX1 != halfX2 && halfY1 == halfY2) {
499  bounds = std::make_unique<Trk::TrapezoidVolumeBounds>(halfX1, halfX2,
500  halfY1, halfZ);
501  }
502  if (!bounds) {
503  ATH_MSG_WARNING("volume shape for component not recognized");
504  }
505  } else if (clv->getShape()->type() == "Box") {
506  const GeoBox* box = dynamic_cast<const GeoBox*>(clv->getShape());
507  const double halfX1 = box->getXHalfLength();
508  const double halfY1 = box->getYHalfLength();
509  const double halfZ = box->getZHalfLength();
510  bounds = std::make_unique<Trk::CuboidVolumeBounds>(halfX1, halfY1, halfZ);
511  } else {
512  double xSize = get_x_size(cv);
513  // printChildren(cv);
514  if (clv->getName().compare(0, 1, "C") != 0 && clv->getName().compare(0, 2, "LB") != 0) {
515  boxTrf = boxTrf * Amg::getRotateY3D(M_PI_2) *
516  Amg::getRotateZ3D(M_PI_2);
517  }
518  bounds = std::make_unique<Trk::TrapezoidVolumeBounds>(envelope.minHalflengthX(),
519  envelope.maxHalflengthX(),
520  envelope.halflengthY(), xSize);
521  }
522  auto vol = std::make_unique<Trk::Volume>(makeTransform(std::move(boxTrf)),
523  bounds.release());
524  std::string cname = clv->getName();
525  std::string vname = mv->getLogVol()->getName();
526  int nameSize = vname.size() - 8;
527  if (cname.compare(0, nameSize, vname, 0, nameSize) == 0) {
528  cname = cname.substr(nameSize, cname.size() - nameSize);
529  }
530  // order in X
531  if (compVol.empty() || vol->center().x() >= compVol.back()->center().x()) {
532  compVol.emplace_back(std::move(vol));
533  compName.push_back(cname);
534  compGeo.push_back(cv);
535  compTransf.push_back(transf);
536  } else {
537  std::vector<std::unique_ptr<Trk::Volume>>::iterator volIter = compVol.begin();
538  std::vector<std::string>::iterator nameIter = compName.begin();
539  std::vector<const GeoVPhysVol*>::iterator geoIter = compGeo.begin();
540  std::vector<Amg::Transform3D>::iterator transfIter = compTransf.begin();
541  while (vol->center().x() >= (*volIter)->center().x()) {
542  ++volIter;
543  ++nameIter;
544  ++geoIter;
545  ++transfIter;
546  }
547  compVol.insert(volIter, std::move(vol));
548  compName.insert(nameIter, cname);
549  compGeo.insert(geoIter, cv);
550  compTransf.insert(transfIter, transf);
551  }
552  } // loop over components
553  // define enveloping volumes for each "technology"
554  std::vector<std::unique_ptr<Trk::TrackingVolume>> trkVols;
555  const double envX1{envelope.minHalflengthX()}, envX2{envelope.maxHalflengthX()},
556  envY{envelope.halflengthY()}, envZ{envelope.halflengthZ()};
557  //
558  double currX{-envZ}, maxX{envZ};
559  //
560  bool openSpacer = false;
561  std::vector<const GeoVPhysVol*> geoSpacer{}, geoRpc{};
562  std::vector<Amg::Transform3D> transfSpacer{}, transfRpc{};
563  double spacerlowXsize{0.}, spaceruppXsize{0.}, Xcurr{0.}, lowX{0.}, uppX{0.};
564  std::vector<float> volSteps;
565  volSteps.push_back(-envelope.halflengthZ());
566  for (unsigned i = 0; i < compVol.size(); i++) {
567  bool comp_processed = false;
568  const Trk::VolumeBounds& volBounds = compVol[i]->volumeBounds();
569  const Trk::CuboidVolumeBounds* compCubBounds = dynamic_cast<const Trk::CuboidVolumeBounds*>(&volBounds);
570  const Trk::TrapezoidVolumeBounds* compTrdBounds = dynamic_cast<const Trk::TrapezoidVolumeBounds*>(&volBounds);
571  if (compCubBounds) {
572  lowX = compVol[i]->center().x() - compCubBounds->halflengthX();
573  uppX = compVol[i]->center().x() + compCubBounds->halflengthX();
574  } else if (compTrdBounds) {
575  lowX = compVol[i]->center().x() - compTrdBounds->halflengthZ();
576  uppX = compVol[i]->center().x() + compTrdBounds->halflengthZ();
577  }
578  if (lowX < currX) {
579  ATH_MSG_WARNING("Warning: we have a clash between components here!");
580  }
581  if (uppX > maxX) {
582  ATH_MSG_WARNING("we have a clash between component and envelope!");
583  }
584  // low edge of current volume
585  Xcurr = lowX;
586  if (!compCubBounds && !compTrdBounds) {
587  ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<<" Unknown volume shape "<<typeid(volBounds).name());
588  return nullptr;
589  }
590  // close spacer if no further components
591  if (openSpacer && compName[i].compare(0, 1, "C") != 0 && compName[i].compare(0, 2, "LB") != 0) {
592  if (Xcurr - currX - (spacerlowXsize + spaceruppXsize) >=-tolerance) {
593  auto spacerBounds = std::make_unique<Trk::TrapezoidVolumeBounds>(envX1, envX2, envY,
594  0.5 * (Xcurr - currX));
595  Amg::Transform3D tr = Amg::getTranslateX3D(currX + spacerBounds->halflengthZ()) *
596  Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2);
597  Trk::Volume spacerVol(makeTransform(std::move(tr)), spacerBounds.release());
598  std::unique_ptr<Trk::TrackingVolume> spacerTrkVol{processSpacer(spacerVol, geoSpacer, transfSpacer)};
599  trkVols.push_back(std::move(spacerTrkVol));
600  currX = Xcurr;
601  volSteps.push_back(Xcurr);
602  openSpacer = false;
603  } else {
604  ATH_MSG_DEBUG(mv->getLogVol()->getName()<< " : clash in spacer definition ");
605  }
606  }
607  if (compName[i].compare(0, 3, "RPC") == 0 || compName[i].compare(0, 3, "Ded") == 0) {
608  ATH_MSG_DEBUG(mv->getLogVol()->getName() << ": RPC components in endcaps? ");
609  }
610  if (compName[i].compare(0, 1, "C") == 0 || compName[i].compare(0, 2, "LB") == 0) {
611  if (!openSpacer) {
612  openSpacer = true;
613  geoSpacer.clear();
614  geoSpacer.push_back(compGeo[i]);
615  transfSpacer.clear();
616  transfSpacer.push_back(compTransf[i]);
617  // establish temporary volume size
618  spacerlowXsize = compVol[i]->center().x() - currX;
619  if (compCubBounds) {
620  spaceruppXsize = compCubBounds->halflengthX();
621  // check clash at low edge
622  if (spacerlowXsize < compCubBounds->halflengthX()){
623  ATH_MSG_DEBUG( mv->getLogVol()->getName() << ", spacer low edge - not enough space");
624  }
625  }
626  if (compTrdBounds) {
627  spaceruppXsize = compTrdBounds->halflengthZ();
628  // check clash at low edge
629  if (spacerlowXsize < compTrdBounds->halflengthZ()) {
630  ATH_MSG_DEBUG( mv->getLogVol()->getName() << ", spacer low edge - not enough space");
631  }
632  }
633  } else {
634  geoSpacer.push_back(compGeo[i]);
635  transfSpacer.push_back(compTransf[i]);
636  // check temporary volume size
637  if (compCubBounds) {
638  if (compVol[i]->center().x() - currX < compCubBounds->halflengthX()) {
639  ATH_MSG_DEBUG( mv->getLogVol()->getName() << ", spacer low edge - not enough space");
640  }
641  if (compVol[i]->center().x() + compCubBounds->halflengthX() > currX + spacerlowXsize + spaceruppXsize) {
642  spaceruppXsize += (compVol[i]->center().x() + compCubBounds->halflengthX()) -
643  (currX + spacerlowXsize + spaceruppXsize);
644  }
645  } else if (compTrdBounds) {
646  if (compVol[i]->center().x() - currX < compTrdBounds->halflengthZ()) {
647  ATH_MSG_DEBUG(mv->getLogVol()->getName() << ", spacer low edge - not enough space");
648  }
649  if (compVol[i]->center().x() + compTrdBounds->halflengthZ() > currX + spacerlowXsize + spaceruppXsize) {
650  spaceruppXsize += (compVol[i]->center().x() + compTrdBounds->halflengthZ()) -
651  (currX + spacerlowXsize + spaceruppXsize);
652  }
653  }
654  }
655  comp_processed = true;
656  }
657  if (compName[i].compare(0, 3, "MDT") == 0) {
658  std::unique_ptr<Trk::Volume> mdtVol{};
659  const double dZ = compTrdBounds? compTrdBounds->halflengthZ() : compCubBounds->halflengthX();
660  if (std::abs(lowX - currX) > 0.002) {
661  ATH_MSG_DEBUG( "Mdt volume size does not match the envelope:lowX,currX:"<< lowX << "," << currX);
662  ATH_MSG_DEBUG("adjusting Mdt volume ");
663  }
664  auto mdtBounds = std::make_unique<Trk::TrapezoidVolumeBounds>(envX1, envX2, envY, dZ + 0.5 * (lowX - currX));
665  const double halfZ = mdtBounds->halflengthZ();
666  mdtVol = std::make_unique<Trk::Volume>(makeTransform(Amg::getTranslateZ3D(0.5 * (currX - lowX)) *compVol[i]->transform()),
667  mdtBounds.release());
668  std::unique_ptr<Trk::TrackingVolume> mdtTrkVol{processMdtTrd(*mdtVol, compGeo[i], compTransf[i], cache)};
669  trkVols.push_back(std::move(mdtTrkVol));
670  currX += 2. * halfZ;
671  volSteps.push_back(currX);
672  comp_processed = true;
673  }
674  if (!comp_processed)
675  ATH_MSG_DEBUG(mv->getLogVol()->getName()<< ", unknown technology:" << compName[i]);
676  } // end loop over station children
677 
678  // there may be a spacer still open
679  if (openSpacer) {
680  if (maxX >= currX + spacerlowXsize + spaceruppXsize) {
681  auto spacerBounds = std::make_unique<Trk::TrapezoidVolumeBounds>(envX1, envX2, envY,
682  0.5 * (maxX - currX));
683 
684  Amg::Transform3D spacerTrf = Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2) *
685  Amg::getTranslateZ3D(currX + spacerBounds->halflengthZ());
686  Trk::Volume spacerVol(makeTransform(spacerTrf), spacerBounds.release());
687 
688  std::unique_ptr<Trk::TrackingVolume> spacerTrkVol{processSpacer(spacerVol, geoSpacer, transfSpacer)};
689  trkVols.push_back(std::move(spacerTrkVol));
690  currX = maxX;
691  volSteps.push_back(currX);
692  openSpacer = false;
693  } else {
694  ATH_MSG_DEBUG(mv->getLogVol()->getName() << ", clash in spacer definition (last volume)");
695  }
696  }
697  // create VolumeArray (1DX)
698 
699 
700  std::unique_ptr<Trk::BinUtility> binUtility = std::make_unique<Trk::BinUtility>(volSteps,
703  std::unique_ptr<Trk::TrackingVolumeArray> components{m_trackingVolumeArrayCreator->trapezoidVolumesArrayNav(Muon::release(trkVols),
704  binUtility.release(), false)};
705  return components;
706 }
707 
708 // finalize
710  ATH_MSG_INFO( " finalize() successful");
711  return StatusCode::SUCCESS;
712 }
713 //
714 std::unique_ptr<Trk::TrackingVolume> Muon::MuonStationTypeBuilder::processMdtBox(const Trk::Volume& vol,
715  const GeoVPhysVol* gv,
716  const Amg::Transform3D& transf,
717  double zShift, Cache& cache) const {
718  std::vector<std::unique_ptr<Trk::PlaneLayer>> layers{};
719  std::vector<double> x_array{}, x_ref{}, x_thickness{};
720  std::vector<Trk::MaterialProperties*> x_mat;
721  std::vector<int> x_active;
722  double currX = -100000;
723  // here one could save time by not reading all tubes
724  for (const auto& [cv, transfc] : geoGetVolumes(gv)) {
725  const GeoLogVol* clv = cv->getLogVol();
726  Trk::MaterialProperties* mdtMat = nullptr;
727  double xv{0.};
728  int active{0};
729  if ((clv->getName()).compare(0, 3, "MDT") == 0) {
730  xv = 13.0055; // the half-thickness
731  if (!cache.m_mdtTubeMat) {
732  const GeoTube* tube = dynamic_cast<const GeoTube*>(clv->getShape());
733  if (!tube) {
734  ATH_MSG_ERROR("tube component does not return tube shape");
735  } else {
736  double volume = 8 * (tube->getRMax()) * (tube->getZHalfLength()) * xv;
737  cache.m_mdtTubeMat = std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(cv, volume, 2 * xv));
738  }
739  }
740  mdtMat = cache.m_mdtTubeMat.get();
741  active = 1;
742  }
743  if ((clv->getName()) == "MultiLayerFoam") {
744  xv = decodeX(clv->getShape());
745  for (auto& i : cache.m_mdtFoamMat) {
746  if (std::abs(xv - 0.5 * i->thickness()) < 0.001) {
747  mdtMat = i.get();
748  break;
749  }
750  }
751  if (!mdtMat) {
752  const Trk::CuboidVolumeBounds* cub = dynamic_cast<const Trk::CuboidVolumeBounds*>(&(vol.volumeBounds()));
753  if (!cub) {
754  ATH_MSG_ERROR(__FILE__<<":"<<__LINE__<< " box station component does not return cuboid shape");
755  } else {
756  double volume = 8 * (cub->halflengthY()) * (cub->halflengthZ()) * xv;
757  cache.m_mdtFoamMat.push_back(std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(cv, volume, 2 * xv)));
758  }
759  if (!cache.m_mdtFoamMat.empty())
760  mdtMat = cache.m_mdtFoamMat.back().get();
761  }
762  }
763  if (transfc.translation().x() != currX) {
764  if (x_array.empty() || transfc.translation().x() > x_array.back()) {
765  x_array.push_back(transfc.translation().x());
766  x_mat.push_back(mdtMat);
767  x_thickness.push_back(2 * xv);
768  x_active.push_back(active);
769  currX = transfc.translation().x();
770  if (std::abs(transfc.translation().y()) > 0.001) {
771  // code 2.corrdinate shift
772  double ref = transfc.translation().z() + 1e5;
773  ref += int(1000 * transfc.translation().y()) * 10e6;
774  x_ref.push_back(ref);
775  } else {
776  x_ref.push_back(transfc.translation().z());
777  }
778  } else {
779  std::vector<double>::iterator xIter = x_array.begin();
781  std::vector<double>::iterator tIter = x_thickness.begin();
782  std::vector<double>::iterator rIter = x_ref.begin();
783  std::vector<int>::iterator aIter = x_active.begin();
784  while (transfc.translation().x() > *xIter) {
785  ++xIter;
786  ++mIter;
787  ++rIter;
788  }
789  x_array.insert(xIter, transfc.translation().x());
790  x_mat.insert(mIter, mdtMat);
791  x_thickness.insert(tIter, 2 * xv);
792  x_active.insert(aIter, active);
793  if (std::abs(transfc.translation().y()) > 0.001) {
794  // code 2.corrdinate shift
795  double sign = (transfc.translation().y() > 0.) ? 1. : -1.;
796  double ref = transfc.translation().z() + sign * 1e5;
797  ref += int(1000 * transfc.translation().y()) * 10e6;
798  x_ref.insert(rIter, ref);
799  } else {
800  x_ref.insert(rIter, transfc.translation().z());
801  }
802  currX = transfc.translation().x();
803  }
804  }
805  }
806  // create layers //
807  double thickness{0.};
808  std::unique_ptr<Trk::OverlapDescriptor> od = nullptr;
809  const Trk::CuboidVolumeBounds* volBounds = dynamic_cast<const Trk::CuboidVolumeBounds*>(&(vol.volumeBounds()));
810  double minX{0.};
811  if (volBounds) {
812  double yv = volBounds->halflengthY();
813  double zv = volBounds->halflengthZ();
814  const auto bounds = std::make_shared<Trk::RectangleBounds>(yv, zv);
815  for (unsigned int iloop = 0; iloop < x_array.size(); iloop++) {
816  // x-y plane -> y-z plane
817  thickness = x_thickness[iloop];
818  Amg::Transform3D cTr = transf * Amg::getTranslateX3D(x_array[iloop]) *
819  Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2);
820 
821  if (!x_mat[iloop]) {
822  ATH_MSG_WARNING("Undefined MDT layer material");
823  }
824  Trk::MaterialProperties matLay = x_mat[iloop] ? *(x_mat[iloop])
825  : Trk::MaterialProperties(*m_muonMaterial, thickness);
826  Trk::HomogeneousLayerMaterial mdtMaterial(matLay, 0.);
827  auto layer = std::make_unique<Trk::PlaneLayer>(cTr, bounds, mdtMaterial, thickness, std::move(od));
828  layer->setRef(x_ref[iloop] - zShift);
829  // make preliminary identification of active layers
830  layer->setLayerType(x_active[iloop]);
831  layers.push_back(std::move(layer));
832  }
833  // fix lower and upper bound of step vector to volume boundary
834  minX = transf.translation().x() - volBounds->halflengthX();
835  }
836  // create the BinnedArray
837  std::vector<Trk::SharedObject<Trk::Layer>> layerOrder;
838  std::vector<float> binSteps;
839  // check if additional (navigation) layers needed
840 
841  binSteps.push_back(minX);
842  if (!layers.empty()) {
843  currX = minX;
844  for (unsigned int i = 0; i < layers.size(); ++i) {
845  const Amg::Transform3D ltransf = layers[i]->transform();
846  if (i < layers.size() - 1) {
847  currX = ltransf.translation().x() + 0.5 * layers[i]->thickness();
848  binSteps.push_back(currX);
849  }
850  layerOrder.emplace_back(std::move(layers[i]));
851  }
852  binSteps.push_back(transf.translation().x() + volBounds->halflengthX());
853  }
854  layers.clear();
855 
856  auto binUtility = std::make_unique<Trk::BinUtility>(binSteps, Trk::BinningOption::open, Trk::BinningValue::binX);
857 
858  auto mdtLayerArray = std::make_unique<Trk::NavBinnedArray1D<Trk::Layer>>(layerOrder,
859  binUtility.release(),
860  makeTransform(Amg::Transform3D::Identity()));
861 
862  return std::make_unique<Trk::TrackingVolume>(vol, *m_muonMaterial, mdtLayerArray.release(), nullptr, "MDT");
863 
864 }
865 //
866 std::unique_ptr<Trk::TrackingVolume>
868  const GeoVPhysVol* gv,
869  const Amg::Transform3D& transf,
870  Cache& cache) const {
871 
872  std::vector<std::unique_ptr<Trk::PlaneLayer>> layers{};
873  std::vector<double> x_array{},x_thickness{},x_ref{};
874  std::vector<Trk::MaterialProperties*> x_mat{};
875  std::vector<int> x_active;
876  double currX = -100000;
877  for ( const auto& [cv, transfc]: geoGetVolumes(gv)) {
878  const GeoLogVol* clv = cv->getLogVol();
879  double xv{0.};
880  int active{0};
881  if (clv->getShape()->type() == "Trd") {
882  const GeoTrd* trd = dynamic_cast<const GeoTrd*>(clv->getShape());
883  double x1v = trd->getXHalfLength1();
884  double x2v = trd->getXHalfLength2();
885  if (x1v == x2v)
886  xv = x1v;
887  }
888  Trk::MaterialProperties* mdtMat = nullptr;
889  if ((clv->getName()).compare(0, 3, "MDT") == 0) {
890  xv = 13.0055; // the half-thickness
891  if (!cache.m_mdtTubeMat) {
892  const GeoTube* tube = dynamic_cast<const GeoTube*>(clv->getShape());
893  double volume = 8 * (tube->getRMax()) * (tube->getZHalfLength()) * xv;
894  cache.m_mdtTubeMat = std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(cv, volume, 2 * xv));
895  }
896  mdtMat = cache.m_mdtTubeMat.get();
897  active = 1;
898  }
899  if ((clv->getName()) == "MultiLayerFoam") {
900  xv = decodeX(clv->getShape());
901  for (auto& i : cache.m_mdtFoamMat) {
902  if (std::abs(xv - 0.5 * i->thickness()) < 0.001) {
903  mdtMat = i.get();
904  break;
905  }
906  }
907  if (!mdtMat) {
908  const Trk::TrapezoidVolumeBounds* trd = dynamic_cast<const Trk::TrapezoidVolumeBounds*>(&(vol.volumeBounds()));
909  // check return to comply with coverity
910  if (!trd) {
911  ATH_MSG_ERROR("trd station component does not return trapezoid shape");
912  }
913  double volume = 4 * (trd->minHalflengthX() + trd->maxHalflengthX()) * (trd->halflengthY()) * xv;
914  cache.m_mdtFoamMat.push_back(std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(cv, volume, 2 * xv)));
915  mdtMat = cache.m_mdtFoamMat.back().get();
916  }
917  }
918 
919  if (transfc.translation().x() != currX) {
920  if (x_array.empty() || transfc.translation().x() > x_array.back()) {
921  x_array.push_back(transfc.translation().x());
922  x_mat.push_back(mdtMat);
923  x_thickness.push_back(2 * xv);
924  x_ref.push_back(transfc.translation().z());
925  currX = transfc.translation().x();
926  x_active.push_back(active);
927  } else {
928  std::vector<double>::iterator xIter = x_array.begin();
930  std::vector<double>::iterator tIter = x_thickness.begin();
931  std::vector<double>::iterator rIter = x_ref.begin();
932  std::vector<int>::iterator aIter = x_active.begin();
933  while (transfc.translation().x() > *xIter) {
934  ++xIter;
935  ++mIter;
936  ++rIter;
937  }
938  x_array.insert(xIter, transfc.translation().x());
939  x_mat.insert(mIter, mdtMat);
940  x_thickness.insert(tIter, 2 * xv);
941  x_ref.insert(rIter, transfc.translation().z());
942  x_active.insert(aIter, active);
943  currX = transfc.translation().x();
944  }
945  }
946  }
947  // create layers //
948  double thickness{0.};
949  std::unique_ptr<Trk::OverlapDescriptor> od = nullptr;
950  const Trk::TrapezoidVolumeBounds* volBounds = dynamic_cast<const Trk::TrapezoidVolumeBounds*>(&(vol.volumeBounds()));
951  if (!volBounds) {
952  return nullptr;
953  }
954 
955  double x1v = volBounds->minHalflengthX();
956  double x2v = volBounds->maxHalflengthX();
957  double yv = volBounds->halflengthY();
958  // x-y plane -> y-z plane
959  auto bounds = std::make_shared<const Trk::TrapezoidBounds>(x1v, x2v, yv);
960  for (unsigned int iloop = 0; iloop < x_array.size(); iloop++) {
961  thickness = x_thickness[iloop];
962  if (!x_mat[iloop]) {
963  ATH_MSG_WARNING("Undefined MDT layer material");
964  }
965  Trk::MaterialProperties matLay = x_mat[iloop] ? *(x_mat[iloop])
966  : Trk::MaterialProperties(*m_muonMaterial, thickness);
967  Trk::HomogeneousLayerMaterial mdtMaterial(matLay, 0.);
968  Amg::Transform3D cTr = transf * Amg::getTranslateZ3D( x_array[iloop]);
969  auto layer = std::make_unique<Trk::PlaneLayer>(cTr, bounds, mdtMaterial, thickness, std::move(od));
970  // make preliminary identification of active layers
971  layer->setLayerType(x_active[iloop]);
972  layer->setRef(x_ref[iloop]);
973  layers.push_back(std::move(layer));
974  }
975 
976  // create the BinnedArray
977  std::vector<Trk::SharedObject<Trk::Layer>> layerOrder;
978  std::vector<float> binSteps;
979  //
980  double minX = transf.translation().x() - volBounds->halflengthZ();
981  binSteps.push_back(minX);
982  if (!layers.empty()) {
983  currX = minX;
984  for (unsigned int i = 0; i < layers.size(); ++i) {
985  const Amg::Transform3D ltransf = layers[i]->transform();
986  if (i < layers.size() - 1) {
987  currX = ltransf.translation().x() + 0.5 * layers[i]->thickness();
988  binSteps.push_back(currX);
989  }
990  layerOrder.emplace_back(std::move(layers[i]));
991  }
992  binSteps.push_back(transf.translation().x() + volBounds->halflengthZ());
993  }
994  auto binUtility = std::make_unique<Trk::BinUtility>(binSteps, Trk::BinningOption::open, Trk::BinningValue::binX);
995  auto mdtLayerArray = std::make_unique<Trk::NavBinnedArray1D<Trk::Layer>>(layerOrder, binUtility.release(),
996  makeTransform(Amg::Transform3D::Identity()));
997 
998  return std::make_unique<Trk::TrackingVolume>(vol, *m_muonMaterial, mdtLayerArray.release(), nullptr, "MDT");
999 
1000 }
1001 std::unique_ptr<Trk::TrackingVolume> Muon::MuonStationTypeBuilder::processRpc(const Trk::Volume& vol,
1002  const std::vector<const GeoVPhysVol*>& gv,
1003  const std::vector<Amg::Transform3D>& transfc, Cache& cache) const {
1004  // layers correspond to DedModules and RpcModules; all substructures
1005  // averaged in material properties
1006  std::vector<std::unique_ptr<Trk::Layer>> layers{};
1007  for (unsigned int ic = 0; ic < gv.size(); ++ic) {
1008  const GeoLogVol* glv = gv[ic]->getLogVol();
1009  const GeoShape* shape = glv->getShape();
1010  if (shape->type() != "Box" && shape->type() != "Trd") {
1011  const GeoShapeSubtraction* sub = dynamic_cast<const GeoShapeSubtraction*>(shape);
1012  const GeoShape* subt = nullptr;
1013  while (sub) {
1014  subt = sub->getOpA();
1015  sub = dynamic_cast<const GeoShapeSubtraction*>(subt);
1016  }
1017  shape = subt;
1018  }
1019  if (shape && shape->type() == "Box") {
1020  const GeoBox* box = dynamic_cast<const GeoBox*>(shape);
1021  double xs = box->getXHalfLength();
1022  double ys = box->getYHalfLength();
1023  double zs = box->getZHalfLength();
1024  // translating into layer; x dimension defines thickness
1025  double thickness = 2 * xs;
1026  std::unique_ptr<Trk::OverlapDescriptor> od = nullptr;
1027  auto bounds = std::make_shared<const Trk::RectangleBounds>(ys, zs);
1028  Amg::Transform3D cTr = transfc[ic] * Amg::getRotateY3D(M_PI_2) *Amg::getRotateZ3D(M_PI_2);
1029  Trk::MaterialProperties rpcMat(0., 10.e10, 10.e10, 13., 26., 0.);
1030  if (glv->getName().compare(0, 3, "Ded") == 0) {
1031  // find if material exists already
1032  bool found = false;
1033  for (auto& i : cache.m_rpcDed) {
1034  if (std::abs(thickness - i->thickness()) < 0.001) {
1035  rpcMat = Trk::MaterialProperties(*i);
1036  found = true;
1037  break;
1038  }
1039  }
1040  if (!found) {
1041  double volc = 8 * xs * ys * zs;
1042  cache.m_rpcDed.push_back(std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(gv[ic], volc, 2 * xs)));
1043  rpcMat = Trk::MaterialProperties(*cache.m_rpcDed.back());
1044  }
1045  } else {
1047  if (std::abs(thickness - 46.0) < 0.001) {
1048  if (!cache.m_rpc46) {
1049  double volc = 8 * xs * ys * zs;
1050  cache.m_rpc46 = std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(gv[ic], volc, 2 * xs));
1051  }
1052  rpcMat = Trk::MaterialProperties(*cache.m_rpc46);
1053  } else {
1054  ATH_MSG_WARNING( "RPC module thickness different from 46: "<< thickness);
1055  }
1056  }
1057 
1058  Trk::HomogeneousLayerMaterial rpcMaterial(rpcMat, 0.);
1059  auto layer = std::make_unique<Trk::PlaneLayer>(cTr, bounds, rpcMaterial, thickness, std::move(od));
1060 
1061  // make preliminary identification of active layers
1062  if ((glv->getName()).compare(0, 3, "Ded") != 0) {
1063  layer->setLayerType(1);
1064  } else {
1065  layer->setLayerType(0);
1066  }
1067  layers.push_back(std::move(layer));
1068  } else if (shape && shape->type() == "Trd") {
1069  const GeoTrd* trd = dynamic_cast<const GeoTrd*>(shape);
1070  double xs1 = trd->getXHalfLength1();
1071  double xs2 = trd->getXHalfLength2();
1072  double ys1 = trd->getYHalfLength1();
1073  double ys2 = trd->getYHalfLength2();
1074  double zs = trd->getZHalfLength();
1075  // translating into layer; x dimension defines thickness
1076  if (xs1 == xs2 && ys1 == ys2) {
1077  double thickness = 2 * xs1;
1078  std::unique_ptr<Trk::OverlapDescriptor> od = nullptr;
1079  auto bounds = std::make_shared<const Trk::RectangleBounds>(ys1, zs);
1080  Amg::Transform3D cTr = transfc[ic] * Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2);
1081  Trk::MaterialProperties rpcMat(0., 10.e10, 10.e10, 13., 26., 0.); // default
1082  if ((glv->getName()).compare(0, 3, "Ded") == 0) {
1083  // find if material exists already
1084  bool found = false;
1085  for (auto& i : cache.m_rpcDed) {
1086  if (std::abs(thickness - i->thickness()) < 0.001) {
1087  rpcMat = Trk::MaterialProperties(*i);
1088  found = true;
1089  break;
1090  }
1091  }
1092  if (!found) {
1093  double volc = 8 * xs1 * ys1 * zs;
1094  cache.m_rpcDed.push_back(std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(gv[ic], volc, 2 * xs1)));
1095  rpcMat = Trk::MaterialProperties(*cache.m_rpcDed.back());
1096  }
1097  // create Ded layer
1098  Trk::HomogeneousLayerMaterial rpcMaterial(rpcMat, 0.);
1099  auto layer = std::make_unique<Trk::PlaneLayer>(cTr, bounds, rpcMaterial, thickness, std::move(od));
1100  layer->setLayerType(0);
1101  layers.push_back(std::move(layer));
1102  } else {
1103  // RPC layer; step one level below to resolve strip planes
1104  unsigned int ngc = gv[ic]->getNChildVols();
1105  for (unsigned int igc = 0; igc < ngc; igc++) {
1106  Amg::Transform3D trgc(Amg::Transform3D::Identity());
1107  if (transfc[ic].rotation().isIdentity())
1108  trgc = gv[ic]->getXToChildVol(igc);
1109  else
1110  trgc = Amg::getRotateZ3D(M_PI) * gv[ic]->getXToChildVol(igc);
1111 
1112  const GeoVPhysVol* gcv = gv[ic]->getChildVol(igc);
1113  const GeoLogVol* gclv = gcv->getLogVol();
1114  const GeoShape* lshape = gclv->getShape();
1115  while (lshape->type() == "Subtraction") {
1116  const GeoShapeSubtraction* sub = dynamic_cast<const GeoShapeSubtraction*>(lshape);
1117  lshape = sub->getOpA();
1118  }
1119  const GeoTrd* gtrd = dynamic_cast<const GeoTrd*>(lshape);
1120  double gx = gtrd->getXHalfLength1();
1121  double gy = gtrd->getYHalfLength1();
1122  double gz = gtrd->getZHalfLength();
1123 
1124  if ((gclv->getName()).compare(0, 6, "RPC_AL") == 0) {
1125  if (std::abs(gx - 5.0) < 0.001) {
1126  if (!cache.m_rpcExtPanel) {
1127  double volc = 8 * gx * gy * gz;
1128  cache.m_rpcExtPanel =
1129  std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(gcv, volc, 2 * gx));
1130  }
1131  rpcMat = Trk::MaterialProperties(*cache.m_rpcExtPanel);
1132  } else if (std::abs(gx - 4.3) < 0.001) {
1133  if (!cache.m_rpcMidPanel) {
1134  double volc = 8 * gx * gy * gz;
1135  cache.m_rpcMidPanel =
1136  std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(gcv, volc, 2 * gx));
1137  }
1138  rpcMat = Trk::MaterialProperties(*cache.m_rpcMidPanel);
1139  } else {
1140  ATH_MSG_WARNING("unknown RPC panel:" << gx);
1141  }
1142  // create Rpc panel layers
1143  thickness = 2 * gx;
1144  Trk::HomogeneousLayerMaterial rpcMaterial(rpcMat, 0.);
1145  auto layer = std::make_unique<Trk::PlaneLayer>(Amg::getTranslate3D(trgc.translation()) *cTr,
1146  bounds, rpcMaterial, thickness, std::move(od));
1147  layer->setLayerType(0);
1148  layers.push_back(std::move(layer));
1149  } else if ((gclv->getName()) == "Rpclayer") {
1150  // two thicknesses allowed for 2/3 gaps RPCs
1151  if (std::abs(gx - 6.85) > 0.001 && std::abs(gx - 5.9) > 0.001) {
1152  ATH_MSG_WARNING("processRpc() - unusual thickness of RPC ("<< glv->getName()<< ") layer :" << 2 * gx);
1153  }
1154  if (!cache.m_rpcLayer) {
1155  double volc = 8 * gx * gy * gz;
1156  cache.m_rpcLayer =
1157  std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(gcv, volc, 2 * gx));
1158  }
1159  rpcMat = Trk::MaterialProperties(*cache.m_rpcLayer);
1160  // define 1 layer for 2 strip planes
1161  thickness = 2 * gx;
1162  Trk::HomogeneousLayerMaterial rpcMaterial(rpcMat, 0.);
1163  auto layer = std::make_unique<Trk::PlaneLayer>(Amg::getTranslate3D(trgc.translation()) *cTr,
1164  bounds, rpcMaterial, thickness, std::move(od));
1165  layer->setLayerType(1);
1166  layers.push_back(std::move(layer));
1167  } else {
1168  ATH_MSG_WARNING( "unknown RPC component? " << gclv->getName());
1169  }
1170  }
1171  }
1172  } else {
1173  ATH_MSG_WARNING("RPC true trapezoid layer, not coded yet");
1174  }
1175  } else {
1176  ATH_MSG_WARNING( "RPC layer shape not recognized");
1177  }
1178  } // end loop over Modules
1179 
1180  ATH_MSG_DEBUG(" Rpc component volume processed with" << layers.size()<< " layers");
1181  auto rpcLayers = std::make_unique<std::vector<Trk::Layer*>>(Muon::release(layers));
1182  return std::make_unique<Trk::TrackingVolume>(vol, *m_muonMaterial, rpcLayers.release(), "RPC");
1183 }
1184 //
1185 
1186 std::unique_ptr<Trk::TrackingVolume> Muon::MuonStationTypeBuilder::processSpacer(const Trk::Volume& vol,
1187  std::vector<const GeoVPhysVol*> gv,
1188  std::vector<Amg::Transform3D> transf) const {
1189  // spacers: one level below, assumed boxes
1190  std::vector<std::unique_ptr<Trk::Layer>> layers{};
1191  // resolve child volumes
1192  // Don't use iterators; they'll be invalidated by the push_back's.
1193  size_t idx{0};
1194  while (idx < gv.size()) {
1195  const GeoVPhysVol* vol = gv[idx];
1196  const Amg::Transform3D& tf = transf[idx];
1197  if (vol->getNChildVols()) {
1198  for (unsigned int ich = 0; ich < vol->getNChildVols(); ++ich) {
1199  gv.push_back(vol->getChildVol(ich));
1200  transf.emplace_back(tf * vol->getXToChildVol(ich));
1201  }
1202  gv.erase(gv.begin() + idx);
1203  transf.erase(transf.begin() + idx);
1204  } else {
1205  ++idx;
1206  }
1207  }
1208  // translate into layers
1209  for (unsigned int ic = 0; ic < gv.size(); ++ic) {
1210  const GeoLogVol* clv = gv[ic]->getLogVol();
1211  Trk::Material cmat = m_materialConverter.convert(clv->getMaterial());
1212  ATH_MSG_VERBOSE(" spacer material all X0 "
1213  << cmat.X0 << " L0 " << cmat.L0 << " A " << cmat.A
1214  << " Z " << cmat.Z << " rho " << cmat.rho);
1215  if (clv->getShape()->type() == "Box") {
1216  const GeoBox* box = dynamic_cast<const GeoBox*>(clv->getShape());
1217  double xs = box->getXHalfLength();
1218  double ys = box->getYHalfLength();
1219  double zs = box->getZHalfLength();
1220  // translating into layer; find minimal size
1222  double thickness{0.};
1223  Amg::Transform3D cTr{Amg::Transform3D::Identity()};
1224  if (zs <= xs && zs <= ys) { // x-y plane
1225  bounds = std::make_shared<const Trk::RectangleBounds>(xs, ys);
1226  thickness = 2 * zs;
1227  cTr = transf[ic];
1228  } else if (xs <= ys && xs <= zs) { // x-y plane -> y-z plane
1229  bounds = std::make_shared<Trk::RectangleBounds>(ys, zs);
1230  thickness = 2 * xs;
1231  cTr = transf[ic] * Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2);
1232  } else { // x-y plane -> x-z plane
1233  bounds = std::make_shared<Trk::RectangleBounds>(xs, zs);
1234  thickness = 2 * ys;
1235  cTr = transf[ic] * Amg::getRotateX3D(M_PI_2);
1236  }
1237  Trk::MaterialProperties material(thickness, cmat.X0, cmat.L0, cmat.A, cmat.Z, cmat.rho);
1238  Trk::HomogeneousLayerMaterial spacerMaterial(material, 0.);
1239 
1240  auto layer = std::make_unique<Trk::PlaneLayer>(cTr, bounds, spacerMaterial, thickness, nullptr, 0);
1241  layers.push_back(std::move(layer));
1242  } else if (clv->getShape()->type() == "Subtraction") {
1243  const GeoShapeSubtraction* sub =
1244  dynamic_cast<const GeoShapeSubtraction*>(clv->getShape());
1245  if (sub && sub->getOpA()->type() == "Box" && sub->getOpB()->type() == "Box") {
1246  // LB
1247  const GeoBox* boxA = dynamic_cast<const GeoBox*>(sub->getOpA());
1248  const GeoBox* boxB = dynamic_cast<const GeoBox*>(sub->getOpB());
1249  auto bounds = std::make_shared<const Trk::RectangleBounds>(boxA->getYHalfLength(), boxA->getZHalfLength());
1250  double thickness = (boxA->getXHalfLength() - boxB->getXHalfLength());
1251  double shift = 0.5 * (boxA->getXHalfLength() + boxB->getXHalfLength());
1252  Trk::MaterialProperties material(0., 10.e10, 10.e10, 13., 26., 0.);
1253  Trk::HomogeneousLayerMaterial spacerMaterial;
1254  if (thickness > 0.) {
1255  material = Trk::MaterialProperties( thickness, cmat.X0, cmat.L0, cmat.A, cmat.Z, cmat.rho);
1256  spacerMaterial = Trk::HomogeneousLayerMaterial(material, 0.);
1257 
1258  auto layx = std::make_unique<Trk::PlaneLayer>(transf[ic] * Amg::getTranslateX3D(shift) *
1259  Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2),
1260  bounds, spacerMaterial, thickness, nullptr, 0);
1261  layers.push_back(std::move(layx));
1262  auto layxx = std::make_unique<Trk::PlaneLayer>(transf[ic] * Amg::getTranslateX3D(-shift) *
1263  Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2),
1264  bounds, spacerMaterial, thickness, nullptr, 0);
1265  layers.push_back(std::move(layxx));
1266  }
1267  thickness = (boxA->getYHalfLength() - boxB->getYHalfLength());
1268  if (thickness > 0.) {
1269  material = Trk::MaterialProperties( thickness, cmat.X0, cmat.L0, cmat.A, cmat.Z, cmat.rho);
1270  spacerMaterial = Trk::HomogeneousLayerMaterial(material, 0.);
1271  shift = 0.5 * (boxA->getYHalfLength() + boxB->getYHalfLength());
1272  bounds = std::make_shared<const Trk::RectangleBounds>(boxB->getXHalfLength(), boxA->getZHalfLength());
1273  auto lay = std::make_unique<Trk::PlaneLayer>(transf[ic] * Amg::getTranslateY3D(shift) * Amg::getRotateX3D(M_PI_2),
1274  bounds, spacerMaterial, thickness, nullptr, 0);
1275  layers.push_back(std::move(lay));
1276 
1277  auto layy = std::make_unique<Trk::PlaneLayer>(transf[ic] * Amg::getTranslateY3D(-shift) * Amg::getRotateX3D(M_PI_2),
1278  bounds, spacerMaterial, thickness, nullptr, 0);
1279 
1280  layers.push_back(std::move(layy));
1281  }
1282  thickness = (boxA->getZHalfLength() - boxB->getZHalfLength());
1283  if (thickness > 0.) {
1284  material = Trk::MaterialProperties(thickness, cmat.X0, cmat.L0, cmat.A, cmat.Z, cmat.rho);
1285  spacerMaterial =Trk::HomogeneousLayerMaterial(material, 0.);
1286  shift = 0.5 * (boxA->getZHalfLength() + boxB->getZHalfLength());
1287  bounds = std::make_shared<const Trk::RectangleBounds>(boxB->getXHalfLength(), boxB->getYHalfLength());
1288  auto layz = std::make_unique<Trk::PlaneLayer>(transf[ic] * Amg::getTranslateZ3D(shift),
1289  bounds, spacerMaterial, thickness, nullptr, 0);
1290  layers.push_back(std::move(layz));
1291 
1292  auto layzz = std::make_unique<Trk::PlaneLayer>(transf[ic] * Amg::getTranslateZ3D(-shift),
1293  bounds, spacerMaterial, thickness, nullptr, 0);
1294  layers.push_back(std::move(layzz));
1295  }
1296  } else if (sub) {
1297  std::vector<std::pair<const GeoShape*, Amg::Transform3D>> subVs;
1298  const GeoShapeShift* shift = dynamic_cast<const GeoShapeShift*>(sub->getOpB());
1299  if (shift)
1300  subVs.emplace_back(shift->getOp(), shift->getX());
1301  const GeoShape* shape = sub->getOpA();
1302  while (shape->type() == "Subtraction") {
1303  const GeoShapeSubtraction* subtr = dynamic_cast<const GeoShapeSubtraction*>(shape);
1304  const GeoShapeShift* shift = dynamic_cast<const GeoShapeShift*>(subtr->getOpB());
1305  if (shift)
1306  subVs.emplace_back(shift->getOp(), shift->getX());
1307  shape = subtr->getOpA();
1308  }
1309  const GeoBox* box = dynamic_cast<const GeoBox*>(shape);
1310  if (box && subVs.size() == 4) {
1311  std::unique_ptr<Trk::Volume> v1{}, v2{};
1312  std::unique_ptr<Trk::VolumeExcluder> volExcl = nullptr;
1313  const GeoBox* sb1 = dynamic_cast<const GeoBox*>(subVs[0].first);
1314  if (sb1) {
1315  v1 = std::make_unique<Trk::Volume>(makeTransform(subVs[0].second),
1316  m_geoShapeConverter.convert(sb1).release());
1317  }
1318  const GeoBox* sb2 = dynamic_cast<const GeoBox*>(subVs[1].first);
1319  if (sb2) {
1320  v2 = std::make_unique<Trk::Volume>(makeTransform(subVs[1].second),
1321  m_geoShapeConverter.convert(sb2).release());
1322  }
1323  const GeoBox* boxB = dynamic_cast<const GeoBox*>(subVs[2].first);
1324  if (boxB && v1 && v2) {
1325  auto bounds = std::make_shared<const Trk::RectangleBounds>(box->getYHalfLength(), box->getZHalfLength());
1326  double thickness = (box->getXHalfLength() - boxB->getXHalfLength());
1327  double shift{0.5 * (box->getXHalfLength() + boxB->getXHalfLength())};
1328  auto combinedBounds = std::make_unique<Trk::CombinedVolumeBounds>(v1.release(), v2.release(), false);
1329  auto cVol = std::make_unique<Trk::Volume>(makeTransform(Amg::getTranslateX3D(-shift)),
1330  combinedBounds.release());
1331  volExcl = std::make_unique<Trk::VolumeExcluder>(cVol->clone());
1332  Trk::PlaneSurface surf{transf[ic] * Amg::getTranslateX3D(shift) * Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2), bounds};
1333  auto subPlane = std::make_unique<Trk::SubtractedPlaneSurface>(std::move(surf), volExcl.release(), false);
1334  auto subPlaneX = std::make_unique<Trk::SubtractedPlaneSurface>(*subPlane, Amg::getTranslateX3D(-2 * shift));
1335 
1336  Trk::MaterialProperties material(thickness, cmat.X0, cmat.L0, cmat.A, cmat.Z, cmat.rho);
1337  Trk::HomogeneousLayerMaterial spacerMaterial(material, 0.);
1338 
1339  auto layx = std::make_unique<Trk::SubtractedPlaneLayer>(subPlane.get(), spacerMaterial, thickness, nullptr, 0);
1340  layers.push_back(std::move(layx));
1341 
1342  auto layxx = std::make_unique<Trk::SubtractedPlaneLayer>(subPlaneX.get(), spacerMaterial, thickness, nullptr, 0);
1343  layers.push_back(std::move(layxx));
1344 
1345  bounds = std::make_shared<const Trk::RectangleBounds>( boxB->getXHalfLength(), box->getZHalfLength());
1346  thickness = subVs[2].second.translation().mag();
1347 
1348 
1349  auto volEx = std::make_unique<Trk::VolumeExcluder>(std::make_unique<Trk::Volume>(*cVol, Amg::getTranslateX3D(2 * shift)).release());
1350 
1351  surf = Trk::PlaneSurface{transf[ic] * Amg::getRotateX3D(M_PI_2), bounds};
1352  auto subPlaneBis = std::make_unique<Trk::SubtractedPlaneSurface>(std::move(surf), volEx.release(), false);
1353  material = Trk::MaterialProperties(thickness, cmat.X0, cmat.L0, cmat.A, cmat.Z, cmat.rho);
1354  spacerMaterial = Trk::HomogeneousLayerMaterial(material, 0.);
1355  auto lay = std::make_unique<Trk::SubtractedPlaneLayer>(subPlaneBis.get(), spacerMaterial, thickness, nullptr, 0);
1356  layers.push_back(std::move(lay));
1357  }
1358  }
1359  } else {
1360  ATH_MSG_DEBUG(clv->getName() << ", unresolved spacer component " << clv->getName());
1361  }
1362  } else {
1363  ATH_MSG_DEBUG(clv->getName() << ", unresolved spacer component " << clv->getName());
1364  }
1365  }
1366 
1367  std::vector<std::unique_ptr<Trk::Layer>>::iterator lIt = layers.begin();
1368  for (; lIt != layers.end(); ++lIt)
1369  if ((*lIt)->thickness() < 0.)
1370  lIt = layers.erase(lIt);
1371 
1372  auto spacerLayers = std::make_unique<std::vector<Trk::Layer*>>(Muon::release(layers));
1373  auto spacer = std::make_unique<Trk::TrackingVolume>(vol, *m_muonMaterial, spacerLayers.release(), "Spacer");
1374 
1375  if (!m_resolveSpacer) { // average into a single material layer
1376  ATH_MSG_VERBOSE(" !m_resolveSpacer createLayerRepresentation ");
1377  auto laySpacer = createLayerRepresentation(*spacer);
1378  laySpacer.first->setLayerType(0);
1379  layers.clear();
1380  layers.push_back(std::move(laySpacer.first));
1381  auto spacerLays = std::make_unique<std::vector<Trk::Layer*>>(Muon::release(layers));
1382  spacer = std::make_unique<Trk::TrackingVolume>(vol, *m_muonMaterial, spacerLays.release(), "Spacer");
1383  }
1384 
1385  return spacer;
1386 }
1387 
1388 std::unique_ptr<Trk::TrackingVolume> Muon::MuonStationTypeBuilder::processCscStation(const GeoVPhysVol* mv,
1389  const std::string& name,
1390  Cache& cache) const {
1391  // CSC stations have the particularity of displacement in Z between
1392  // multilayer and the spacer - the envelope
1393  // has to be derived from the component volume shape and component
1394  // displacement
1395  bool isDiamond = false;
1396  double xMin{0.}, xMed{0.}, xMax{0}, y1{0.}, y2{0}, z{0.};
1397  // find the shape and dimensions for the first component
1398  const GeoVPhysVol* cv = &(*(mv->getChildVol(0)));
1399  const GeoLogVol* clv = cv->getLogVol();
1400  // Amg::Transform3D transform =
1401  // Amg::CLHEPTransformToEigen(mv->getXToChildVol(0));
1402  if (clv->getShape()->type() == "Shift") {
1403  const GeoShapeShift* shift =
1404  dynamic_cast<const GeoShapeShift*>(clv->getShape());
1405  if (shift->getOp()->type() == "Union") {
1406  // that would be the union making the diamond/double trapezoid
1407  // shape, let's retrieve the parameters
1408  isDiamond = true;
1409  const GeoShapeUnion* uni = dynamic_cast<const GeoShapeUnion*>(shift->getOp());
1410  if (uni->getOpA()->type() == "Trd") {
1411  const GeoTrd* trdA = dynamic_cast<const GeoTrd*>(uni->getOpA());
1412  xMin = trdA->getYHalfLength1();
1413  xMed = trdA->getYHalfLength2();
1414  y1 = trdA->getZHalfLength();
1415  z = trdA->getXHalfLength1();
1416  }
1417  if (uni->getOpB()->type() == "Shift") {
1418  const GeoShapeShift* sh = dynamic_cast<const GeoShapeShift*>(uni->getOpB());
1419  const GeoTrd* trdB = dynamic_cast<const GeoTrd*>(sh->getOp());
1420  if (trdB->getYHalfLength1() != xMed || trdB->getXHalfLength1() != z) {
1421  ATH_MSG_DEBUG(mv->getLogVol()->getName() <<
1422  ": something is wrong: dimensions of 2 trapezoids do not match");
1423  }
1424  xMax = trdB->getYHalfLength2();
1425  y2 = trdB->getZHalfLength();
1426  }
1427  } // end Union
1428  if (shift->getOp()->type() == "Trd") {
1429  // that would be the trapezoid shape, let's retrieve the parameters
1430  const GeoTrd* trd = dynamic_cast<const GeoTrd*>(shift->getOp());
1431  xMin = trd->getYHalfLength1();
1432  xMed = trd->getYHalfLength2();
1433  y1 = trd->getZHalfLength();
1434  z = trd->getXHalfLength1();
1435  } // end Trd
1436  } else {
1437  if (clv->getShape()->type() == "Trd") {
1438  // that would be the trapezoid shape, let's retrieve the parameters
1439  const GeoTrd* trd = dynamic_cast<const GeoTrd*>(clv->getShape());
1440  xMin = trd->getYHalfLength1();
1441  xMed = trd->getYHalfLength2();
1442  y1 = trd->getZHalfLength();
1443  z = trd->getXHalfLength1();
1444  }
1445  }
1446  // then loop over all components to get total Xsize & transforms
1447  std::vector<Amg::Transform3D> compTransf;
1448  std::vector<std::string> compName;
1449  std::vector<const GeoVPhysVol*> compGeoVol;
1450  std::vector<double> xSizes;
1451  double xmn = +10000.;
1452  double xmx = -10000.;
1453  for (const auto& [cv, transform]: geoGetVolumes(mv)) {
1454  const GeoLogVol* clv = cv->getLogVol();
1455  unsigned int ich = compTransf.size();
1456  compTransf.push_back(transform);
1457  compName.push_back(clv->getName());
1458  compGeoVol.push_back(cv);
1459  if (clv->getShape()->type() == "Shift") {
1460  const GeoShapeShift* shift = dynamic_cast<const GeoShapeShift*>(clv->getShape());
1461  if (shift->getOp()->type() == "Union") {
1462  // that would be the union making the diamond/double trapezoid
1463  // shape, let's retrieve the parameters
1464  const GeoShapeUnion* uni = dynamic_cast<const GeoShapeUnion*>(shift->getOp());
1465  if (uni->getOpA()->type() == "Trd") {
1466  const GeoTrd* trdA = dynamic_cast<const GeoTrd*>(uni->getOpA());
1467  double xSize = trdA->getXHalfLength1();
1468  if (!xSizes.empty()){
1469  xSizes.push_back((std::abs(transform.translation().x() - compTransf[ich - 1].translation().x()) - xSizes.back()));
1470  } else {
1471  xSizes.push_back(xSize);
1472  }
1473  double xpos = (transform * shift->getX()).translation().x();
1474  xmn = std::min(xmn, xpos - xSizes.back());
1475  xmx = std::max(xmx, xpos + xSizes.back());
1476  }
1477  } // end Union
1478  } // end Shift
1479  if (clv->getShape()->type() == "Trd") {
1480  const GeoTrd* trd = dynamic_cast<const GeoTrd*>(clv->getShape());
1481  double xSize = trd->getXHalfLength1();
1482  if (!xSizes.empty()) {
1483  xSizes.push_back( std::abs(transform.translation().x() - compTransf[ich - 1].translation().x()) - xSizes.back());
1484  } else {
1485  xSizes.push_back(xSize);
1486  }
1487  double xpos = transform.translation().x();
1488  xmn = std::min(xmn, xpos - xSizes.back());
1489  xmx = std::max(xmx, xpos + xSizes.back());
1490  } // end Trd
1491  }
1492  // this should be enough to build station envelope
1493  double xTotal{0.};
1494  for (double xSize : xSizes)
1495  xTotal += xSize;
1496  double xShift{0.5 * (xmx + xmn)}, zShift{0.};
1497  zShift = std::abs(compTransf.front().translation().z()) + std::abs(compTransf.back().translation().z());
1498  // calculate displacement with respect to GeoModel station volume
1499  // one way or the other, the station envelope is double trapezoid
1500  std::unique_ptr<Trk::Volume> envelope;
1501  double envXMed = xMed;
1502  double envY1 = y1;
1503  double envY2 = y2;
1504  std::vector<float> volSteps;
1505  volSteps.push_back(-xTotal + xShift);
1506  std::vector<std::unique_ptr<Trk::TrackingVolume>> components{};
1507  if (!isDiamond) {
1508  xMax = xMed;
1509  y2 = 0.5 * zShift;
1510  auto cscBounds = std::make_unique<Trk::TrapezoidVolumeBounds>(xMin, xMax, y1, xTotal);
1511  // xy -> yz rotation
1512  // the center of Volume is shifted by y1-y2 in y
1514  envelope = std::make_unique<Trk::Volume>(makeTransform(std::move(cTr)), cscBounds.release());
1515  // components
1516  double xCurr = -xTotal;
1517  for (unsigned int ic = 0; ic < xSizes.size(); ic++) {
1518  // component volumes follow the envelope dimension
1519  xCurr += xSizes[ic];
1520  Amg::Transform3D compTr = Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2) * Amg::getTranslateZ3D(xCurr + xShift);
1521  auto compBounds = std::make_unique<Trk::TrapezoidVolumeBounds>(xMin, xMax, y1, xSizes[ic]);
1522  std::unique_ptr<Trk::LayerArray> cscLayerArray = processCSCTrdComponent(compGeoVol[ic], *compBounds, compTr, cache);
1523  std::unique_ptr<Trk::Volume> compVol = std::make_unique<Trk::Volume>(makeTransform(compTr), compBounds.release());
1524  auto compTV = std::make_unique<Trk::TrackingVolume>(*compVol, *m_muonMaterial, cscLayerArray.release(), nullptr, compName[ic]);
1525  components.push_back(std::move(compTV));
1526  xCurr += xSizes[ic];
1527  volSteps.push_back(xCurr + xShift);
1528  } // end components
1529  } else {
1530  if (xMed != xMin && xMed != xMax) {
1531  envXMed += zShift / (y1 / (xMed - xMin) + y2 / (xMed - xMax));
1532  envY1 = y1 * (envXMed - xMin) / (xMed - xMin);
1533  envY2 = y2 * (envXMed - xMax) / (xMed - xMax);
1534  }
1535  auto cscBounds = std::make_unique<Trk::DoubleTrapezoidVolumeBounds>(xMin, envXMed, xMax, envY1, envY2, xTotal);
1536  // xy -> yz rotation
1537  // the center of DoubleTrapezoidVolume is shifted by (envY1-envY2) in y
1538  Amg::Transform3D cTr = Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2) * Amg::getTranslate3D(0., envY1 - envY2, xShift);
1539  envelope = std::make_unique<Trk::Volume>(makeTransform(cTr), cscBounds.release());
1540  // components
1541  double xCurr = -xTotal;
1542  for (unsigned int ic = 0; ic < xSizes.size(); ic++) {
1543  // component volumes follow the envelope dimension
1544  xCurr += xSizes[ic];
1545  Amg::Transform3D compTr = Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2) *
1546  Amg::getTranslate3D(0., envY1 - envY2, xCurr + xShift);
1547  auto compBounds = std::make_unique<Trk::DoubleTrapezoidVolumeBounds>(xMin, envXMed, xMax, envY1, envY2, xSizes[ic]);
1548  std::unique_ptr<Trk::LayerArray> cscLayerArray{processCSCDiamondComponent(compGeoVol[ic], *compBounds, compTr, cache)};
1549  std::unique_ptr<Trk::Volume> compVol = std::make_unique<Trk::Volume>(makeTransform(compTr), compBounds.release());
1550  auto compTV = std::make_unique<Trk::TrackingVolume>(*compVol, *m_muonMaterial,
1551  cscLayerArray.release(), nullptr, compName[ic]);
1552  components.push_back(std::move(compTV));
1553  xCurr += xSizes[ic];
1554  volSteps.push_back(xCurr + xShift);
1555  } // end components
1556  }
1557 
1558  // convert component volumes into array
1559  std::unique_ptr<Trk::BinnedArray<Trk::TrackingVolume>> compArray{};
1560  if (!components.empty() && isDiamond) {
1561  auto binUtil = std::make_unique<Trk::BinUtility>(volSteps, Trk::BinningOption::open, Trk::BinningValue::binX);
1562  compArray.reset(m_trackingVolumeArrayCreator->doubleTrapezoidVolumesArrayNav(Muon::release(components), binUtil.release(), false));
1563  } else if (!components.empty() && !isDiamond) {
1564 
1565  auto binUtil = std::make_unique<Trk::BinUtility>(volSteps, Trk::BinningOption::open, Trk::BinningValue::binX);
1566  compArray.reset(m_trackingVolumeArrayCreator->trapezoidVolumesArrayNav(Muon::release(components), binUtil.release(), false));
1567 
1568  }
1569  // ready to build the station prototype
1570  return std::make_unique<Trk::TrackingVolume>(*envelope, *m_muonMaterial, nullptr, compArray.release(), name);
1571 }
1572 
1573 std::unique_ptr<Trk::TrackingVolume> Muon::MuonStationTypeBuilder::processTgcStation(const GeoVPhysVol* cv, Cache& cache) const {
1574 
1575  const GeoLogVol* clv = cv->getLogVol();
1576  const std::string& tgc_name = clv->getName();
1577  const GeoShape* baseShape = clv->getShape();
1578  if (baseShape->type() == "Subtraction") {
1579  const GeoShapeSubtraction* sub = dynamic_cast<const GeoShapeSubtraction*>(baseShape);
1580  if (sub) {
1581  baseShape = sub->getOpA();
1582  }
1583  }
1584 
1585  if (baseShape->type() == "Trd") {
1586  const GeoTrd* trd = dynamic_cast<const GeoTrd*>(baseShape);
1587  double x1 = trd->getXHalfLength1();
1588  double y1 = trd->getYHalfLength1();
1589  double y2 = trd->getYHalfLength2();
1590  double z = trd->getZHalfLength();
1591  // define envelope
1592  auto tgcBounds = std::make_unique<Trk::TrapezoidVolumeBounds>(y1, y2, z, x1);
1593  // xy -> yz rotation
1594  Amg::Transform3D tTr = Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2);
1595  std::unique_ptr<Trk::LayerArray> tgcLayerArray{processTGCComponent(cv, *tgcBounds, tTr, cache)};
1596  printVolumeBounds("TGC envelope bounds:", *tgcBounds);
1597  auto envelope = std::make_unique<Trk::Volume>(makeTransform(tTr), tgcBounds.release());
1598 
1599  // ready to build the station prototype
1600  auto tgc_station = std::make_unique<Trk::TrackingVolume>(*envelope, *m_muonMaterial, tgcLayerArray.release(), nullptr, tgc_name);
1601  return tgc_station;
1602  } else {
1603  ATH_MSG_WARNING( tgc_name << ": TGC component not a trapezoid ? no prototype built ");
1604  }
1605  return nullptr;
1606 }
1607 
1608 std::unique_ptr<Trk::DetachedTrackingVolume> Muon::MuonStationTypeBuilder::process_sTGC(const Identifier& nswId,
1609  const GeoVPhysVol* gv,
1610  const Amg::Transform3D& transf) const {
1611 
1612  std::string vName = gv->getLogVol()->getName();
1613  ATH_MSG_DEBUG("processing sTGC prototype of " << vName);
1614 
1615  std::unique_ptr<Trk::Volume> envelope = m_geoShapeConverter.translateGeoShape(gv->getLogVol()->getShape(), transf);
1616  if (!envelope) {
1617  ATH_MSG_WARNING("sTGC prototype for " << vName << " not built ");
1618  return nullptr;
1619  }
1620  double thickness = envelopeThickness(envelope->volumeBounds()); // half thickness
1621 
1622  // use envelope to define layer bounds
1623  Trk::SharedObject<const Trk::SurfaceBounds> layBounds{getLayerBoundsFromEnvelope(*envelope)};
1624  // calculate layer area
1625  double layArea = area(*layBounds);
1626  // use area to blend station material
1627  Trk::MaterialProperties sTgc_mat;
1628  m_volumeConverter.collectMaterial(gv, sTgc_mat, layArea);
1629  Trk::HomogeneousLayerMaterial stgcMaterial(sTgc_mat, 0.);
1630  const double scale = 1. / gv->getNChildVols();
1631  Trk::MaterialProperties sTgc_layerMat(sTgc_mat);
1632  sTgc_layerMat *= scale; // divide station material between layers
1633  Trk::HomogeneousLayerMaterial stgcLayMaterial(sTgc_layerMat, 0.);
1634 
1635  // loop over child volumes, check transforms / align with readout geometry
1636 
1637  std::vector<std::unique_ptr<Trk::PlaneLayer>> layers{};
1638  unsigned int ic = 0;
1639  const sTgcIdHelper& idHelper{m_idHelperSvc->stgcIdHelper()};
1640  for (const auto& [cv, trc] : geoGetVolumes(gv)) {
1641 
1642  auto layer = std::make_unique<Trk::PlaneLayer>(envelope->transform() * trc, layBounds,
1643  stgcLayMaterial, sTgc_layerMat.thickness());
1644 
1645  const Identifier id = idHelper.channelID(nswId,idHelper.multilayer(nswId),
1646  idHelper.gasGap(nswId) + ic, sTgcIdHelper::Wire, 1);
1647 
1648  layer->setLayerType(id.get_identifier32().get_compact());
1649 
1650  layers.push_back(std::move(layer));
1651  ++ic;
1652  }
1653  // create the BinnedArray
1654  std::vector<Trk::SharedObject<Trk::Layer>> layerOrder;
1655  std::vector<float> binSteps;
1656  binSteps.push_back(-thickness);
1657  for (unsigned int il=0; il < layers.size(); il++) {
1658  binSteps.push_back(binSteps.back() + sTgc_layerMat.thickness());
1659  layerOrder.push_back(std::move(layers[il]));
1660  }
1661  if (binSteps.back() > thickness + 1.e-3) {
1662  ATH_MSG_WARNING("rescale stgc binning:" << binSteps.back() << ">" << thickness);
1663  }
1664  binSteps.back() = thickness;
1665  auto binUtility = std::make_unique<Trk::BinUtility>(binSteps, Trk::BinningOption::open, Trk::BinningValue::binX);
1666  auto stgcLayerArray = std::make_unique<Trk::NavBinnedArray1D<Trk::Layer>>(layerOrder, binUtility.release(),
1667  makeTransform(Amg::Transform3D::Identity()));
1668  // build tracking volume
1669  auto sTgc = std::make_unique<Trk::TrackingVolume>(*envelope, *m_muonMaterial,
1670  stgcLayerArray.release(), nullptr, vName);
1671  // create layer representation
1672  auto layerRepr = std::make_unique<Trk::PlaneLayer>(transf, layBounds, stgcMaterial, sTgc_mat.thickness());
1673  // create prototype as detached tracking volume
1674  return std::make_unique<Trk::DetachedTrackingVolume>(vName, sTgc.release(), layerRepr.release(), nullptr);
1675 }
1676 
1677 std::unique_ptr<Trk::DetachedTrackingVolume> Muon::MuonStationTypeBuilder::process_MM(const Identifier& nswId,
1678  const GeoVPhysVol* gv,
1679  const Amg::Transform3D& transf) const {
1680 
1681  std::string vName = gv->getLogVol()->getName();
1682 
1683  ATH_MSG_DEBUG("processing MM:" << vName << ":"<< gv->getLogVol()->getShape()->type());
1684  std::unique_ptr<const Trk::Volume> envelope{m_geoShapeConverter.translateGeoShape(gv->getLogVol()->getShape(), transf)};
1685  if (!envelope) {
1686  ATH_MSG_WARNING("MM prototype for " << vName << " not built ");
1687  return nullptr;
1688  }
1689  double thickness = envelopeThickness(envelope->volumeBounds());
1690  printVolumeBounds("MM envelope bounds", envelope->volumeBounds());
1691 
1692  // use envelope to define layer bounds
1693  Trk::SharedObject<const Trk::SurfaceBounds> layBounds = getLayerBoundsFromEnvelope(*envelope);
1694  // calculate layer area
1695  double layArea = area(*layBounds);
1696  // use area to blend station material
1697  Trk::MaterialProperties mm_mat;
1698  m_volumeConverter.collectMaterial(gv, mm_mat, layArea);
1699  Trk::HomogeneousLayerMaterial mmMaterial(mm_mat, 0.);
1700  double scale = 1. / gv->getNChildVols();
1701  Trk::MaterialProperties mm_layerMat(mm_mat);
1702  mm_layerMat *= scale; // divide station material between layers
1703  Trk::HomogeneousLayerMaterial mmLayMaterial(mm_layerMat, 0.);
1704 
1705  // loop over child volumes, check transforms / align with readout geometry
1706  std::vector<std::unique_ptr<Trk::PlaneLayer>> layers;
1707  unsigned int ic = 0;
1708  const MmIdHelper& idHelper{m_idHelperSvc->mmIdHelper()};
1709  for (const auto& [cv, trc] : geoGetVolumes(gv)) {
1710  auto layer = std::make_unique<Trk::PlaneLayer>(transf * trc, layBounds, mmLayMaterial, mm_layerMat.thickness());
1711  Identifier id = idHelper.channelID(nswId, idHelper.multilayer(nswId), 1 + ic, 1);
1712  layer->setLayerType(id.get_identifier32().get_compact());
1713 
1714  layers.push_back(std::move(layer));
1715  ic++;
1716  }
1717 
1718  // create the BinnedArray
1719  std::vector<Trk::SharedObject<Trk::Layer>> layerOrder;
1720  std::vector<float> binSteps;
1721  binSteps.push_back(-thickness);
1722  for (unsigned int il=0; il < layers.size(); il++) {
1723  binSteps.push_back(binSteps.back() + mm_layerMat.thickness());
1724  layerOrder.push_back(std::move(layers[il]));
1725  }
1726  if (binSteps.back() > thickness + 1.e-3) {
1727  ATH_MSG_WARNING("rescale mm binning:" << binSteps.back() << ">" << thickness);
1728  }
1729  binSteps.back() = thickness;
1730  auto binUtility = std::make_unique<Trk::BinUtility>(binSteps, Trk::BinningOption::open, Trk::BinningValue::binX);
1731  auto mmLayerArray = std::make_unique<Trk::NavBinnedArray1D<Trk::Layer>>(layerOrder, binUtility.release(),
1732  makeTransform(Amg::Transform3D::Identity()));
1733  // build tracking volume
1734  auto mM = std::make_unique<Trk::TrackingVolume>(*envelope, *m_muonMaterial, mmLayerArray.release(), nullptr, vName);
1735  // create layer representation
1736  auto layerRepr = std::make_unique<Trk::PlaneLayer>(transf, layBounds, mmMaterial, mm_mat.thickness());
1737  // create prototype as detached tracking volume
1738  return std::make_unique<Trk::DetachedTrackingVolume>(vName, mM.release(), layerRepr.release(), nullptr);
1739 }
1740 
1741 double Muon::MuonStationTypeBuilder::get_x_size(const GeoVPhysVol* pv) const {
1742  double xlow{0.}, xup{0.};
1743  // subcomponents
1745  if (vols.empty()) {
1746  return decodeX(pv->getLogVol()->getShape());
1747  }
1748 
1749  for (const auto& [cv, transf] : vols) {
1750  const GeoLogVol* clv = cv->getLogVol();
1751  double xh = decodeX(clv->getShape());
1752  xlow = std::min(xlow, (transf.translation())[0] - xh);
1753  xup = std::max(xup, (transf.translation())[0] + xh);
1754  }
1755 
1756  return std::max(-xlow, xup);
1757 }
1758 
1760  double volume,
1761  double thickness) const {
1762  ATH_MSG_DEBUG( "::getAveragedLayerMaterial:processing ");
1763  // loop through the whole hierarchy; collect material
1764  Trk::MaterialProperties sumMat;
1765  // protect nan
1766  if (thickness > 0.)
1767  m_volumeConverter.collectMaterial(pv, sumMat, volume / thickness);
1768 
1769  ATH_MSG_VERBOSE( " combined material thickness: "<< sumMat.thickness());
1770  ATH_MSG_VERBOSE( " actual layer thickness: " << thickness);
1771 
1772  // scale material properties to the actual layer thickness
1773  if (sumMat.thickness() != thickness && sumMat.thickness() > 0.) {
1774  double sf = thickness / sumMat.thickness();
1775  sumMat.material().X0 /= sf;
1776  sumMat.material().L0 /= sf;
1777  sumMat.material().rho *= sf;
1778  ATH_MSG_VERBOSE("averaged material scale :"<< sf << " sumMat.material().X0() "
1779  << sumMat.material().X0 << " sumMat.material().L0 "
1780  << sumMat.material().L0 << " sumMat.material().rho "
1781  << sumMat.material().rho << " sumMat.material().x0() "
1782  << sumMat.material().x0());
1783  ATH_MSG_VERBOSE("averaged material:d,x0,dInX0:"
1784  << sumMat.thickness() << "," << sumMat.material().x0());
1785  return sumMat;
1786  }
1787  return sumMat;
1788 }
1789 
1790 std::unique_ptr<Trk::LayerArray> Muon::MuonStationTypeBuilder::processCSCTrdComponent(const GeoVPhysVol* pv,
1791  const Trk::TrapezoidVolumeBounds& compBounds,
1792  const Amg::Transform3D& transf,
1793  Cache& cache) const {
1794  // tolerance
1795  std::string name = pv->getLogVol()->getName();
1796  std::vector<std::unique_ptr<Trk::PlaneLayer>> layers{};
1797  std::vector<double> x_array{}, x_thickness{};
1798  std::vector<Trk::MaterialProperties> x_mat;
1799  std::vector<int> x_active;
1800  double currX = -100000;
1801  // while waiting for better suggestion, define a single material layer
1802  Trk::MaterialProperties matCSC(0., 10.e10, 10.e10, 13., 26., 0.);
1803  double thickness = 2 * compBounds.halflengthZ();
1804  double minX = compBounds.minHalflengthX();
1805  double maxX = compBounds.maxHalflengthX();
1806  double halfY = compBounds.halflengthY();
1807  double halfZ = compBounds.halflengthZ();
1808  if (name.compare(name.size() - 5, 5, "CSC01") == 0) {
1809  if (!cache.m_matCSC01) {
1810  double vol = (minX + maxX) * 2 * halfY * thickness;
1811  cache.m_matCSC01 = std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(pv, vol, thickness));
1812  }
1813  matCSC = Trk::MaterialProperties(*cache.m_matCSC01);
1814  // retrieve number of gas gaps and their position -> turn them into
1815  // active layers step 1 level below
1816  const GeoVPhysVol* cv1 = pv->getChildVol(0);
1817  for (const auto& [cv, transfc]: geoGetVolumes(cv1)) {
1818  const GeoLogVol* clv = cv->getLogVol();
1819  if (clv->getName() == "CscArCO2") {
1820  double xl = transfc.translation().x();
1821  if (x_array.empty() || xl >= x_array.back()) {
1822  x_array.push_back(xl);
1823  } else {
1824  unsigned int ix = 0;
1825  while (ix < x_array.size() && x_array[ix] < xl) {
1826  ix++;
1827  }
1828  x_array.insert(x_array.begin() + ix, xl);
1829  }
1830  }
1831  }
1832  if (x_array.empty()) {
1833  x_array.push_back(0.);
1834  x_mat.push_back(matCSC);
1835  x_thickness.push_back(thickness);
1836  x_active.push_back(1);
1837  } else if (x_array.size() == 1) {
1838  double xthick = 2 * std::min(x_array[0] + halfZ, halfZ - x_array[0]);
1839  double scale = xthick / thickness;
1840  Trk::MaterialProperties xmatCSC(xthick, scale * matCSC.x0(), scale * matCSC.l0(),
1841  matCSC.averageA(), matCSC.averageZ(),
1842  matCSC.averageRho() / scale);
1843  x_mat.push_back(xmatCSC);
1844  x_thickness.push_back(xthick);
1845  x_active.push_back(1);
1846  } else {
1847  double currX = -halfZ;
1848  for (unsigned int il=0; il < x_array.size(); il++) {
1849  double xthick;
1850  if (il < x_array.size() - 1) {
1851  xthick = 2 * std::min(x_array[il] - currX, 0.5 * (x_array[il + 1] - x_array[il]));
1852  } else {
1853  xthick = 2 * std::min(x_array[il] - currX, halfZ - x_array[il]);
1854  }
1855  x_thickness.push_back(xthick);
1856  x_mat.push_back(matCSC);
1857  currX = x_array[il] + 0.5 * x_thickness.back();
1858  x_active.push_back(1);
1859  }
1860  }
1861  }
1862  if (name == "CSCspacer") {
1863  if (!cache.m_matCSCspacer1) {
1864  double vol = (minX + maxX) * 2 * halfY * thickness;
1865  cache.m_matCSCspacer1 = std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(pv, vol, thickness));
1866  }
1867  x_array.push_back(0.);
1868  x_mat.push_back(*cache.m_matCSCspacer1);
1869  x_thickness.push_back(thickness);
1870  x_active.push_back(0);
1871  }
1872  // create layers
1873  std::unique_ptr<Trk::OverlapDescriptor> od{};
1874  Trk::SharedObject<const Trk::SurfaceBounds> bounds = std::make_unique<Trk::TrapezoidBounds>(minX, maxX, halfY);
1875  for (unsigned int iloop = 0; iloop < x_array.size(); iloop++) {
1876  Amg::Transform3D cTr = transf * Amg::getTranslateZ3D(x_array[iloop]);
1877  Trk::HomogeneousLayerMaterial cscMaterial(x_mat[iloop], 0.);
1878  auto layer = std::make_unique<Trk::PlaneLayer>(cTr, bounds, cscMaterial, x_thickness[iloop], std::move(od));
1879  // make preliminary identification of active layers
1880  layer->setLayerType(x_active[iloop]);
1881  layers.push_back(std::move(layer));
1882  }
1883 
1884  // create the BinnedArray
1885  std::vector<Trk::SharedObject<Trk::Layer>> layerOrder;
1886  std::vector<float> binSteps;
1887  double xShift = transf.translation().x();
1888  float lowX = -compBounds.halflengthZ() + xShift;
1889  binSteps.push_back(lowX);
1890 
1891  if (!layers.empty()) {
1892  currX = lowX - xShift;
1893  for (unsigned int i = 0; i < layers.size() - 1; i++) {
1894  currX = x_array[i] + 0.5 * layers[i]->thickness();
1895  layerOrder.push_back(std::move(layers[i]));
1896  binSteps.push_back(currX + xShift);
1897  }
1898  layerOrder.push_back(std::move(layers.back()));
1899  binSteps.push_back(compBounds.halflengthZ() + xShift);
1900  }
1901 
1902  auto binUtility = std::make_unique<Trk::BinUtility>(binSteps, Trk::BinningOption::open, Trk::BinningValue::binX);
1903  return std::make_unique<Trk::NavBinnedArray1D<Trk::Layer>>(layerOrder, binUtility.release(),
1904  makeTransform(Amg::Transform3D::Identity()));
1905 }
1906 
1907 std::unique_ptr<Trk::LayerArray>
1909  const Trk::DoubleTrapezoidVolumeBounds& compBounds,
1910  const Amg::Transform3D& transf,
1911  Cache& cache) const {
1912  // tolerance
1913  std::string name = pv->getLogVol()->getName();
1914  std::vector<std::unique_ptr<Trk::PlaneLayer>> layers{};
1915  std::vector<double> x_array{}, x_thickness{};
1916  std::vector<Trk::MaterialProperties> x_mat;
1917  std::vector<int> x_active;
1918  double currX = -100000;
1919  // while waiting for better suggestion, define a single material layer
1920  Trk::MaterialProperties matCSC(0., 10e8, 10e8, 13., 26., 0.);
1921  double thickness = 2 * compBounds.halflengthZ();
1922  double minX = compBounds.minHalflengthX();
1923  double medX = compBounds.medHalflengthX();
1924  double maxX = compBounds.maxHalflengthX();
1925  double halfY1 = compBounds.halflengthY1();
1926  double halfY2 = compBounds.halflengthY2();
1927  double halfZ = compBounds.halflengthZ();
1928  if (name.compare(name.size() - 5, 5, "CSC02") == 0) {
1929  if (!cache.m_matCSC02) {
1930  double vol = ((minX + medX) * 2 * halfY1 + (medX + maxX) * 2 * halfY2) * thickness;
1931  cache.m_matCSC02 = std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(pv, vol, thickness));
1932  }
1933  matCSC = Trk::MaterialProperties(*cache.m_matCSC02);
1934  // retrieve number of gas gaps and their position -> turn them into
1935  // active layers step 1 level below
1936  const GeoVPhysVol* cv1 = pv->getChildVol(0);
1937  for (const auto& [cv, transfc] : geoGetVolumes(cv1)) {
1938  const GeoLogVol* clv = cv->getLogVol();
1939  if (clv->getName() == "CscArCO2") {
1940  double xl = transfc.translation().x();
1941  if (x_array.empty() || xl >= x_array.back()) {
1942  x_array.push_back(xl);
1943  } else {
1944  unsigned int ix = 0;
1945  while (ix < x_array.size() && x_array[ix] < xl) {
1946  ix++;
1947  }
1948  x_array.insert(x_array.begin() + ix, xl);
1949  }
1950  }
1951  }
1952  //
1953  if (x_array.empty()) {
1954  x_array.push_back(0.);
1955  x_mat.push_back(matCSC);
1956  x_thickness.push_back(thickness);
1957  x_active.push_back(1);
1958  } else if (x_array.size() == 1) {
1959  x_mat.push_back(matCSC);
1960  x_thickness.push_back(2 *std::min(x_array[0] + halfZ, halfZ - x_array[0]));
1961  x_active.push_back(1);
1962  } else {
1963  double currX = -halfZ;
1964  for (unsigned int il=0; il < x_array.size(); il++) {
1965  double xthick{0.};
1966  if (il < x_array.size() - 1) {
1967  xthick = 2 * std::min(x_array[il] - currX, 0.5 * (x_array[il + 1] - x_array[il]));
1968  x_thickness.push_back(xthick);
1969  } else {
1970  xthick = 2 * std::min(x_array[il] - currX, halfZ - x_array[il]);
1971  x_thickness.push_back(xthick);
1972  }
1973  x_mat.push_back(matCSC);
1974  currX = x_array[il] + 0.5 * x_thickness.back();
1975  x_active.push_back(1);
1976  }
1977  }
1978  }
1979  if (name == "CSCspacer") {
1980  if (!cache.m_matCSCspacer2) {
1981  double vol = ((minX + medX) * 2 * halfY1 + (medX + maxX) * 2 * halfY2) *thickness;
1982  cache.m_matCSCspacer2 = std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(pv, vol, thickness));
1983  }
1984  matCSC = Trk::MaterialProperties(*cache.m_matCSCspacer2);
1985  x_array.push_back(0.);
1986  x_mat.push_back(matCSC);
1987  x_thickness.push_back(thickness);
1988  x_active.push_back(0);
1989  }
1990  // create layers
1991  std::unique_ptr<Trk::OverlapDescriptor> od{};
1992  Trk::SharedObject<const Trk::DiamondBounds> dbounds = std::make_unique<Trk::DiamondBounds>(minX, medX, maxX, halfY1, halfY2);
1993  for (unsigned int iloop = 0; iloop < x_array.size(); iloop++) {
1994  Amg::Transform3D cTr = transf * Amg::getTranslateZ3D(x_array[iloop]);
1995  Trk::HomogeneousLayerMaterial cscMaterial(x_mat[iloop], 0.);
1996  auto layer = std::make_unique<Trk::PlaneLayer>(cTr, dbounds, cscMaterial,
1997  x_thickness[iloop], std::move(od));
1998  // make preliminary identification of active layers
1999  layer->setLayerType(x_active[iloop]);
2000  layers.push_back(std::move(layer));
2001  }
2002 
2003  // create the BinnedArray
2004  std::vector<Trk::SharedObject<Trk::Layer>> layerOrder;
2005  std::vector<float> binSteps;
2006  double xShift = transf.translation().x();
2007  double lowX = -compBounds.halflengthZ() + xShift;
2008  binSteps.push_back(lowX);
2009 
2010  if (!layers.empty()) {
2011  currX = lowX;
2012  for (unsigned int i = 0; i < layers.size() - 1; i++) {
2013  currX = x_array[i] + 0.5 * layers[i]->thickness() + xShift;
2014  binSteps.push_back(currX);
2015  layerOrder.push_back(std::move(layers[i]));
2016  }
2017 
2018  layerOrder.push_back(std::move(layers.back()));
2019  binSteps.push_back(compBounds.halflengthZ() + xShift);
2020  }
2021 
2022  auto binUtility = std::make_unique<Trk::BinUtility>(binSteps, Trk::BinningOption::open, Trk::BinningValue::binX);
2023  return std::make_unique<Trk::NavBinnedArray1D<Trk::Layer>>(layerOrder, binUtility.release(),
2024  makeTransform(Amg::Transform3D::Identity()));
2025 
2026 }
2027 
2028 std::unique_ptr<Trk::LayerArray> Muon::MuonStationTypeBuilder::processTGCComponent(const GeoVPhysVol* pv,
2029  const Trk::TrapezoidVolumeBounds& tgcBounds,
2030  const Amg::Transform3D& transf,
2031  Cache& cache) const {
2032  // tolerance
2033  constexpr double tol{0.001};
2034  std::string name = pv->getLogVol()->getName();
2035  std::vector<std::unique_ptr<Trk::PlaneLayer>> layers{};
2036  std::vector<double> x_array{}, x_thickness{};
2037  std::vector<Trk::MaterialProperties> x_mat;
2038  double currX = -100000;
2039  // while waiting for better suggestion, define a single material layer
2040  Trk::MaterialProperties matTGC(0., 10e8, 10e8, 13., 26., 0.);
2041  double minX = tgcBounds.minHalflengthX();
2042  double maxX = tgcBounds.maxHalflengthX();
2043  double halfY = tgcBounds.halflengthY();
2044  double halfZ = tgcBounds.halflengthZ();
2045  double thickness = 2 * halfZ;
2046  if (std::abs(halfZ - 35.00) < tol) {
2047  if (!cache.m_matTGC01) {
2048  double vol = (minX + maxX) * 2 * halfY * thickness;
2049  cache.m_matTGC01 = std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(pv, vol, thickness));
2050  }
2051  matTGC = Trk::MaterialProperties(*cache.m_matTGC01);
2052  } else if (std::abs(halfZ - 21.85) < tol) {
2053  if (!cache.m_matTGC06) {
2054  double vol = (minX + maxX) * 2 * halfY * thickness;
2055  cache.m_matTGC06 = std::make_unique<Trk::MaterialProperties>(getAveragedLayerMaterial(pv, vol, thickness));
2056  }
2057  matTGC = Trk::MaterialProperties(*cache.m_matTGC06);
2058  } else {
2059  ATH_MSG_DEBUG("unknown TGC material:" << halfZ);
2060  }
2061 
2062  for (const auto& [cv, transfc] : geoGetVolumes(pv)) {
2063  const GeoLogVol* clv = cv->getLogVol();
2064  if (clv->getName() == "muo::TGCGas") {
2065  double xl = transfc.translation().x();
2066  if (x_array.empty() || xl >= x_array.back()) {
2067  x_array.push_back(xl);
2068  } else {
2069  unsigned int ix = 0;
2070  while (ix < x_array.size() && x_array[ix] < xl) {
2071  ix++;
2072  }
2073  x_array.insert(x_array.begin() + ix, xl);
2074  }
2075  }
2076  }
2077  double activeThick{0.};
2078  if (x_array.empty()) {
2079  x_array.push_back(0.);
2080  x_thickness.push_back(thickness);
2081  activeThick = thickness;
2082  } else if (x_array.size() == 1) {
2083  x_thickness.push_back(2 * fmin(x_array[0] + halfZ, halfZ - x_array[0]));
2084  activeThick += x_thickness.back();
2085  } else {
2086  double currX = -halfZ;
2087  for (unsigned int il=0; il < x_array.size(); ++il) {
2088  if (il < x_array.size() - 1) {
2089  x_thickness.push_back(2 * std::min(x_array[il] - currX, 0.5 * (x_array[il + 1] - x_array[il])));
2090  } else {
2091  x_thickness.push_back(2 * std::min(x_array[il] - currX, halfZ - x_array[il]));
2092  }
2093  currX = x_array[il] + 0.5 * x_thickness.back();
2094  activeThick += x_thickness.back();
2095  }
2096  }
2097  // rescale material to match the combined thickness of active layers
2098  double scale = activeThick / thickness;
2099  matTGC = Trk::MaterialProperties(activeThick, scale * matTGC.x0(), scale * matTGC.l0(),
2100  matTGC.averageA(), matTGC.averageZ(), matTGC.averageRho() / scale);
2101  // create layers
2102  std::unique_ptr<Trk::OverlapDescriptor> od = nullptr;
2103  Trk::SharedObject<const Trk::SurfaceBounds> bounds = std::make_unique<Trk::TrapezoidBounds>(minX, maxX, halfY);
2104 
2105  for (unsigned int iloop = 0; iloop < x_array.size(); iloop++) {
2106  Amg::Transform3D cTr = Amg::getTranslateX3D(x_array[iloop]) * transf;
2107  Trk::HomogeneousLayerMaterial tgcMaterial(matTGC, 0.);
2108  auto layer = std::make_unique<Trk::PlaneLayer>(cTr, bounds, tgcMaterial, x_thickness[iloop], std::move(od));
2109  // make preliminary identification of active layers
2110  layer->setLayerType(1);
2111  layers.push_back(std::move(layer));
2112  }
2113  // create the BinnedArray
2114  std::vector<Trk::SharedObject<Trk::Layer>> layerOrder;
2115  std::vector<float> binSteps;
2116  //
2117  float xShift = transf.translation().x();
2118  float lowX = -halfZ + xShift;
2119  binSteps.push_back(lowX);
2120  if (!layers.empty()) {
2121  currX = lowX;
2122  for (unsigned int i = 0; i < layers.size() - 1; ++i) {
2123  currX = x_array[i] + 0.5 * layers[i]->thickness() + xShift;
2124  binSteps.push_back(currX);
2125  layerOrder.push_back(std::move(layers[i]));
2126  }
2127  layerOrder.push_back(std::move(layers.back()));
2128  binSteps.push_back(halfZ + xShift);
2129  }
2130  auto binUtility = std::make_unique<Trk::BinUtility>(binSteps, Trk::BinningOption::open, Trk::BinningValue::binX);
2131  return std::make_unique<Trk::NavBinnedArray1D<Trk::Layer>>(layerOrder, binUtility.release(),
2132  makeTransform(Amg::Transform3D::Identity()));
2133 
2134 }
2135 
2136 double Muon::MuonStationTypeBuilder::decodeX(const GeoShape* sh) const {
2137  double xHalf{0.};
2138 
2139  const GeoTrd* trd = dynamic_cast<const GeoTrd*>(sh);
2140  const GeoBox* box = dynamic_cast<const GeoBox*>(sh);
2141  const GeoTube* tub = dynamic_cast<const GeoTube*>(sh);
2142  const GeoTubs* tubs = dynamic_cast<const GeoTubs*>(sh);
2143  const GeoShapeShift* shift = dynamic_cast<const GeoShapeShift*>(sh);
2144  const GeoShapeUnion* uni = dynamic_cast<const GeoShapeUnion*>(sh);
2145  const GeoShapeSubtraction* sub = dynamic_cast<const GeoShapeSubtraction*>(sh);
2146  const GeoSimplePolygonBrep* spb = dynamic_cast<const GeoSimplePolygonBrep*>(sh);
2147 
2148  if (!trd && !box && !tub && !tubs && !shift && !uni && !sub && !spb) {
2149  ATH_MSG_WARNING("decodeX(GeoShape="
2150  << sh->type() << "): shape type " << sh->type()
2151  << " is unknown, returning xHalf=0");
2152  return xHalf;
2153  }
2154 
2155  if (spb) {
2156  for (unsigned int i = 0; i < spb->getNVertices(); i++) {
2157  ATH_MSG_DEBUG(" XVertex " << spb->getXVertex(i) << " YVertex "
2158  << spb->getYVertex(i));
2159  if (spb->getXVertex(i) > xHalf)
2160  xHalf = spb->getXVertex(i);
2161  }
2162  ATH_MSG_DEBUG(" GeoSimplePolygonBrep xHalf " << xHalf);
2163  }
2164 
2165  if (trd){
2166  xHalf = std::max(trd->getXHalfLength1(), trd->getXHalfLength2());
2167  }
2168  if (box) {
2169  xHalf = box->getXHalfLength();
2170  }
2171  if (tub) {
2172  xHalf = tub->getRMax();
2173  }
2174  if (sub) {
2175  // be careful to handle properly GeoModel habit of subtracting large
2176  // volumes from smaller ones
2177  double xA = decodeX(sub->getOpA());
2178  xHalf = xA;
2179  }
2180  if (uni) {
2181  xHalf = std::max(decodeX(uni->getOpA()), decodeX(uni->getOpB()));
2182  }
2183  if (shift) {
2184  double xA = decodeX(shift->getOp());
2185  double xB = shift->getX().translation().x();
2186  xHalf = xA + std::abs(xB);
2187  }
2188 
2189  return xHalf;
2190 }
2191 
2192 std::pair<std::unique_ptr<Trk::Layer>,std::vector<std::unique_ptr<Trk::Layer>>>
2194 
2195  std::unique_ptr<Trk::Layer> layRepr{};
2196 
2197 
2198  std::vector<std::unique_ptr<Trk::Layer>> multi{};
2199 
2200  // retrieve volume envelope
2201 
2202  Trk::CuboidVolumeBounds* cubBounds = dynamic_cast<Trk::CuboidVolumeBounds*>(&(trVol.volumeBounds()));
2203  Trk::TrapezoidVolumeBounds* trdBounds = dynamic_cast<Trk::TrapezoidVolumeBounds*>(&(trVol.volumeBounds()));
2204  Trk::DoubleTrapezoidVolumeBounds* dtrdBounds =dynamic_cast<Trk::DoubleTrapezoidVolumeBounds*>(&(trVol.volumeBounds()));
2205 
2206  Amg::Transform3D subt{Amg::Transform3D::Identity()};
2207 
2208  Trk::SubtractedVolumeBounds* subBounds = dynamic_cast<Trk::SubtractedVolumeBounds*>(&(trVol.volumeBounds()));
2209  if (subBounds) {
2210  subt = Amg::getRotateY3D(M_PI_2) *Amg::getRotateZ3D(M_PI_2);
2211  while (subBounds) {
2212  cubBounds = dynamic_cast<Trk::CuboidVolumeBounds*>(&(subBounds->outer()->volumeBounds()));
2213  trdBounds = dynamic_cast<Trk::TrapezoidVolumeBounds*>(&(subBounds->outer()->volumeBounds()));
2214  dtrdBounds = dynamic_cast<Trk::DoubleTrapezoidVolumeBounds*>(&(subBounds->outer()->volumeBounds()));
2215  subBounds = dynamic_cast<Trk::SubtractedVolumeBounds*>(&(subBounds->outer()->volumeBounds()));
2216  }
2217  }
2218 
2219  if (cubBounds) {
2220  double thickness = 2 * cubBounds->halflengthX();
2221  double sf = 4 * cubBounds->halflengthZ() * cubBounds->halflengthY();
2222  auto bounds = std::make_unique<Trk::RectangleBounds>(cubBounds->halflengthY(), cubBounds->halflengthZ());
2223  std::unique_ptr<Trk::OverlapDescriptor> od;
2224  Trk::MaterialProperties matProp = collectStationMaterial(trVol, sf);
2225  ATH_MSG_VERBOSE(" collectStationMaterial cub " << matProp);
2226  if (matProp.thickness() > thickness) {
2227  ATH_MSG_DEBUG(" thickness of combined station material exceeds station size:" << trVol.volumeName());
2228  } else if (matProp.thickness() < thickness && matProp.thickness() > 0.) {
2229 
2230  double sf = thickness / matProp.thickness();
2231  matProp = Trk::MaterialProperties(thickness, sf * matProp.x0(), sf * matProp.l0(),
2232  matProp.averageA(), matProp.averageZ(), matProp.averageRho() / sf);
2233  }
2234  Trk::HomogeneousLayerMaterial mat(matProp, 0.);
2235  layRepr = std::make_unique<Trk::PlaneLayer>(Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2),
2236  bounds->clone(), mat, thickness, std::move(od), 1);
2237  // multilayers
2238  if (m_multilayerRepresentation && trVol.confinedVolumes()) {
2240  if (vols.size() > 1) {
2241  for (auto* vol : vols) {
2242  Trk::MaterialProperties matMulti = collectStationMaterial(*vol, sf);
2243  ATH_MSG_VERBOSE(" collectStationMaterial cub matMulti "<< matMulti);
2244  multi.emplace_back(std::make_unique<Trk::PlaneLayer>(vol->transform() * Amg::getRotateY3D(M_PI_2) * Amg::getRotateZ3D(M_PI_2),
2245  bounds->clone(), Trk::HomogeneousLayerMaterial(matMulti, 0.),
2246  matMulti.thickness(), std::move(od), 1));
2247  }
2248  }
2249  }
2250  } else if (trdBounds) {
2251  double thickness = 2 * trdBounds->halflengthZ();
2252  double sf = 2 * (trdBounds->minHalflengthX() + trdBounds->maxHalflengthX()) * trdBounds->halflengthY();
2253  std::vector<std::unique_ptr<const Trk::Surface>> surfs = toVec(trdBounds->decomposeToSurfaces(Amg::Transform3D::Identity()));
2254  const Trk::TrapezoidBounds* tbounds = dynamic_cast<const Trk::TrapezoidBounds*>(&surfs[0]->bounds());
2255  Trk::SharedObject<const Trk::SurfaceBounds> bounds = std::make_unique<Trk::TrapezoidBounds>(*tbounds);
2256  std::unique_ptr<Trk::OverlapDescriptor> od = nullptr;
2257  Trk::MaterialProperties matProp = collectStationMaterial(trVol, sf);
2258  ATH_MSG_VERBOSE(" collectStationMaterial trd " << matProp << trVol.volumeName());
2259  if (matProp.thickness() > thickness) {
2260  ATH_MSG_DEBUG(" thickness of combined station material exceeds station size:" << trVol.volumeName());
2261  } else if (matProp.thickness() < thickness && matProp.thickness() > 0.) {
2262  float sf = thickness / matProp.thickness();
2263  matProp = Trk::MaterialProperties(thickness, sf * matProp.x0(), sf * matProp.l0(),
2264  matProp.averageA(), matProp.averageZ(), matProp.averageRho() / sf);
2265  }
2266  Trk::HomogeneousLayerMaterial mat(matProp, 0.);
2267  layRepr = std::make_unique<Trk::PlaneLayer>(subt * trVol.transform(), bounds, mat, thickness, std::move(od), 1);
2268 
2269  // multilayers
2270  if (m_multilayerRepresentation && trVol.confinedVolumes()) {
2272  if (vols.size() > 1) {
2273  for (auto* vol : vols) {
2274  Trk::MaterialProperties matMulti = collectStationMaterial(*vol, sf);
2275  ATH_MSG_VERBOSE(" collectStationMaterial trd matMulti "<< matMulti);
2276  multi.emplace_back(std::make_unique<Trk::PlaneLayer>(Amg::Transform3D(vol->transform()), bounds,
2277  Trk::HomogeneousLayerMaterial(matMulti, 0.),
2278  matMulti.thickness(), std::move(od), 1));
2279  }
2280  }
2281  }
2282  } else if (dtrdBounds) {
2283  double thickness = 2 * dtrdBounds->halflengthZ();
2284  double sf = 2 * (dtrdBounds->minHalflengthX() + dtrdBounds->medHalflengthX()) * dtrdBounds->halflengthY1() +
2285  2 * (dtrdBounds->medHalflengthX() + dtrdBounds->maxHalflengthX()) * dtrdBounds->halflengthY2();
2286  std::vector<std::unique_ptr<const Trk::Surface>> surfs = toVec(dtrdBounds->decomposeToSurfaces(Amg::Transform3D::Identity()));
2287  const Trk::DiamondBounds* dbounds = dynamic_cast<const Trk::DiamondBounds*>(&surfs[0]->bounds());
2288  Trk::SharedObject<const Trk::SurfaceBounds> bounds = std::make_unique<Trk::DiamondBounds>(*dbounds);
2289  std::unique_ptr<Trk::OverlapDescriptor> od = nullptr;
2290  Trk::MaterialProperties matProp = collectStationMaterial(trVol, sf);
2291  ATH_MSG_VERBOSE(" collectStationMaterial dtrd " << matProp);
2292  if (matProp.thickness() > thickness) {
2293  ATH_MSG_DEBUG(" thickness of combined station material exceeds station size:"<< trVol.volumeName());
2294  } else if (matProp.thickness() < thickness && matProp.thickness() > 0.) {
2295  float sf = thickness / matProp.thickness();
2296  matProp = Trk::MaterialProperties(thickness, sf * matProp.x0(), sf * matProp.l0(),
2297  matProp.averageA(), matProp.averageZ(),
2298  matProp.averageRho() / sf);
2299  }
2300  Trk::HomogeneousLayerMaterial mat(matProp, 0.);
2301  layRepr = std::make_unique<Trk::PlaneLayer>(trVol.transform(), bounds, mat, thickness, std::move(od), 1);
2302  // multilayers
2303  if (m_multilayerRepresentation && trVol.confinedVolumes()) {
2305  if (vols.size() > 1) {
2306  for (auto* vol : vols) {
2307  Trk::MaterialProperties matMulti = collectStationMaterial(*vol, sf);
2308  ATH_MSG_VERBOSE(" collectStationMaterial dtrd matMulti " << matMulti);
2309  multi.emplace_back(std::make_unique<Trk::PlaneLayer>(vol->transform(), bounds,
2310  Trk::HomogeneousLayerMaterial(matMulti, 0.),
2311  matMulti.thickness(), std::move(od), 1));
2312  }
2313  }
2314  }
2315  }
2316  return std::make_pair(std::move(layRepr), std::move(multi));
2317 }
2318 
2320  const Amg::Transform3D& transf) const {
2321  Identifier id(0);
2322 
2323  if ((vName[0] == 'Q') || (vName[0] == 'M')) { // NSW stations
2324  // station eta
2325  std::istringstream istr(&vName[1]);
2326  int iEta;
2327  if (vName[0] == 'Q') {
2328  std::istringstream istr2(&vName[2]);
2329  istr2 >> iEta;
2330  } else
2331  istr >> iEta;
2332  if (transf.translation().z() < 0.)
2333  iEta *= -1;
2334  // station Phi
2335  unsigned int iPhi = 1;
2336  // if (trVol.center().z()>0.) iPhi += 8;
2337  // station multilayer
2338  std::istringstream istm(&vName[3]);
2339  int iMult;
2340  istm >> iMult;
2341  if (vName[0] == 'Q' && vName[3] == 'P')
2342  iMult = (vName[1] == 'L') ? 1 : 2;
2343  if (vName[0] == 'Q' && vName[3] == 'C')
2344  iMult = (vName[1] == 'L') ? 2 : 1;
2345  // layer
2346  std::string stl(&vName[vName.size() - 1]);
2347  std::istringstream istl(stl);
2348  int iLay;
2349  istl >> iLay;
2350  iLay += 1;
2351  if (vName[0] == 'Q') {
2352  std::string stName = (vName[1] == 'L') ? "STL" : "STS";
2353  id = m_idHelperSvc->stgcIdHelper().channelID(
2354  stName, iEta, iPhi, iMult, iLay, 2, 1); // wire position
2355  } else {
2356  std::string stName = (vName[2] == 'L') ? "MML" : "MMS";
2357  id = m_idHelperSvc->mmIdHelper().channelID(stName, iEta, iPhi, iMult,
2358  iLay, 1);
2359  }
2360  }
2361 
2362  return id;
2363 }
2364 
2366  Trk::MaterialProperties layMat(0., 10.e10, 10.e10, 13., 26., 0.);
2367 
2368  // sf is surface of the new layer used to calculate the average 'thickness'
2369  // of components layers
2370  if (vol.confinedLayers()) {
2372  for (const auto* lay : lays) {
2373  const Trk::MaterialProperties* mLay =lay->layerMaterialProperties()->fullMaterial(lay->surfaceRepresentation().center());
2374  // protect nan
2375  if (mLay && lay->thickness() > 0 && mLay->material().x0() > 0.) {
2376  layMat.addMaterial(mLay->material(),
2377  lay->thickness() / mLay->material().x0());
2378  ATH_MSG_VERBOSE(" collectStationMaterial after add confined lay "<< layMat);
2379  }
2380  }
2381  }
2382  if (!vol.confinedArbitraryLayers().empty()) {
2384  for (const auto* lay : lays) {
2385  const Trk::MaterialProperties* mLay = lay->layerMaterialProperties()->fullMaterial(lay->surfaceRepresentation().center());
2386  // scaling factor
2387  const Trk::RectangleBounds* rect = dynamic_cast<const Trk::RectangleBounds*>(&(lay->surfaceRepresentation().bounds()));
2388  const Trk::TrapezoidBounds* trap =dynamic_cast<const Trk::TrapezoidBounds*>(&(lay->surfaceRepresentation().bounds()));
2389  if ((rect || trap) && mLay) {
2390  double scale = rect ? 4 * rect->halflengthX() * rect->halflengthY() / sf
2391  : 2 * (trap->minHalflengthX() + trap->maxHalflengthX()) * trap->halflengthY() / sf;
2392  // protect nan
2393  if (lay->thickness() > 0 && mLay->material().x0() > 0.) {
2394  layMat.addMaterial(mLay->material(),
2395  scale * lay->thickness() / mLay->material().x0());
2396  ATH_MSG_VERBOSE(" collectStationMaterial after add confined sub lay "<< layMat);
2397  }
2398  }
2399  }
2400  }
2401  // subvolumes
2402  if (vol.confinedVolumes()) {
2404  for (const auto* subVol : subVols) {
2405  if (subVol->confinedLayers()) {
2406  Trk::BinnedArraySpan<Trk::Layer const* const> lays = subVol->confinedLayers()->arrayObjects();
2407  for (const auto* lay : lays) {
2408  const Trk::MaterialProperties* mLay = lay->layerMaterialProperties()->fullMaterial(
2409  lay->surfaceRepresentation().center());
2410  // protect nan
2411  if (mLay && lay->thickness() > 0 && mLay->material().x0() > 0.) {
2412  layMat.addMaterial(mLay->material(), lay->thickness() / mLay->material().x0());
2413  ATH_MSG_VERBOSE(" collectStationMaterial after add confined vol " << layMat);
2414  }
2415  }
2416  }
2417  if (!subVol->confinedArbitraryLayers().empty()) {
2418  Trk::ArraySpan<const Trk::Layer* const> lays = (subVol->confinedArbitraryLayers());
2419  for (const auto* lay : lays) {
2420  const Trk::MaterialProperties* mLay = lay->layerMaterialProperties()->fullMaterial(lay->surfaceRepresentation().center());
2421  // scaling factor
2422  const Trk::RectangleBounds* rect =
2423  dynamic_cast<const Trk::RectangleBounds*>(&(lay->surfaceRepresentation().bounds()));
2424  const Trk::TrapezoidBounds* trap =
2425  dynamic_cast<const Trk::TrapezoidBounds*>(&(lay->surfaceRepresentation().bounds()));
2426  if ((rect || trap) && mLay) {
2427  double scale = rect ? 4 * rect->halflengthX() * rect->halflengthY() / sf
2428  : 2 * (trap->minHalflengthX() + trap->maxHalflengthX()) * trap->halflengthY() / sf;
2429  // protect nan
2430  if (lay->thickness() > 0 && mLay->material().x0() > 0.) {
2431  layMat.addMaterial(mLay->material(), scale * lay->thickness() / mLay->material().x0());
2432  ATH_MSG_VERBOSE(" collectStationMaterial after add sub vols " << layMat);
2433  }
2434  }
2435  }
2436  }
2437  }
2438  }
2439  ATH_MSG_VERBOSE(" collectStationMaterial " << layMat);
2440  return layMat;
2441 }
2442 
2444 
2446 
2447  const Trk::CuboidVolumeBounds* box =
2448  dynamic_cast<const Trk::CuboidVolumeBounds*>(&volBounds);
2449  if (box) {
2450  ATH_MSG_DEBUG("cuboid:" << box->halflengthX() << ","
2451  << box->halflengthY() << ","
2452  << box->halflengthZ());
2453  return;
2454  }
2455  const Trk::TrapezoidVolumeBounds* trd =
2456  dynamic_cast<const Trk::TrapezoidVolumeBounds*>(&volBounds);
2457  if (trd) {
2458  ATH_MSG_DEBUG("trapezoid:" << trd->minHalflengthX() << ","
2459  << trd->maxHalflengthX() << ","
2460  << trd->halflengthY() << ","
2461  << trd->halflengthZ());
2462  return;
2463  }
2464  const Trk::DoubleTrapezoidVolumeBounds* dtrd =
2465  dynamic_cast<const Trk::DoubleTrapezoidVolumeBounds*>(&volBounds);
2466  if (dtrd) {
2467  ATH_MSG_DEBUG("double trapezoid:"
2468  << dtrd->minHalflengthX() << "," << dtrd->medHalflengthX()
2469  << "," << dtrd->maxHalflengthX() << ","
2470  << dtrd->halflengthY1() << "," << dtrd->halflengthY2()
2471  << "," << dtrd->halflengthZ());
2472  return;
2473  }
2474 
2476  dynamic_cast<const Trk::SimplePolygonBrepVolumeBounds*>(&volBounds);
2477  if (spb){
2478  ATH_MSG_DEBUG("SimplePolygonBrep bounds: number of vertices:"
2479  << spb->xyVertices().size());
2480  return;
2481  }
2482 }
2483 
2485 
2486  const Trk::CuboidVolumeBounds* box = dynamic_cast<const Trk::CuboidVolumeBounds*>(&volBounds);
2487  if (box)
2488  return box->halflengthZ();
2489 
2490  const Trk::TrapezoidVolumeBounds* trd = dynamic_cast<const Trk::TrapezoidVolumeBounds*>(&volBounds);
2491  if (trd)
2492  return trd->halflengthZ();
2493 
2494  const Trk::DoubleTrapezoidVolumeBounds* dtrd = dynamic_cast<const Trk::DoubleTrapezoidVolumeBounds*>(&volBounds);
2495  if (dtrd)
2496  return dtrd->halflengthZ();
2497 
2498  const Trk::SimplePolygonBrepVolumeBounds* spb = dynamic_cast<const Trk::SimplePolygonBrepVolumeBounds*>(&volBounds);
2499  if (spb)
2500  return spb->halflengthZ();
2501 
2502  return 0.;
2503 }
2504 
2505 std::unique_ptr<Trk::SurfaceBounds>
2507 
2508  const Trk::CuboidVolumeBounds* box =
2509  dynamic_cast<const Trk::CuboidVolumeBounds*>(&(envelope.volumeBounds()));
2510  if (box){
2511  return std::make_unique<Trk::RectangleBounds>(box->halflengthX(), box->halflengthY());
2512  }
2513  const Trk::TrapezoidVolumeBounds* trd =dynamic_cast<const Trk::TrapezoidVolumeBounds*>(&(envelope.volumeBounds()));
2514 
2515  if (trd) {
2516  return std::make_unique<Trk::TrapezoidBounds>(trd->minHalflengthX(), trd->maxHalflengthX(), trd->halflengthY());
2517  }
2518  const Trk::DoubleTrapezoidVolumeBounds* dtrd = dynamic_cast<const Trk::DoubleTrapezoidVolumeBounds*>(&(envelope.volumeBounds()));
2519 
2520  if (dtrd)
2521  return std::make_unique<Trk::DiamondBounds>(dtrd->minHalflengthX(), dtrd->medHalflengthX(),
2522  dtrd->maxHalflengthX(), dtrd->halflengthY1(), dtrd->halflengthY2());
2523 
2524  return nullptr;
2525 }
2526 
2528 
2529  const Trk::RectangleBounds* box = dynamic_cast<const Trk::RectangleBounds*>(&sb);
2530  if (box) {
2531  return 4 * box->halflengthX() * box->halflengthY();
2532  }
2533  const Trk::TrapezoidBounds* trd = dynamic_cast<const Trk::TrapezoidBounds*>(&sb);
2534  if (trd) {
2535  return 2 * (trd->minHalflengthX() + trd->maxHalflengthX()) * trd->halflengthY();
2536  }
2537  const Trk::DiamondBounds* dtrd = dynamic_cast<const Trk::DiamondBounds*>(&sb);
2538  if (dtrd) {
2539  return 2 * (dtrd->minHalflengthX() + dtrd->medHalflengthX()) * dtrd->halflengthY1() +
2540  2 * (dtrd->medHalflengthX() + dtrd->maxHalflengthX()) * dtrd->halflengthY2();
2541  }
2542  return 0.;
2543 }
Muon::MuonStationTypeBuilder::interfaceID
static const InterfaceID & interfaceID()
Interface methode.
Definition: MuonStationTypeBuilder.cxx:71
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
Trk::CuboidVolumeBounds::halflengthZ
double halflengthZ() const
This method returns the halflength in local z.
Definition: CuboidVolumeBounds.h:136
geoGetVolumes
GeoVolumeVec_t geoGetVolumes(const GeoGraphNode *node, int depthLimit=1, int sizeHint=20)
Return the child volumes and associated transforms.
Definition: GeoVisitVolumes.cxx:211
PlotCalibFromCool.il
il
Definition: PlotCalibFromCool.py:381
TrapezoidBounds.h
Trk::TrapezoidBounds::maxHalflengthX
double maxHalflengthX() const
This method returns the maximal halflength in X (first coordinate of local surface frame)
Trk::TrapezoidVolumeBounds::maxHalflengthX
double maxHalflengthX() const
This method returns the maximal halflength in local x.
Definition: TrapezoidVolumeBounds.h:160
Muon::makeTransform
Amg::Transform3D * makeTransform(const Amg::Transform3D &trf)
Definition: MuonSpectrometer/MuonDetDescr/MuonTrackingGeometry/MuonTrackingGeometry/Utils.h:14
Trk::RectangleBounds
Definition: RectangleBounds.h:38
python.SystemOfUnits.second
int second
Definition: SystemOfUnits.py:120
plotBeamSpotCompare.x1
x1
Definition: plotBeamSpotCompare.py:216
Muon::MuonStationTypeBuilder::process_MM
std::unique_ptr< Trk::DetachedTrackingVolume > process_MM(const Identifier &id, const GeoVPhysVol *gv, const Amg::Transform3D &transf) const
Definition: MuonStationTypeBuilder.cxx:1677
Trk::DiamondBounds::halflengthY2
double halflengthY2() const
Muon::MuonStationTypeBuilder::collectStationMaterial
Trk::MaterialProperties collectStationMaterial(const Trk::TrackingVolume &trVol, double) const
Definition: MuonStationTypeBuilder.cxx:2365
Amg::compare
std::pair< int, int > compare(const AmgSymMatrix(N) &m1, const AmgSymMatrix(N) &m2, double precision=1e-9, bool relative=false)
compare two matrices, returns the indices of the first element that fails the condition,...
Definition: EventPrimitivesHelpers.h:109
AddEmptyComponent.compName
compName
Definition: AddEmptyComponent.py:32
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
Trk::SimplePolygonBrepVolumeBounds::halflengthZ
double halflengthZ() const
This method returns the halflength in local z.
Definition: SimplePolygonBrepVolumeBounds.h:151
Muon::MuonStationTypeBuilder::processCscStation
std::unique_ptr< Trk::TrackingVolume > processCscStation(const GeoVPhysVol *cv, const std::string &name, Cache &) const
Definition: MuonStationTypeBuilder.cxx:1388
Trk::TrapezoidVolumeBounds::minHalflengthX
double minHalflengthX() const
This method returns the minimal halflength in local x.
Definition: TrapezoidVolumeBounds.h:157
tolerance
constexpr double tolerance
Definition: runMdtGeoComparison.cxx:105
Trk::MaterialProperties::averageA
float averageA() const
Return the average A of the material [gram/mole].
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
max
#define max(a, b)
Definition: cfImp.cxx:41
DiscBounds.h
Trk::Material::L0
float L0
Definition: Material.h:120
Muon::MuonStationTypeBuilder::processCSCDiamondComponent
std::unique_ptr< Trk::LayerArray > processCSCDiamondComponent(const GeoVPhysVol *, const Trk::DoubleTrapezoidVolumeBounds &, const Amg::Transform3D &, Cache &) const
Definition: MuonStationTypeBuilder.cxx:1908
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
RectangleBounds.h
GeoVolumeVec_t
std::vector< std::pair< const GeoVPhysVol *, GeoTrf::Transform3D > > GeoVolumeVec_t
Return the child volumes and associated transforms.
Definition: GeoVisitVolumes.h:219
Trk::SimplePolygonBrepVolumeBounds
Definition: SimplePolygonBrepVolumeBounds.h:44
Muon::MuonStationTypeBuilder::processMdtTrd
std::unique_ptr< Trk::TrackingVolume > processMdtTrd(const Trk::Volume &trkVol, const GeoVPhysVol *, const Amg::Transform3D &, Cache &) const
Definition: MuonStationTypeBuilder.cxx:867
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
Muon::MuonStationTypeBuilder::processCSCTrdComponent
std::unique_ptr< Trk::LayerArray > processCSCTrdComponent(const GeoVPhysVol *, const Trk::TrapezoidVolumeBounds &, const Amg::Transform3D &, Cache &) const
Definition: MuonStationTypeBuilder.cxx:1790
Muon::MuonStationTypeBuilder::Cache::m_rpc46
std::unique_ptr< Trk::MaterialProperties > m_rpc46
Definition: MuonStationTypeBuilder.h:58
MaterialProperties.h
Muon::MuonStationTypeBuilder::envelopeThickness
double envelopeThickness(const Trk::VolumeBounds &vb) const
Definition: MuonStationTypeBuilder.cxx:2484
Trk::CuboidVolumeBounds
Definition: CuboidVolumeBounds.h:52
sTgcReadoutElement.h
ILayerBuilder.h
Muon::MuonStationTypeBuilder::Cache::m_mdtFoamMat
std::vector< std::unique_ptr< Trk::MaterialProperties > > m_mdtFoamMat
Definition: MuonStationTypeBuilder.h:57
Trk::SurfaceBounds
Definition: SurfaceBounds.h:47
Muon::MuonStationTypeBuilder::initialize
StatusCode initialize()
AlgTool initailize method.
Definition: MuonStationTypeBuilder.cxx:88
Trk::DiamondBounds::minHalflengthX
double minHalflengthX() const
This method returns the halflength in X at minimal Y (first coordinate of local surface frame)
Trk::Material::Z
float Z
Definition: Material.h:122
Muon::MuonStationTypeBuilder::get_x_size
double get_x_size(const GeoVPhysVol *) const
Definition: MuonStationTypeBuilder.cxx:1741
mat
GeoMaterial * mat
Definition: LArDetectorConstructionTBEC.cxx:53
BinnedArray.h
OverlapDescriptor.h
Amg::getTranslateZ3D
Amg::Transform3D getTranslateZ3D(const double Z)
: Returns a shift transformation along the z-axis
Definition: GeoPrimitivesHelpers.h:285
Trk::TrapezoidBounds::halflengthY
double halflengthY() const
This method returns the halflength in Y (second coordinate of local surface frame)
Muon::MuonStationTypeBuilder::Cache::m_rpcExtPanel
std::unique_ptr< Trk::MaterialProperties > m_rpcExtPanel
Definition: MuonStationTypeBuilder.h:60
BinUtility.h
module_driven_slicing.layers
layers
Definition: module_driven_slicing.py:114
skel.it
it
Definition: skel.GENtoEVGEN.py:423
DiscLayer.h
M_PI
#define M_PI
Definition: ActiveFraction.h:11
BinningType.h
Trk::MaterialProperties::averageRho
float averageRho() const
Return the average density of the material.
Trk::CuboidVolumeBounds::halflengthX
double halflengthX() const
This method returns the halflength in local x.
Definition: CuboidVolumeBounds.h:132
HomogeneousLayerMaterial.h
Muon::MuonStationTypeBuilder::Cache::m_rpcLayer
std::unique_ptr< Trk::MaterialProperties > m_rpcLayer
Definition: MuonStationTypeBuilder.h:56
NavBinnedArray1D.h
Trk::MaterialProperties::x0
float x0() const
Return the radiation length.
Amg::getTranslateY3D
Amg::Transform3D getTranslateY3D(const double Y)
: Returns a shift transformation along the y-axis
Definition: GeoPrimitivesHelpers.h:281
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
Trk::TrapezoidBounds::minHalflengthX
double minHalflengthX() const
This method returns the minimal halflength in X (first coordinate of local surface frame)
PlotCalibFromCool.multi
multi
Definition: PlotCalibFromCool.py:99
Muon::MuonStationTypeBuilder::processMdtBox
std::unique_ptr< Trk::TrackingVolume > processMdtBox(const Trk::Volume &trkVol, const GeoVPhysVol *, const Amg::Transform3D &, double, Cache &) const
components
Definition: MuonStationTypeBuilder.cxx:714
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
Muon::MuonStationTypeBuilder::getLayerBoundsFromEnvelope
std::unique_ptr< Trk::SurfaceBounds > getLayerBoundsFromEnvelope(const Trk::Volume &envelope) const
Definition: MuonStationTypeBuilder.cxx:2506
python.compareNtuple.vName
vName
Definition: compareNtuple.py:23
Trk::MaterialProperties::material
const Material & material() const
Return the stored Material.
yodamerge_tmp.scale
scale
Definition: yodamerge_tmp.py:138
x
#define x
Trk::SimplePolygonBrepVolumeBounds::xyVertices
std::vector< std::pair< double, double > > xyVertices() const
This method returns the set of xy generating vertices.
Definition: SimplePolygonBrepVolumeBounds.h:147
spacer
const std::string spacer
Definition: spacer.h:24
ILayerArrayCreator.h
makeTRTBarrelCans.y1
tuple y1
Definition: makeTRTBarrelCans.py:15
TrapezoidVolumeBounds.h
Trk::DoubleTrapezoidVolumeBounds::halflengthZ
double halflengthZ() const
This method returns the halflength in local z.
Definition: DoubleTrapezoidVolumeBounds.h:200
Trk::TrapezoidVolumeBounds::halflengthY
double halflengthY() const
This method returns the halflength in local y.
Definition: TrapezoidVolumeBounds.h:163
Amg::getRotateZ3D
Amg::Transform3D getRotateZ3D(double angle)
get a rotation transformation around Z-axis
Definition: GeoPrimitivesHelpers.h:270
Muon::MuonStationTypeBuilder::processTGCComponent
std::unique_ptr< Trk::LayerArray > processTGCComponent(const GeoVPhysVol *, const Trk::TrapezoidVolumeBounds &, const Amg::Transform3D &, Cache &) const
Definition: MuonStationTypeBuilder.cxx:2028
Trk::DoubleTrapezoidVolumeBounds::maxHalflengthX
double maxHalflengthX() const
This method returns the X halflength at maximal Y (local coordinates)
Definition: DoubleTrapezoidVolumeBounds.h:188
Trk::TrackingVolume::confinedLayers
const LayerArray * confinedLayers() const
Return the subLayer array.
Trk::MaterialProperties::thickness
float thickness() const
Return the thickness in mm.
Muon::MuonStationTypeBuilder::decodeX
double decodeX(const GeoShape *) const
Definition: MuonStationTypeBuilder.cxx:2136
Trk::DiamondBounds::medHalflengthX
double medHalflengthX() const
This method returns the (maximal) halflength in X (first coordinate of local surface frame)
DiamondBounds.h
Trk::CuboidVolumeBounds::halflengthY
double halflengthY() const
This method returns the halflength in local y.
Definition: CuboidVolumeBounds.h:134
VolumeExcluder.h
GeometryStatics.h
GeoVisitVolumes.h
Visitor to process all volumes under a GeoModel node.
Trk::VolumeBounds
Definition: VolumeBounds.h:45
CylinderVolumeBounds.h
Muon::MuonStationTypeBuilder::processTrdStationComponents
std::unique_ptr< Trk::TrackingVolumeArray > processTrdStationComponents(const GeoVPhysVol *cv, const Trk::TrapezoidVolumeBounds &envBounds, Cache &) const
Definition: MuonStationTypeBuilder.cxx:462
MMReadoutElement.h
Trk::MaterialProperties::addMaterial
void addMaterial(const Material &mp, float dInX0)
Material averaging.
Definition: MaterialProperties.cxx:46
Amg::getRotateX3D
Amg::Transform3D getRotateX3D(double angle)
get a rotation transformation around X-axis
Definition: GeoPrimitivesHelpers.h:252
SubtractedPlaneSurface.h
Trk::Material::x0
float x0() const
Definition: Material.h:226
Trk::DiamondBounds
Definition: DiamondBounds.h:37
Amg::toString
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Definition: GeoPrimitivesToStringConverter.h:40
Muon::MuonStationTypeBuilder::Cache::m_matCSC02
std::unique_ptr< Trk::MaterialProperties > m_matCSC02
Definition: MuonStationTypeBuilder.h:64
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
Muon::MuonStationTypeBuilder::MuonStationTypeBuilder
MuonStationTypeBuilder(const std::string &, const std::string &, const IInterface *)
Constructor.
Definition: MuonStationTypeBuilder.cxx:79
Muon::MuonStationTypeBuilder::Cache
Definition: MuonStationTypeBuilder.h:54
FullCPAlgorithmsTest_eljob.sh
sh
Definition: FullCPAlgorithmsTest_eljob.py:98
Trk::active
@ active
Definition: Layer.h:48
Trk::RectangleBounds::halflengthX
double halflengthX() const
for consistant naming
lumiFormat.i
int i
Definition: lumiFormat.py:92
Trk::Material::A
float A
Definition: Material.h:121
Muon::MuonStationTypeBuilder::processTgcStation
std::unique_ptr< Trk::TrackingVolume > processTgcStation(const GeoVPhysVol *cv, Cache &) const
Definition: MuonStationTypeBuilder.cxx:1573
z
#define z
Trk::ArraySpan
std::span< T > ArraySpan
Definition: DetachedTrackingVolume.h:34
Trk::DoubleTrapezoidVolumeBounds::halflengthY1
double halflengthY1() const
This method returns the halflength1 in local y.
Definition: DoubleTrapezoidVolumeBounds.h:192
Identifier
Definition: DetectorDescription/Identifier/Identifier/Identifier.h:32
beamspotman.n
n
Definition: beamspotman.py:731
Trk::TrackingVolume::confinedArbitraryLayers
ArraySpan< Layer const *const > confinedArbitraryLayers() const
Return the confined subLayer array.
RCU::Shell
Definition: ShellExec.cxx:28
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
sTgcIdHelper::Wire
@ Wire
Definition: sTgcIdHelper.h:190
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
Muon::MuonStationTypeBuilder::Cache::m_matTGC06
std::unique_ptr< Trk::MaterialProperties > m_matTGC06
Definition: MuonStationTypeBuilder.h:67
xAOD::rotation
rotation
Definition: TrackSurface_v1.cxx:15
TRT::Hit::layer
@ layer
Definition: HitInfo.h:79
makeTRTBarrelCans.y2
tuple y2
Definition: makeTRTBarrelCans.py:18
Amg::Transform3D
Eigen::Affine3d Transform3D
Definition: GeoPrimitives.h:46
Amg::transform
Amg::Vector3D transform(Amg::Vector3D &v, Amg::Transform3D &tr)
Transform a point from a Trasformation3D.
Definition: GeoPrimitivesHelpers.h:156
Muon::MuonStationTypeBuilder::area
double area(const Trk::SurfaceBounds &sb) const
Definition: MuonStationTypeBuilder.cxx:2527
sign
int sign(int a)
Definition: TRT_StrawNeighbourSvc.h:127
RotatedDiamondBounds.h
Muon::MuonStationTypeBuilder::Cache::m_matCSCspacer1
std::unique_ptr< Trk::MaterialProperties > m_matCSCspacer1
Definition: MuonStationTypeBuilder.h:63
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
CylinderLayer.h
Amg::isIdentity
bool isIdentity(const Amg::Transform3D &trans)
Checks whether the transformation is the Identity transformation.
Definition: GeoPrimitivesHelpers.h:348
Trk::binX
@ binX
Definition: BinningType.h:47
Trk::DoubleTrapezoidVolumeBounds::halflengthY2
double halflengthY2() const
This method returns the halflength2 in local y.
Definition: DoubleTrapezoidVolumeBounds.h:196
SharedObject.h
SubtractedPlaneLayer.h
Muon::MuonStationTypeBuilder::processRpc
std::unique_ptr< Trk::TrackingVolume > processRpc(const Trk::Volume &inVol, const std::vector< const GeoVPhysVol * > &childVols, const std::vector< Amg::Transform3D > &childVolsTrf, Cache &) const
Definition: MuonStationTypeBuilder.cxx:1001
Trk::SubtractedVolumeBounds::outer
const Volume * outer() const
This method returns the outer Volume.
Definition: SubtractedVolumeBounds.h:113
Trk::Material::X0
float X0
Definition: Material.h:119
DetachedTrackingVolume.h
min
#define min(a, b)
Definition: cfImp.cxx:40
Muon::MuonStationTypeBuilder::createLayerRepresentation
std::pair< std::unique_ptr< Trk::Layer >, std::vector< std::unique_ptr< Trk::Layer > > > createLayerRepresentation(Trk::TrackingVolume &trVol) const
Definition: MuonStationTypeBuilder.cxx:2193
grepfile.ic
int ic
Definition: grepfile.py:33
Muon::MuonStationTypeBuilder::Cache::m_matTGC01
std::unique_ptr< Trk::MaterialProperties > m_matTGC01
Definition: MuonStationTypeBuilder.h:66
CaloCondBlobAlgs_fillNoiseFromASCII.comment
string comment
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:27
tolerance
Definition: suep_shower.h:17
Muon::MuonStationTypeBuilder::process_sTGC
std::unique_ptr< Trk::DetachedTrackingVolume > process_sTGC(const Identifier &id, const GeoVPhysVol *gv, const Amg::Transform3D &transf) const
Definition: MuonStationTypeBuilder.cxx:1608
Trk::TrackingVolume::volumeName
const std::string & volumeName() const
Returns the VolumeName - for debug reason, might be depreciated later.
keylayer_zslicemap.sb
sb
Definition: keylayer_zslicemap.py:192
SimplePolygonBrepVolumeBounds.h
DoubleTrapezoidVolumeBounds.h
id
SG::auxid_t id
Definition: Control/AthContainers/Root/debug.cxx:191
Muon::MuonStationTypeBuilder::Cache::m_matCSCspacer2
std::unique_ptr< Trk::MaterialProperties > m_matCSCspacer2
Definition: MuonStationTypeBuilder.h:65
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:192
Muon::toVec
std::vector< std::unique_ptr< ObjType > > toVec(const std::vector< ObjType * > *vecPtr)
Definition: MuonSpectrometer/MuonDetDescr/MuonTrackingGeometry/MuonTrackingGeometry/Utils.h:38
Trk::BinnedArray::arrayObjects
virtual BinnedArraySpan< T *const > arrayObjects()=0
Return all objects of the Array non-const we can still modify the T.
GeoMaterialConverter.h
Trk::RectangleBounds::halflengthY
double halflengthY() const
for consitant naming
Muon::MuonStationTypeBuilder::Cache::m_matCSC01
std::unique_ptr< Trk::MaterialProperties > m_matCSC01
Definition: MuonStationTypeBuilder.h:62
sTgcIdHelper
Definition: sTgcIdHelper.h:55
MuonStationTypeBuilder.h
Trk::Volume::transform
const Amg::Transform3D & transform() const
Return methods for geometry transform.
Definition: Volume.h:81
Trk::TrapezoidVolumeBounds
Definition: TrapezoidVolumeBounds.h:57
Amg::getRotateY3D
Amg::Transform3D getRotateY3D(double angle)
get a rotation transformation around Y-axis
Definition: GeoPrimitivesHelpers.h:261
Trk::DiamondBounds::maxHalflengthX
double maxHalflengthX() const
This method returns the halflength in X at maximal Y (first coordinate of local surface frame)
Muon::MuonStationTypeBuilder::Cache::m_rpcMidPanel
std::unique_ptr< Trk::MaterialProperties > m_rpcMidPanel
Definition: MuonStationTypeBuilder.h:61
Trk::DoubleTrapezoidVolumeBounds::decomposeToSurfaces
const std::vector< const Trk::Surface * > * decomposeToSurfaces(const Amg::Transform3D &transform) override final
Method to decompose the Bounds into Surfaces.
Definition: DoubleTrapezoidVolumeBounds.cxx:94
MuonDetectorManager.h
DataModelTestDataCommonDict::xb
DMTest::CView::Pers_t xb
Definition: DataModelTestDataCommonDict.h:44
Trk::TrapezoidBounds
Definition: TrapezoidBounds.h:43
Trk::Material::rho
float rho
Definition: Material.h:123
BoundarySurface.h
Muon::MuonStationTypeBuilder::finalize
StatusCode finalize()
AlgTool finalize method.
Definition: MuonStationTypeBuilder.cxx:709
Muon::MuonStationTypeBuilder::getAveragedLayerMaterial
Trk::MaterialProperties getAveragedLayerMaterial(const GeoVPhysVol *, double, double) const
Definition: MuonStationTypeBuilder.cxx:1759
Trk::iPhi
@ iPhi
Definition: ParamDefs.h:53
Muon::MuonStationTypeBuilder::processBoxComponentsArbitrary
std::vector< std::unique_ptr< Trk::Layer > > processBoxComponentsArbitrary(const GeoVPhysVol *mv, const Trk::CuboidVolumeBounds &envBounds, Cache &cache) const
Definition: MuonStationTypeBuilder.cxx:107
Trk::open
@ open
Definition: BinningType.h:40
ReadCellNoiseFromCoolCompare.v2
v2
Definition: ReadCellNoiseFromCoolCompare.py:364
Trk::MaterialProperties
Definition: MaterialProperties.h:40
Trk::SharedObject
std::shared_ptr< T > SharedObject
Definition: SharedObject.h:24
Trk::DoubleTrapezoidVolumeBounds::minHalflengthX
double minHalflengthX() const
This method returns the X halflength at minimal Y.
Definition: DoubleTrapezoidVolumeBounds.h:180
MmIdHelper
Definition: MmIdHelper.h:54
Trk::DiamondBounds::halflengthY1
double halflengthY1() const
This method returns the halflength in Y of trapezoid at negative/positive Y (second coordinate)
CondAlgsOpts.found
int found
Definition: CondAlgsOpts.py:101
mapkey::sf
@ sf
Definition: TElectronEfficiencyCorrectionTool.cxx:38
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
ref
const boost::regex ref(r_ef)
Trk::PlaneSurface
Definition: PlaneSurface.h:64
Muon::MuonStationTypeBuilder::identifyNSW
Identifier identifyNSW(const std::string &, const Amg::Transform3D &) const
Definition: MuonStationTypeBuilder.cxx:2319
Muon::MuonStationTypeBuilder::printVolumeBounds
void printVolumeBounds(std::string comment, const Trk::VolumeBounds &vb) const
Definition: MuonStationTypeBuilder.cxx:2443
Trk::DoubleTrapezoidVolumeBounds::medHalflengthX
double medHalflengthX() const
This method returns the (maximal) halflength in local x.
Definition: DoubleTrapezoidVolumeBounds.h:184
GeoPrimitivesHelpers.h
Trk::TrackingVolume::confinedVolumes
const TrackingVolumeArray * confinedVolumes() const
Return the subLayer array.
Trk::SubtractedVolumeBounds
Definition: SubtractedVolumeBounds.h:40
Trk::TrapezoidVolumeBounds::decomposeToSurfaces
const std::vector< const Trk::Surface * > * decomposeToSurfaces(const Amg::Transform3D &transform) override final
Method to decompose the Bounds into Surfaces.
Definition: TrapezoidVolumeBounds.cxx:105
Muon::MuonStationTypeBuilder::Cache::m_rpcDed
std::vector< std::unique_ptr< Trk::MaterialProperties > > m_rpcDed
Definition: MuonStationTypeBuilder.h:59
Trk::MaterialProperties::averageZ
float averageZ() const
Returns the average Z of the material.
Trk::Volume::volumeBounds
const VolumeBounds & volumeBounds() const
returns the volumeBounds()
Definition: Volume.h:97
Trk::DoubleTrapezoidVolumeBounds
Definition: DoubleTrapezoidVolumeBounds.h:66
python.changerun.pv
pv
Definition: changerun.py:81
GeoPrimitivesToStringConverter.h
LArNewCalib_DelayDump_OFC_Cali.idx
idx
Definition: LArNewCalib_DelayDump_OFC_Cali.py:69
CombinedVolumeBounds.h
TrackingGeometry.h
Trk::TrapezoidVolumeBounds::halflengthZ
double halflengthZ() const
This method returns the halflength in local z.
Definition: TrapezoidVolumeBounds.h:164
Trk::Material
Definition: Material.h:116
Muon::MuonStationTypeBuilder::Cache::m_mdtTubeMat
std::unique_ptr< Trk::MaterialProperties > m_mdtTubeMat
Definition: MuonStationTypeBuilder.h:55
area
double area(double R)
Definition: ConvertStaveServices.cxx:42
AthAlgTool
Definition: AthAlgTool.h:26
Trk::HomogeneousLayerMaterial
Definition: HomogeneousLayerMaterial.h:53
RotatedTrapezoidBounds.h
Trk::Volume
Definition: Volume.h:35
xAOD::iEta
setScale setgFexType iEta
Definition: gFexJetRoI_v1.cxx:74
Trk::MaterialProperties::l0
float l0() const
Return the nuclear interaction length.
Trk::TrackingVolume
Definition: TrackingVolume.h:121
Trk::BinnedArraySpan
std::span< T > BinnedArraySpan
Definition: BinnedArray.h:34
Amg::getTranslateX3D
Amg::Transform3D getTranslateX3D(const double X)
: Returns a shift transformation along the x-axis
Definition: GeoPrimitivesHelpers.h:277
Utils.h
Muon::MuonStationTypeBuilder::processSpacer
std::unique_ptr< Trk::TrackingVolume > processSpacer(const Trk::Volume &, std::vector< const GeoVPhysVol * >, std::vector< Amg::Transform3D >) const
Definition: MuonStationTypeBuilder.cxx:1186
Muon::release
std::vector< ObjType * > release(std::vector< std::unique_ptr< ObjType >> &objVec)
Definition: MuonSpectrometer/MuonDetDescr/MuonTrackingGeometry/MuonTrackingGeometry/Utils.h:18
calibdata.tube
tube
Definition: calibdata.py:31
CuboidVolumeBounds.h
Material.h
LayerMaterialProperties.h
Amg::getTranslate3D
Amg::Transform3D getTranslate3D(const double X, const double Y, const double Z)
: Returns a shift transformation along an arbitrary axis
Definition: GeoPrimitivesHelpers.h:289
PlaneLayer.h
SubtractedVolumeBounds.h
Muon::MuonStationTypeBuilder::processBoxStationComponents
std::unique_ptr< Trk::TrackingVolumeArray > processBoxStationComponents(const GeoVPhysVol *cv, const Trk::CuboidVolumeBounds &envBounds, Cache &) const
steering routine
Definition: MuonStationTypeBuilder.cxx:134