ATLAS Offline Software
TgcReadoutGeomTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #include "TgcReadoutGeomTool.h"
6 
7 #include <GaudiKernel/SystemOfUnits.h>
10 
11 #include <GeoModelKernel/GeoFullPhysVol.h>
12 #include <GeoModelKernel/GeoPhysVol.h>
13 #include <GeoModelKernel/GeoTrd.h>
14 #include <GeoModelKernel/GeoBox.h>
15 
16 #include <GeoModelRead/ReadGeoModel.h>
20 
21 #include <format>
23 
25 
26 #ifndef SIMULATIONBASE
27 # include "Acts/Utilities/BoundFactory.hpp"
28 #endif
29 
30 using namespace CxxUtils;
31 using namespace ActsTrk;
32 
33 namespace MuonGMR4 {
34 
37 
38 
39 
40 std::unique_ptr<WireGroupDesign>
41  TgcReadoutGeomTool::constructWireDesign(const wTgcTable& table,
42  const GeoTrd* gapTrd) const {
43  if (table.wireGangs.empty()) {
44  return nullptr;
45  }
46  const double halfMinX = std::min(gapTrd->getYHalfLength1(), gapTrd->getYHalfLength2());
47  const double halfMaxX = std::max(gapTrd->getYHalfLength1(), gapTrd->getYHalfLength2());
48  const double halfY = gapTrd->getZHalfLength();
49  auto design = std::make_unique<WireGroupDesign>();
50  design->defineTrapezoid(halfMinX, halfMaxX, halfY);
51  for (unsigned gang : table.wireGangs) {
52  design->declareGroup(gang);
53  }
54  const double wireOffSet = -0.5*table.wirePitch * design->nAllWires();
55  design->defineStripLayout(Amg::Vector2D{wireOffSet, 0.},
56  table.wirePitch, 0., table.wireGangs.size());
57  return design;
58 }
59 std::unique_ptr<RadialStripDesign>
60  TgcReadoutGeomTool::constructRadialDesign(const wTgcTable& table,
61  const GeoTrd* gapTrd) const {
62  if (table.bottomStripPos.empty()) {
63  return nullptr;
64  }
65  const double halfMinX = std::min(gapTrd->getYHalfLength1(), gapTrd->getYHalfLength2());
66  const double halfMaxX = std::max(gapTrd->getYHalfLength1(), gapTrd->getYHalfLength2());
67  const double halfY = gapTrd->getZHalfLength();
68 
69  auto design = std::make_unique<RadialStripDesign>();
70 
71  design->defineTrapezoid(halfMinX, halfMaxX, halfY);
72  design->defineStripLayout(Amg::Vector2D{-halfY,0.},
73  0.,0.,table.bottomStripPos.size());
74  design->flipTrapezoid();
75  for (size_t s = 0; s < table.bottomStripPos.size(); ++s) {
76  design->addStrip(table.bottomStripPos.at(s),
77  table.topStripPos.at(s));
78  }
79  return design;
80 }
81 
82 StatusCode TgcReadoutGeomTool::loadDimensions(TgcReadoutElement::defineArgs& define,
83  FactoryCache& factoryCache) {
84  ATH_MSG_VERBOSE("Load dimensions of "<<m_idHelperSvc->toString(define.detElId)
85  <<std::endl<<std::endl<<m_geoUtilTool->dumpVolume(define.physVol));
86  const GeoShape* shape = m_geoUtilTool->extractShape(define.physVol);
87  if (!shape) {
88  ATH_MSG_FATAL("Failed to deduce a valid shape for "<<m_idHelperSvc->toString(define.detElId));
89  return StatusCode::FAILURE;
90  }
91 
92  if (shape->typeID() != GeoTrd::getClassTypeID()) {
93  ATH_MSG_FATAL("The shape of "<<m_idHelperSvc->toStringDetEl(define.detElId)
94  <<" is expected to be a trapezoid "<<m_geoUtilTool->dumpShape(shape));
95  return StatusCode::FAILURE;
96  }
97  const GeoTrd* chambTrd = static_cast<const GeoTrd*>(shape);
98  define.halfWidthShort = std::min(chambTrd->getYHalfLength1(), chambTrd->getYHalfLength2());
99  define.halfWidthLong = std::max(chambTrd->getYHalfLength1(), chambTrd->getYHalfLength2());
100  define.halfHeight = chambTrd->getZHalfLength();
101  define.halfThickness = chambTrd->getXHalfLength1();
103  std::vector<physVolWithTrans> allGasGaps = m_geoUtilTool->findAllLeafNodesByName(define.physVol, "TgcGas");
104  if (allGasGaps.empty()) {
105  ATH_MSG_FATAL("The volume "<<m_idHelperSvc->toStringDetEl(define.detElId)<<" does not have any childern TgcGas"
106  <<std::endl<<m_geoUtilTool->dumpVolume(define.physVol));
107  return StatusCode::FAILURE;
108  }
109  unsigned gasGap{0};
111  auto assignReadoutLayer = [&define, & gasGap, this] (const StripLayerPtr& layerReadout) {
112  if (!layerReadout) {
113  return StatusCode::SUCCESS;
114  }
115  unsigned layerIdx = static_cast<unsigned>(layerReadout->hash());
116  if (layerIdx >= define.sensorLayouts.size()) {
117  ATH_MSG_FATAL("The strip index "<<layerIdx<<" is out of range for gasGap "<<gasGap);
118  return StatusCode::FAILURE;
119  }
120  define.sensorLayouts[layerIdx] = layerReadout;
121  return StatusCode::SUCCESS;
122  };
123  for (const physVolWithTrans& pVolTrans : allGasGaps) {
124  const std::string key = std::format("{:}_{:}{:}",define.chambDesign, gasGap+1,
125  (m_idHelperSvc->stationEta(define.detElId) > 0 ? "A" : "C"));
126  StripLayerPtr& wireReadout{factoryCache.wireLayers[key]};
127  StripLayerPtr& stripReadout{factoryCache.stripLayers[key]};
128  if (!wireReadout || !stripReadout) {
129  const wTgcTable& table{factoryCache.parameterBook[key]};
130  if (!table.gasGap) {
131  ATH_MSG_FATAL("No wTGC table could be found for "<<m_idHelperSvc->toStringDetEl(define.detElId)
132  <<" "<<define.chambDesign<<", gasGap "<<(gasGap+1));
133  return StatusCode::FAILURE;
134  }
135  const GeoShape* gapShape = m_geoUtilTool->extractShape(pVolTrans.volume);
136  if (gapShape->typeID() != GeoTrd::getClassTypeID()) {
137  ATH_MSG_FATAL("Expected shape "<<m_geoUtilTool->dumpShape(gapShape)<<" to be a trapezoid");
138  return StatusCode::FAILURE;
139  }
140  const GeoTrd* gapTrd = static_cast<const GeoTrd*>(gapShape);
141  WireDesignPtr wireDesign = constructWireDesign(table, gapTrd);
142  RadialStripDesignPtr radDesign = constructRadialDesign(table, gapTrd);
143  if (wireDesign) {
144  wireDesign = (*factoryCache.wireLayouts.insert(std::move(wireDesign)).first);
145  }
146  if (radDesign) {
147  radDesign = (*factoryCache.stripReadouts.insert(std::move(radDesign)).first);
148  }
150  if (!wireReadout && wireDesign) {
151  const IdentifierHash layHash = TgcReadoutElement::constructHash(0, gasGap+1, false);
152  ATH_MSG_VERBOSE("Wire hash "<<layHash);
153  const Amg::Transform3D trans{pVolTrans.transform
159  if (false && radDesign) {
160  wireReadout = std::make_unique<StripLayer>(factoryCache.trfNodeMaker.makeTransform(trans),
161  wireDesign, radDesign, layHash);
162  wireReadout->flipPhiRotation();
163  } else {
164  wireReadout = std::make_unique<StripLayer>(factoryCache.trfNodeMaker.makeTransform(trans),
165  wireDesign, layHash);
166  }
167  }
168  if (!stripReadout && radDesign) {
169  const IdentifierHash layHash = TgcReadoutElement::constructHash(0, gasGap+1, true);
170  ATH_MSG_VERBOSE("Radial hash "<<layHash);
171  const Amg::Transform3D trans{pVolTrans.transform
174  stripReadout = std::make_unique<StripLayer>(factoryCache.trfNodeMaker.makeTransform(trans),
175  radDesign, layHash);
176  }
177  }
178  ATH_CHECK(assignReadoutLayer(stripReadout));
179  ATH_CHECK(assignReadoutLayer(wireReadout));
180  ++gasGap;
181  }
182  define.nGasGaps = gasGap;
183  return StatusCode::SUCCESS;
184 }
185 StatusCode TgcReadoutGeomTool::buildReadOutElements(MuonDetectorManager& mgr) {
186  ATH_CHECK(m_geoDbTagSvc.retrieve());
187  ATH_CHECK(m_idHelperSvc.retrieve());
188  ATH_CHECK(m_geoUtilTool.retrieve());
189  GeoModelIO::ReadGeoModel* sqliteReader = m_geoDbTagSvc->getSqliteReader();
190  if (!sqliteReader) {
191  ATH_MSG_FATAL("Error, the tool works exclusively from sqlite geometry inputs");
192  return StatusCode::FAILURE;
193  }
194 
195  FactoryCache facCache{};
196  ATH_CHECK(readParameterBook(facCache));
197 
198 #ifndef SIMULATIONBASE
199  auto layerBounds = std::make_shared<Acts::SurfaceBoundFactory>();
200 #endif
201  const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
202  // Get the list of full phys volumes from SQLite, and create detector elements
204  physNodeMap mapFPV = sqliteReader->getPublishedNodes<std::string, GeoFullPhysVol*>("Muon");
205  for (auto& [key, pv] : mapFPV) {
209  std::vector<std::string> key_tokens = tokenize(key, "_");
210  if (key_tokens.size() < 4 ||
211  !key_tokens[0].starts_with( "TGC"))
212  continue;
213 
214  bool isValid{false};
215  const Identifier elementID = idHelper.elementID(key_tokens[1].substr(0,3), atoi(key_tokens[2]), atoi(key_tokens[3]), isValid);
217  if (!isValid){
218  ATH_MSG_FATAL("Failed to construct the station Identifier from "<<key);
219  return StatusCode::FAILURE;
220  }
221  defineArgs define{};
222  define.physVol = pv;
223  define.detElId = elementID;
224  define.chambDesign = key_tokens[0];
225  define.alignTransform = m_geoUtilTool->findAlignableTransform(define.physVol);
226 #ifndef SIMULATIONBASE
227  define.layerBounds = layerBounds;
228 #endif
229  ATH_MSG_DEBUG("Key "<<key<<" lead to Identifier "<<m_idHelperSvc->toStringDetEl(define.detElId));
230  ATH_CHECK(loadDimensions(define, facCache));
231  std::unique_ptr<TgcReadoutElement> readoutEle = std::make_unique<TgcReadoutElement>(std::move(define));
232  ATH_CHECK(mgr.addTgcReadoutElement(std::move(readoutEle)));
233  }
234  ATH_CHECK(writeSectorMapping(mgr));
235  return StatusCode::SUCCESS;
236 }
237 StatusCode TgcReadoutGeomTool::writeSectorMapping(const MuonDetectorManager& mgr) const {
239  std::vector<const TgcReadoutElement*> tgcReadOutEles = mgr.getAllTgcReadoutElements();
240  std::unique_ptr<std::vector<int>> tgcSectorMapping = std::make_unique<std::vector<int>>();
241  tgcSectorMapping->resize(m_idHelperSvc->tgcIdHelper().module_hash_max());
242  Muon::MuonSectorMapping sectorMapping{};
243  const ActsGeometryContext gctx{};
244  for (const TgcReadoutElement* readoutEle : tgcReadOutEles) {
245  int& sectNumb = (*tgcSectorMapping)[m_idHelperSvc->moduleHash(readoutEle->identify())];
246  sectNumb = sectorMapping.getSector(readoutEle->center(gctx).phi());
247  }
248  ATH_CHECK(detStore()->record(std::move(tgcSectorMapping), "TGC_SectorMapping"));
249  return StatusCode::SUCCESS;
250 }
251 StatusCode TgcReadoutGeomTool::readParameterBook(FactoryCache& cache) {
252  ServiceHandle<IRDBAccessSvc> accessSvc(m_geoDbTagSvc->getParamSvcName(), name());
253  ATH_CHECK(accessSvc.retrieve());
254  IRDBRecordset_ptr paramTable = accessSvc->getRecordsetPtr("TgcSensorLayout", "");
255  if (paramTable->size() == 0) {
256  ATH_MSG_FATAL("Empty parameter book table found");
257  return StatusCode::FAILURE;
258  }
259  for (const IRDBRecord_ptr& record : *paramTable) {
260  const std::string chambType = record->getString("technology");
261  const int gasGap = record->getInt("gasGap");
262  const std::vector<int> wireGangs{tokenizeInt(record->getString("wireGangs"),",")};
263  const std::vector<double> botStrips = tokenizeDouble(record->getString("bottomStrips"), ",");
264  const std::vector<double> topStrips = tokenizeDouble(record->getString("topStrips"), ",");
265  const std::vector<std::string> sides = tokenize(record->getString("side"), ";");
266  const double wirePitch = record->getDouble("wirePitch");
267  for (const std::string& side : sides) {
268  const std::string key = std::format("{:}_{:}{:}", chambType, gasGap, side);
269  wTgcTable& parBook{cache.parameterBook[key]};
270  parBook.wireGangs.insert(parBook.wireGangs.end(), wireGangs.begin(), wireGangs.end());
271  parBook.bottomStripPos = botStrips;
272  parBook.topStripPos = topStrips;
273  parBook.wirePitch = wirePitch;
274  parBook.gasGap = gasGap;
275  }
276 
277  }
278  ATH_MSG_DEBUG("Read in total "<<cache.parameterBook.size()<<" chamber layouts");
279  return StatusCode::SUCCESS;
280 }
281 } // namespace MuonGMR4
GeoModel::TransientConstSharedPtr
The TransientConstSharedPtr allows non-const access if the pointer itself is non-const but in the con...
Definition: TransientConstSharedPtr.h:13
dumpTgcDigiDeadChambers.gasGap
list gasGap
Definition: dumpTgcDigiDeadChambers.py:33
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
CxxUtils::tokenizeDouble
std::vector< double > tokenizeDouble(const std::string &the_str, std::string_view delimiter)
Definition: Control/CxxUtils/Root/StringUtils.cxx:34
MuonGMR4::RpcReadoutElement::defineArgs
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/RpcReadoutElement.h:48
vtune_athena.format
format
Definition: vtune_athena.py:14
MuonGMR4::MuonDetectorManager
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MuonDetectorManager.h:62
TgcIdHelper
Definition: TgcIdHelper.h:50
RPDUtils::sides
constexpr std::initializer_list< unsigned int > sides
Definition: RPDUtils.h:17
Amg::Vector2D
Eigen::Matrix< double, 2, 1 > Vector2D
Definition: GeoPrimitives.h:48
CxxUtils::tokenizeInt
std::vector< int > tokenizeInt(const std::string &the_str, std::string_view delimiter)
Definition: Control/CxxUtils/Root/StringUtils.cxx:55
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
CxxUtils::tokenize
std::vector< std::string > tokenize(const std::string &the_str, std::string_view delimiters)
Splits the string into smaller substrings.
Definition: Control/CxxUtils/Root/StringUtils.cxx:15
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
MuonGMR4::TgcReadoutGeomTool::wTgcTable
Helper struct to cache the essential readout parameters from the WTGC tables.
Definition: TgcReadoutGeomTool.h:38
WireGroupDesign.h
MuonGMR4::TgcReadoutElement::parameterBook::halfThickness
double halfThickness
Describe the chamber dimensions Half thickness of the chamber.
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/TgcReadoutElement.h:27
deg
#define deg
Definition: SbPolyhedron.cxx:17
RadialStripDesign.h
MuonGMR4::TgcReadoutGeomTool::FactoryCache::trfNodeMaker
GeoDeDuplicator trfNodeMaker
Helper object to turn Amg::Transforms into GeoModel tree transform nodes.
Definition: TgcReadoutGeomTool.h:62
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
isValid
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
Definition: AtlasPID.h:867
Amg::getRotateZ3D
Amg::Transform3D getRotateZ3D(double angle)
get a rotation transformation around Z-axis
Definition: GeoPrimitivesHelpers.h:270
TRT::Hit::side
@ side
Definition: HitInfo.h:83
BchCleanup.mgr
mgr
Definition: BchCleanup.py:294
Amg::getRotateX3D
Amg::Transform3D getRotateX3D(double angle)
get a rotation transformation around X-axis
Definition: GeoPrimitivesHelpers.h:252
IRDBAccessSvc.h
Definition of the abstract IRDBAccessSvc interface.
MuonGMR4
The ReadoutGeomCnvAlg converts the Run4 Readout geometry build from the GeoModelXML into the legacy M...
Definition: MdtCalibInput.h:19
MuonGMR4::TgcReadoutElement::parameterBook::nGasGaps
unsigned nGasGaps
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/TgcReadoutElement.h:35
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
Amg::Transform3D
Eigen::Affine3d Transform3D
Definition: GeoPrimitives.h:46
CxxUtils
Definition: aligned_vector.h:29
MuonGMR4::TgcReadoutElement::parameterBook::halfWidthLong
double halfWidthLong
Half length of the chamber long edge (Top)
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/TgcReadoutElement.h:33
MuonDetectorManager.h
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
MuonGMR4::TgcReadoutGeomTool::FactoryCache::wireLayouts
WireGroupDesignSet wireLayouts
Set to share equivalent WireGroupDesigns across multiple gas gaps.
Definition: TgcReadoutGeomTool.h:60
TgcReadoutGeomTool.h
MuonGMR4::TgcReadoutElement::parameterBook::halfWidthShort
double halfWidthShort
Half length of the chamber short edge (Bottom)
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/TgcReadoutElement.h:31
IRDBRecordset_ptr
std::shared_ptr< IRDBRecordset > IRDBRecordset_ptr
Definition: IRDBAccessSvc.h:25
ActsGeometryContext
Include the GeoPrimitives which need to be put first.
Definition: ActsGeometryContext.h:27
MuonGMR4::TgcReadoutGeomTool::FactoryCache::stripLayers
ReadoutTable stripLayers
Definition: TgcReadoutGeomTool.h:55
MuonGMR4::TgcReadoutElement::defineArgs
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/TgcReadoutElement.h:45
python.PyKernel.detStore
detStore
Definition: PyKernel.py:41
MuonGMR4::MuonReadoutElement::defineArgs::chambDesign
std::string chambDesign
chamber design name as it's occuring in the parameter book tables E.g. BMS5, RPC10,...
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MuonReadoutElement.h:49
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
MuonGMR4::TgcReadoutGeomTool::FactoryCache::wireLayers
ReadoutTable wireLayers
Definition: TgcReadoutGeomTool.h:54
MuonGMR4::TgcReadoutGeomTool::FactoryCache::stripReadouts
RadialStripDesignSet stripReadouts
Set to share equivalent RadialStripDesigns across multiple gas gaps.
Definition: TgcReadoutGeomTool.h:58
python.ext.table_printer.table
list table
Definition: table_printer.py:78
MuonGMR4::physVolWithTrans
IMuonGeoUtilityTool::physVolWithTrans physVolWithTrans
Definition: MdtReadoutGeomTool.cxx:31
Amg::getRotateY3D
Amg::Transform3D getRotateY3D(double angle)
get a rotation transformation around Y-axis
Definition: GeoPrimitivesHelpers.h:261
MuonGMR4::TgcReadoutGeomTool::FactoryCache::parameterBook
ParamBookTable parameterBook
Definition: TgcReadoutGeomTool.h:50
MuonSectorMapping.h
IRDBRecord.h
Definition of the abstract IRDBRecord interface.
MuonGMR4::TgcReadoutElement::parameterBook::halfHeight
double halfHeight
Half height of the chamber (Top - botom edge)
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/TgcReadoutElement.h:29
DeMoScan.first
bool first
Definition: DeMoScan.py:534
IRDBRecord_ptr
std::unique_ptr< IRDBRecord > IRDBRecord_ptr
Definition: IRDBRecordset.h:23
python.changerun.pv
pv
Definition: changerun.py:79
MuonGMR4::TgcReadoutElement::parameterBook::sensorLayouts
std::array< StripLayerPtr, 6 > sensorLayouts
We have maximum 3 gasgaps times eta / phi measurement.
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/TgcReadoutElement.h:37
python.SystemOfUnits.s
float s
Definition: SystemOfUnits.py:147
CxxUtils::atoi
int atoi(std::string_view str)
Helper functions to unpack numbers decoded in string into integers and doubles The strings are requir...
Definition: Control/CxxUtils/Root/StringUtils.cxx:85
MuonGMR4::MuonReadoutElement::defineArgs::detElId
Identifier detElId
ATLAS identifier.
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MuonReadoutElement.h:51
Muon::MuonSectorMapping
Definition: MuonSectorMapping.h:20
ActsTrk
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
Definition: MSTrackingVolumeBuilder.cxx:24
IRDBRecordset.h
Definition of the abstract IRDBRecordset interface.
MuonGMR4::MuonReadoutElement::defineArgs::physVol
GeoIntrusivePtr< GeoVFullPhysVol > physVol
Pointer to the underlying physical volume in GeoModel.
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MuonReadoutElement.h:45
MuonGMR4::TgcReadoutElement
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/TgcReadoutElement.h:19
MuonGMR4::TgcReadoutGeomTool::FactoryCache
Definition: TgcReadoutGeomTool.h:45
MuonGMR4::defineArgs
RpcReadoutElement::defineArgs defineArgs
Definition: RpcReadoutGeomTool.cxx:32
ServiceHandle< IRDBAccessSvc >
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37
Identifier
Definition: IdentifierFieldParser.cxx:14