ATLAS Offline Software
MuonBlueprintNodeBuilder.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 
7 
8 #include "Acts/Geometry/BlueprintNode.hpp"
9 #include "Acts/Geometry/StaticBlueprintNode.hpp"
10 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
11 #include <Acts/Geometry/ContainerBlueprintNode.hpp>
12 #include "Acts/Geometry/MultiWireVolumeBuilder.hpp"
13 #include "Acts/Surfaces/TrapezoidBounds.hpp"
14 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
15 #include <Acts/Geometry/MaterialDesignatorBlueprintNode.hpp>
16 #include <Acts/Geometry/GeometryIdentifierBlueprintNode.hpp>
17 #include <Acts/Geometry/VolumeAttachmentStrategy.hpp>
18 #include "Acts/Geometry/VolumeResizeStrategy.hpp"
19 #include <Acts/Geometry/TrackingVolume.hpp>
20 #include <Acts/Geometry/TrapezoidVolumeBounds.hpp>
21 #include <Acts/Surfaces/PlaneSurface.hpp>
22 #include <Acts/Plugins/GeoModel/GeoModelMaterialConverter.hpp>
23 #include <Acts/Visualization/ObjVisualization3D.hpp>
24 
25 
28 
29 #include "GeoModelValidation/GeoMaterialHelper.h"
30 
31 namespace {
32  //Muon System IDs
33 constexpr std::size_t s_muonBarrelId = 30;
34 constexpr std::size_t s_muonEndcapAId = 31;
35 constexpr std::size_t s_muonEndcapCId = 32;
36 }
37 
38 namespace ActsTrk {
39 
42  return StatusCode::SUCCESS;
43  }
44 
45 
46 std::shared_ptr<Acts::Experimental::BlueprintNode> MuonBlueprintNodeBuilder::buildBlueprintNode(const Acts::GeometryContext& gctx, std::shared_ptr<Acts::Experimental::BlueprintNode>&& childNode) {
47 
48 const MuonChamberSet allChambers = m_detMgr->getAllChambers();
49 
50 //Divide the chambers for every blueprint node of the muon system
51 MuonChamberSet barrelStations;
52 MuonChamberSet endcapAStations;
53 MuonChamberSet endcapCStations;
54 
55 for(const MuonGMR4::Chamber* chamber: allChambers){
56 
58  barrelStations.insert(chamber);
60  endcapAStations.insert(chamber);
62  endcapCStations.insert(chamber);
63  }
64 }
65 
66  // Top level node for the Muon system
67 auto muonNode = std::make_shared<Acts::Experimental::CylinderContainerBlueprintNode>("MuonNode", Acts::AxisDirection::AxisZ);
68 
69 Acts::VolumeBoundFactory boundsFactory{};
70 
71 auto barrelNode = buildMuonNode(gctx, barrelStations, "BI_BM_BO_EE_EI",Acts::GeometryIdentifier().withVolume(s_muonBarrelId), boundsFactory);
72 auto endcapANode = buildMuonNode(gctx, endcapAStations, "EM_EO_A", Acts::GeometryIdentifier().withVolume(s_muonEndcapAId), boundsFactory);
73 auto endcapCNode = buildMuonNode(gctx, endcapCStations, "EM_EO_C", Acts::GeometryIdentifier().withVolume(s_muonEndcapCId), boundsFactory);
74 
75 // Add to the muon barrel child node (e.g calo or Itk) - if existed
76 if(childNode){
77  barrelNode->addChild(std::move(childNode));
78 }
79 
80 muonNode->addChild(std::move(barrelNode));
81 muonNode->addChild(std::move(endcapANode));
82 muonNode->addChild(std::move(endcapCNode));
83 
84 return muonNode;
85 
86 }
87 
88 std::shared_ptr<Acts::Experimental::StaticBlueprintNode>
90  const Acts::GeometryContext& gctx,
91  const MuonChamberSet& chambers,
92  const std::string& name,
93  const Acts::GeometryIdentifier& id,
94  Acts::VolumeBoundFactory& boundsFactory) const {
95 
96  const ActsGeometryContext* context = gctx.get<const ActsGeometryContext* >();
97  std::vector<std::string> stationNames;
98 
99  std::vector<std::shared_ptr<Acts::Experimental::StaticBlueprintNode>> nodes;
100 
101  double innerRadius = 0.0;
102  double outerRadius = std::numeric_limits<double>::lowest();
103  double maxZ = std::numeric_limits<double>::lowest();
104  double minZ = std::numeric_limits<double>::max();
105 
106 
107  int chamberId = 1;
108  ATH_MSG_DEBUG("Chambers= "<<chambers.size());
109  for(const MuonGMR4::Chamber* chamber: chambers){
110  const Amg::Transform3D& transform = chamber->localToGlobalTrans(*context);
111  auto vol = std::make_unique<Acts::TrackingVolume>(
112  transform,
113  chamber->bounds(),
114  chamber->identString());
115 
116  // Get material per chamber, blend it and place it in the center of the volume
117  auto material = blendChamberMaterial(*chamber);
118  vol->addSurface(std::move(material));
119  //the chamber geometry id
120  Acts::GeometryIdentifier chId = id.withLayer(chamberId++);
121  vol->assignGeometryId(chId);
122 
123  std::pair<std::vector<volumePtr>,std::vector<surfacePtr>> innerStructure = getSensitiveElements(*context, *chamber, chId, boundsFactory);
124 
125  for(auto& surface: innerStructure.second){
126  vol->addSurface(surface);
127  }
128 
129  //calculate the bounds of the cylinder container
130  for(const auto& surface: vol->boundarySurfaces()){
131  const auto& surfaceRepr = surface->surfaceRepresentation();
132  const Acts::Polyhedron& polyhedron = surfaceRepr.polyhedronRepresentation(gctx);
133  const Amg::Vector3D& center = surfaceRepr.center(gctx);
134 
135  maxZ = std::max(maxZ, center.z());
136  minZ = std::min(minZ, center.z());
137 
138  // Outer radius needs to be treated differently due to curvature of cylindrical surface
139  for(const Amg::Vector3D& vertex: polyhedron.vertices){
140  outerRadius = std::max(outerRadius, vertex.perp());
141  }
142  }
143  if(m_dumpVolumes){
144  //for visualizing each chamber volume individually
145  Acts::ObjVisualization3D helper;
146  vol->visualize(helper, gctx, {.visible = true},
147  {.visible = false}, {.visible = true});
148  helper.write(chamber->identString() + ".obj");
149  helper.clear();
150  }
151 
152  auto node = std::make_shared<Acts::Experimental::StaticBlueprintNode>(std::move(vol));
153  for(auto& readoutVol : innerStructure.first){
154  node->addStaticVolume(std::move(readoutVol));
155  }
156 
157 
158  nodes.emplace_back(std::move(node));
159  }
160 
161  double halfLengthZ = 0.5 * std::abs(maxZ - minZ);
162  ATH_MSG_DEBUG("Inner radius: " << innerRadius);
163  ATH_MSG_DEBUG("Outer radius: " << outerRadius);
164  ATH_MSG_DEBUG("Max Z: " << maxZ);
165  ATH_MSG_DEBUG("Min Z: " << minZ);
166  ATH_MSG_DEBUG("Half length Z: " << halfLengthZ);
167 
168  Amg::Transform3D trf = Amg::getTranslateZ3D(halfLengthZ + minZ);
169 
170  auto bounds = boundsFactory.makeBounds<Acts::CylinderVolumeBounds>(innerRadius, outerRadius, halfLengthZ);
171  auto volume = std::make_unique<Acts::TrackingVolume>(trf, bounds, name);
172  volume->assignGeometryId(id);
173  auto muonNode = std::make_shared<Acts::Experimental::StaticBlueprintNode>(std::move(volume));
174 
175  ATH_MSG_DEBUG("There are " << nodes.size() << " nodes");
176  std::ranges::for_each(nodes, [&muonNode](auto& node) {
177  muonNode->addChild(std::move(node));
178  });
179  return muonNode;
180  }
181 
182 
183 std::pair<std::vector<volumePtr>, std::vector<surfacePtr>>
185  const ActsGeometryContext& gctx,
186  const MuonGMR4::Chamber& chamber,
187  const Acts::GeometryIdentifier& chId,
188  Acts::VolumeBoundFactory& boundsFactory) const {
189 
190  std::vector<volumePtr> readoutVolumes;
191  std::vector<surfacePtr> readoutSurfaces;
192  Acts::GeometryIdentifier::Value mdtId{1};
193 
194  for (const MuonGMR4::MuonReadoutElement* readoutEle : chamber.readoutEles()) {
195 
196  std::vector<surfacePtr> detSurfaces = readoutEle->getSurfaces();
197  switch(readoutEle->detectorType()){
198  case DetectorType::Mdt: {
199  const auto* mdtReadoutEle = static_cast<const MuonGMR4::MdtReadoutElement*>(readoutEle);
200  const MuonGMR4::MdtReadoutElement::parameterBook& parameters{mdtReadoutEle->getParameters()};
201 
202  // get the transform to the chamber's frame
203  const Amg::Vector3D toChamber = chamber.globalToLocalTrans(gctx)*mdtReadoutEle->center(gctx);
204  const Acts::Transform3 mdtTransform = chamber.localToGlobalTrans(gctx) * Amg::getTranslate3D(toChamber);
205 
206  // create the MDT multilayer volume with the dedicated builder
207  Acts::Experimental::MultiWireVolumeBuilder::Config mwCfg;
208  mwCfg.name = m_detMgr->idHelperSvc()->toStringDetEl(mdtReadoutEle->identify());
209  mwCfg.mlSurfaces = detSurfaces;
210  mwCfg.transform = mdtTransform;
211 
212  auto mdtBounds = boundsFactory.makeBounds<Acts::TrapezoidVolumeBounds>(parameters.shortHalfX,
213  parameters.longHalfX, parameters.halfY, parameters.halfHeight);
214 
215  mwCfg.bounds = mdtBounds;
216  using BoundsV = Acts::TrapezoidVolumeBounds::BoundValues;
217  mwCfg.binning = {{{Acts::AxisDirection::AxisY, Acts::AxisBoundaryType::Bound,
218  -mdtBounds->get(BoundsV::eHalfLengthY),
219  mdtBounds->get(BoundsV::eHalfLengthY),
220  static_cast<std::size_t>(std::lround(2 * mdtBounds->get(BoundsV::eHalfLengthY) / parameters.tubePitch))}, 2u},
221  {{Acts::AxisDirection::AxisZ, Acts::AxisBoundaryType::Bound,
222  -mdtBounds->get(BoundsV::eHalfLengthZ),
223  mdtBounds->get(BoundsV::eHalfLengthZ),
224  static_cast<std::size_t>(std::lround(2 * mdtBounds->get(BoundsV::eHalfLengthZ) / parameters.tubePitch))}, 1u}};
225  Acts::Experimental::MultiWireVolumeBuilder mdtBuilder{mwCfg};
226  std::unique_ptr<Acts::TrackingVolume> mdtVolume = mdtBuilder.buildVolume(gctx.context());
227 
228  mdtVolume->assignGeometryId(chId.withExtra(mdtId++));
229  readoutVolumes.push_back(std::move(mdtVolume));
230  break;
231 
232  } case DetectorType::Rpc:
233  case DetectorType::Tgc:
234  case DetectorType::sTgc:
235  case DetectorType::Mm: {
236 
237  readoutSurfaces.insert(readoutSurfaces.end(), std::make_move_iterator(detSurfaces.begin()),
238  std::make_move_iterator(detSurfaces.end()));
239 
240  break;
241 
242  } default:
243  THROW_EXCEPTION("Unknown detector type for readout element: " << ActsTrk::to_string(readoutEle->detectorType()));
244  break;
245 
246  }
247  }
248 
249  return std::make_pair(std::move(readoutVolumes), std::move(readoutSurfaces));
250 }
251 
252 
253 
254 std::shared_ptr<Acts::Surface>
256  const MuonGMR4::Chamber& chamber) const {
257 
258  const float thickness = chamber.halfZ() * 2;
259  PVConstLink parentVolume = chamber.readoutEles().front()->getMaterialGeom()->getParent();
260  GeoModelTools::GeoMaterialHelper geoMaterialHelper;
261  std::pair<GeoModelTools::GeoMaterialPtr, double> geoMaterials = geoMaterialHelper.collectMaterial(parentVolume);
262 
263  const Acts::Material aMat = Acts::GeoModel::geoMaterialConverter(*geoMaterials.first);
264  //rotate about the z axis
265  auto constPtr = chamber.surface().getSharedPtr();
266  //to assign the material shouldnt be const
267  auto ptr = std::const_pointer_cast<Acts::Surface>(constPtr);
268  Acts::MaterialSlab slab{aMat, thickness};
269  std::shared_ptr<Acts::HomogeneousSurfaceMaterial> material = std::make_shared<Acts::HomogeneousSurfaceMaterial>(slab);
270  ptr->assignSurfaceMaterial(material);
271  return ptr;
272 
273 }
274 
275 bool MuonBlueprintNodeBuilder::isChamberInTheStation(const MuonGMR4::Chamber& chamber, const std::vector<StIdx>& stationIndex, const EndcapSide& side) const {
276  StIdx stationIdx = toStationIndex(chamber.chamberIndex());
277  bool matchesName = std::ranges::any_of(stationIndex.begin(), stationIndex.end(), [&](const auto& n){
278  return stationIdx == n;
279  });
280  const int stationEta = chamber.stationEta();
281  bool etaSignCorrect = ((stationEta > 0 && side == EndcapSide::A) || (stationEta < 0 && side == EndcapSide::C) || (side == EndcapSide::Both));
282  return matchesName && etaSignCorrect;
283 }
284 
285 
286 } //namespace ActsTrk
python.PyKernel.retrieve
def retrieve(aClass, aKey=None)
Definition: PyKernel.py:110
MuonBlueprintNodeBuilder.h
calibdata.chamber
chamber
Definition: calibdata.py:31
TRT_PAI_gasdata::EO
const float EO[NO]
Energy levels for Oxygen.
Definition: TRT_PAI_gasdata.h:301
Muon::MuonStationIndex::StIndex::EM
@ EM
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
ActsTrk::MuonBlueprintNodeBuilder::EndcapSide::Both
@ Both
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
Amg::getTranslateZ3D
Amg::Transform3D getTranslateZ3D(const double Z)
: Returns a shift transformation along the z-axis
Definition: GeoPrimitivesHelpers.h:285
ActsTrk::DetectorType::Tgc
@ Tgc
Resitive Plate Chambers.
MuonGMR4::MuonReadoutElement
The MuonReadoutElement is an abstract class representing the geometry representing the muon detector.
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MuonReadoutElement.h:38
Muon::IMuonIdHelperSvc::toStringDetEl
virtual std::string toStringDetEl(const Identifier &id) const =0
print all fields up to detector element to string
ActsTrk::MuonBlueprintNodeBuilder::m_dumpVolumes
Gaudi::Property< bool > m_dumpVolumes
Definition: MuonBlueprintNodeBuilder.h:73
dbg::ptr
void * ptr(T *p)
Definition: SGImplSvc.cxx:74
ActsTrk::DetectorType::sTgc
@ sTgc
Micromegas (NSW)
ActsTrk::MuonBlueprintNodeBuilder::m_detMgr
const MuonGMR4::MuonDetectorManager * m_detMgr
Definition: MuonBlueprintNodeBuilder.h:71
ActsTrk::MuonBlueprintNodeBuilder::EndcapSide::A
@ A
Trk::u
@ u
Enums for curvilinear frames.
Definition: ParamDefs.h:77
TRT::Hit::side
@ side
Definition: HitInfo.h:83
runBeamSpotCalibration.helper
helper
Definition: runBeamSpotCalibration.py:115
ActsGeometryContext::context
Acts::GeometryContext context() const
Definition: ActsGeometryContext.h:45
ActsTrk::MuonBlueprintNodeBuilder::EndcapSide::C
@ C
Muon::MuonStationIndex::toStationIndex
StIndex toStationIndex(ChIndex index)
convert ChIndex into StIndex
MuonGMR4::Chamber
Definition: Chamber.h:23
ActsTrk::MuonBlueprintNodeBuilder::blendChamberMaterial
std::shared_ptr< Acts::Surface > blendChamberMaterial(const MuonGMR4::Chamber &chamber) const
Blend the chamber's material as plane surface.
Definition: MuonBlueprintNodeBuilder.cxx:255
ActsTrk::DetectorType::Mm
@ Mm
Maybe not needed in the migration.
MuonGMR4::MdtReadoutElement::parameterBook
Set of parameters to describe a MDT chamber.
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MdtReadoutElement.h:22
beamspotman.n
n
Definition: beamspotman.py:729
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
Amg::transform
Amg::Vector3D transform(Amg::Vector3D &v, Amg::Transform3D &tr)
Transform a point from a Trasformation3D.
Definition: GeoPrimitivesHelpers.h:156
ActsTrk::MuonBlueprintNodeBuilder::initialize
StatusCode initialize() override
Definition: MuonBlueprintNodeBuilder.cxx:40
ActsTrk::MuonBlueprintNodeBuilder::isChamberInTheStation
bool isChamberInTheStation(const MuonGMR4::Chamber &chamber, const std::vector< StIdx > &stationNames, const EndcapSide &side) const
Check if the chamber is in this node.
Definition: MuonBlueprintNodeBuilder.cxx:275
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
ActsGeometryContext
Include the GeoPrimitives which need to be put first.
Definition: ActsGeometryContext.h:27
Muon::MuonStationIndex::StIndex::BO
@ BO
Muon::MuonStationIndex::StIndex
StIndex
enum to classify the different station layers in the muon spectrometer
Definition: MuonStationIndex.h:23
python.PyKernel.detStore
detStore
Definition: PyKernel.py:41
ActsTrk::DetectorType::Mdt
@ Mdt
MuonSpectrometer.
MuonGMR4::MdtReadoutElement
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MdtReadoutElement.h:18
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
ActsTrk::to_string
std::string to_string(const DetectorType &type)
Definition: GeometryDefs.h:34
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
THROW_EXCEPTION
#define THROW_EXCEPTION(MESSAGE)
Definition: throwExcept.h:10
ActsTrk::MuonBlueprintNodeBuilder::getSensitiveElements
std::pair< std::vector< volumePtr >, std::vector< surfacePtr > > getSensitiveElements(const ActsGeometryContext &gctx, const MuonGMR4::Chamber &chamber, const Acts::GeometryIdentifier &chId, Acts::VolumeBoundFactory &boundsFactory) const
Get the chamber's sensitive elements.
Definition: MuonBlueprintNodeBuilder.cxx:184
Chamber.h
ActsTrk::MuonBlueprintNodeBuilder::EndcapSide
EndcapSide
Definition: MuonBlueprintNodeBuilder.h:53
Trk::vertex
@ vertex
Definition: MeasurementType.h:21
MuonGMR4::MuonDetectorManager::idHelperSvc
const Muon::IMuonIdHelperSvc * idHelperSvc() const
Returns a pointer to the central MuonIdHelperSvc.
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MuonDetectorManager.cxx:159
ActsTrk::DetectorType::Rpc
@ Rpc
Monitored Drift Tubes.
ActsTrk::MuonChamberSet
MuonGMR4::MuonDetectorManager::MuonChamberSet MuonChamberSet
Definition: MuonBlueprintNodeBuilder.h:42
physics_parameters.parameters
parameters
Definition: physics_parameters.py:144
ActsTrk
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
Definition: MSTrackingVolumeBuilder.cxx:24
MuonStationIndex.h
CaloLCW_tf.trf
trf
Definition: CaloLCW_tf.py:20
Muon::MuonStationIndex::StIndex::BI
@ BI
ActsTrk::MuonBlueprintNodeBuilder::buildMuonNode
std::shared_ptr< Acts::Experimental::StaticBlueprintNode > buildMuonNode(const Acts::GeometryContext &gctx, const MuonChamberSet &chambers, const std::string &name, const Acts::GeometryIdentifier &id, Acts::VolumeBoundFactory &boundsFactory) const
Build subnodes for the muon system node.
Definition: MuonBlueprintNodeBuilder.cxx:89
Muon::MuonStationIndex::StIndex::BM
@ BM
MuonGMR4::MuonDetectorManager::getAllChambers
MuonChamberSet getAllChambers() const
Definition: MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MuonDetectorManager.cxx:215
Material
@ Material
Definition: MaterialTypes.h:8
Muon::MuonStationIndex::StIndex::EI
@ EI
node
Definition: node.h:21
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
ActsTrk::MuonBlueprintNodeBuilder::buildBlueprintNode
std::shared_ptr< Acts::Experimental::BlueprintNode > buildBlueprintNode(const Acts::GeometryContext &gctx, std::shared_ptr< Acts::Experimental::BlueprintNode > &&childNode) override
Build the Muon Blueprint Node.
Definition: MuonBlueprintNodeBuilder.cxx:46