ATLAS Offline Software
Loading...
Searching...
No Matches
ActsTrk::MuonBlueprintNodeBuilder Class Reference

Helper class to build a Blueprint node of the muon system. More...

#include <MuonBlueprintNodeBuilder.h>

Inheritance diagram for ActsTrk::MuonBlueprintNodeBuilder:
Collaboration diagram for ActsTrk::MuonBlueprintNodeBuilder:

Public Types

enum class  EndcapSide { A , C , Both }

Public Member Functions

StatusCode initialize () override
std::shared_ptr< Acts::Experimental::BlueprintNode > buildBlueprintNode (const Acts::GeometryContext &gctx, std::shared_ptr< Acts::Experimental::BlueprintNode > &&childNode) override
 Build the Muon Blueprint Node.

Private Member Functions

template<typename T>
std::shared_ptr< Acts::Surface > blendMaterial (const T &element) const
 Blend the sector's/chamber's material as plane surface.
template<typename T>
std::pair< std::vector< staticNodePtr >, std::vector< surfacePtr > > getSensitiveElements (const ActsTrk::GeometryContext &gctx, const T &element, const Acts::GeometryIdentifier &chId, Acts::VolumeBoundFactory &boundsFactory) const
 Get the chamber's sensitive elements.
template<typename T>
bool isElementInTheStation (const T &element, const std::vector< StIdx > &stationNames, const EndcapSide &side) const
 Check if the chamber is in this node.
template<typename MuonElementsSet>
std::shared_ptr< Acts::Experimental::StaticBlueprintNode > buildMuonNode (const Acts::GeometryContext &gctx, const MuonElementsSet &elements, const std::string &name, const Acts::GeometryIdentifier &id, Acts::VolumeBoundFactory &boundsFactory) const
 Build subnodes for the muon system node.

Private Attributes

const MuonGMR4::MuonDetectorManagerm_detMgr {nullptr}
Gaudi::Property< bool > m_dumpVolumes {this, "dumpVolumes", false}
Gaudi::Property< bool > m_useSectors {this, "UseSectors", false}

Detailed Description

Helper class to build a Blueprint node of the muon system.

It builds the whole muon system for PhaseII adding it to the Blueprint as a node.

Definition at line 49 of file MuonBlueprintNodeBuilder.h.

Member Enumeration Documentation

◆ EndcapSide

Enumerator
Both 

Definition at line 54 of file MuonBlueprintNodeBuilder.h.

54 {
55 A,
56 C,
57 Both
58 };
struct color C

Member Function Documentation

◆ blendMaterial()

template<typename T>
std::shared_ptr< Acts::Surface > ActsTrk::MuonBlueprintNodeBuilder::blendMaterial ( const T & element) const
private

Blend the sector's/chamber's material as plane surface.

Parameters
elementThe element for which to blend the material for This function returns a plane surface with the element's (chamber or sector) material assigned to be placed at the center of the element.

Definition at line 327 of file MuonBlueprintNodeBuilder.cxx.

328 {
329
330 const float thickness = element.halfZ() * 2;
331 PVConstLink parentVolume = element.readoutEles().front()->getMaterialGeom()->getParent();
332 GeoModelTools::GeoMaterialHelper geoMaterialHelper;
333 std::pair<GeoModelTools::GeoMaterialPtr, double> geoMaterials = geoMaterialHelper.collectMaterial(parentVolume);
334
335 const Acts::Material aMat = ActsPlugins::GeoModel::geoMaterialConverter(*geoMaterials.first);
336 //rotate about the z axis
337 auto constPtr = element.surface().getSharedPtr();
338 //to assign the material shouldnt be const
339 auto ptr = std::const_pointer_cast<Acts::Surface>(constPtr);
340
341 Acts::MaterialSlab slab{aMat, thickness};
342 std::shared_ptr<Acts::HomogeneousSurfaceMaterial> material = std::make_shared<Acts::HomogeneousSurfaceMaterial>(slab);
343 ptr->assignSurfaceMaterial(material);
344 return ptr;
345
346}
void * ptr(T *p)
Definition SGImplSvc.cxx:74

◆ buildBlueprintNode()

std::shared_ptr< Acts::Experimental::BlueprintNode > ActsTrk::MuonBlueprintNodeBuilder::buildBlueprintNode ( const Acts::GeometryContext & gctx,
std::shared_ptr< Acts::Experimental::BlueprintNode > && childNode )
override

Build the Muon Blueprint Node.

Parameters
gctxGeometry context
childNodeThe blueprint node as child of this node (for Muon System it should be Calo or Itk).

Definition at line 51 of file MuonBlueprintNodeBuilder.cxx.

51 {
52
53std::variant<MuonChamberSet, MuonSectorSet> elements;
54std::variant<MuonChamberSet, MuonSectorSet> barrelStations, endcapAStations, endcapCStations, endcapMiddleAStations, endcapMiddleCStations;
55
56if (m_useSectors) {
57 elements = m_detMgr->getAllSectors();
58} else {
59 elements = m_detMgr->getAllChambers();
60}
61
62std::visit([&](auto& elems) {
63 using SetType = std::decay_t<decltype(elems)>;
64
65 // Initialize station containers of the same type
66 SetType barrel, endcapA, endcapC, endcapMiddleA, endcapMiddleC;
67
68 for (const auto& element : elems) {
69 if (isElementInTheStation(*element,
70 {StIdx::BI, StIdx::BM, StIdx::BO, StIdx::BE, StIdx::EE, StIdx::EI},
72 barrel.push_back(element);
73 } else if (isElementInTheStation(*element, {StIdx::EO}, EndcapSide::A)) {
74 endcapA.push_back(element);
75 } else if (isElementInTheStation(*element, {StIdx::EO}, EndcapSide::C)) {
76 endcapC.push_back(element);
77 } else if (isElementInTheStation(*element, {StIdx::EM}, EndcapSide::A)) {
78 endcapMiddleA.push_back(element);
79 } else if (isElementInTheStation(*element, {StIdx::EM}, EndcapSide::C)) {
80 endcapMiddleC.push_back(element);
81 } else {
82 ATH_MSG_WARNING("Element " << element->identString()
83 << " not assigned to any station!");
84 }
85 }
86
87 // Assign back into the outer variants
88 barrelStations = std::move(barrel);
89 endcapAStations = std::move(endcapA);
90 endcapCStations = std::move(endcapC);
91 endcapMiddleAStations= std::move(endcapMiddleA);
92 endcapMiddleCStations= std::move(endcapMiddleC);
93
94}, elements);
95
96 // Top level node for the Muon system
97auto muonNode = std::make_shared<Acts::Experimental::CylinderContainerBlueprintNode>("MuonNode", Acts::AxisDirection::AxisZ);
98
99Acts::VolumeBoundFactory boundsFactory{};
100
101auto barrelNode = buildMuonNode(gctx, barrelStations, "BI_BM_BO_EE_EI",Acts::GeometryIdentifier().withVolume(s_muonBarrelId), boundsFactory);
102auto endcapANode = buildMuonNode(gctx, endcapAStations, "EO_A", Acts::GeometryIdentifier().withVolume(s_muonEndcapAId), boundsFactory);
103auto endcapCNode = buildMuonNode(gctx, endcapCStations, "EO_C", Acts::GeometryIdentifier().withVolume(s_muonEndcapCId), boundsFactory);
104auto endcapMiddleANode = buildMuonNode(gctx, endcapMiddleAStations, "EM_A", Acts::GeometryIdentifier().withVolume(s_muonEndcapMiddleAId), boundsFactory);
105auto endcapMiddleCNode = buildMuonNode(gctx, endcapMiddleCStations, "EM_C", Acts::GeometryIdentifier().withVolume(s_muonEndcapMiddleCId), boundsFactory);
106
107//Add to the muon barrel child node (e.g calo or Itk) - if existed
108if(childNode){
109 barrelNode->addChild(std::move(childNode));
110}
111
112muonNode->addChild(std::move(barrelNode));
113muonNode->addChild(std::move(endcapANode));
114muonNode->addChild(std::move(endcapCNode));
115muonNode->addChild(std::move(endcapMiddleANode));
116muonNode->addChild(std::move(endcapMiddleCNode));
117
118return muonNode;
119
120}
#define ATH_MSG_WARNING(x)
bool isElementInTheStation(const T &element, const std::vector< StIdx > &stationNames, const EndcapSide &side) const
Check if the chamber is in this node.
std::shared_ptr< Acts::Experimental::StaticBlueprintNode > buildMuonNode(const Acts::GeometryContext &gctx, const MuonElementsSet &elements, const std::string &name, const Acts::GeometryIdentifier &id, Acts::VolumeBoundFactory &boundsFactory) const
Build subnodes for the muon system node.
const MuonGMR4::MuonDetectorManager * m_detMgr

◆ buildMuonNode()

template<typename MuonElementsSet>
std::shared_ptr< Acts::Experimental::StaticBlueprintNode > ActsTrk::MuonBlueprintNodeBuilder::buildMuonNode ( const Acts::GeometryContext & gctx,
const MuonElementsSet & elements,
const std::string & name,
const Acts::GeometryIdentifier & id,
Acts::VolumeBoundFactory & boundsFactory ) const
private

Build subnodes for the muon system node.

Parameters
gctxThe geometry context
elementsThe name of the stations to include
sideThe side (A, C or Both)
idThe geometry identifier of this node
boundsFactoryThe factory for volume bounds

Definition at line 124 of file MuonBlueprintNodeBuilder.cxx.

129 {
130
131 const ActsTrk::GeometryContext* context = gctx.get<const ActsTrk::GeometryContext* >();
132 std::vector<std::string> stationNames;
133
134 std::vector<std::shared_ptr<Acts::Experimental::StaticBlueprintNode>> nodes;
135
136 double innerRadius = 0.0;
137 double outerRadius = std::numeric_limits<double>::lowest();
138 double maxZ = std::numeric_limits<double>::lowest();
139 double minZ = std::numeric_limits<double>::max();
140
141 int chamberId = 1;
142
143 std::visit([&](const auto& elems){
144
145 for(const auto& element : elems){
146 const Amg::Transform3D& transform = element->localToGlobalTrans(*context);
147 std::string volName = element->identString();
148
149 auto vol = std::make_unique<Acts::TrackingVolume>(
150 transform,
151 element->bounds(),
152 volName);
153
154 // Get material per chamber, blend it and place it in the center of the volume
155 auto material = blendMaterial(*element);
156 vol->addSurface(std::move(material));
157 // //the chamber geometry id
158 Acts::GeometryIdentifier chId = id.withLayer(chamberId++);
159 vol->assignGeometryId(chId);
160
161 std::pair<std::vector<staticNodePtr>,std::vector<surfacePtr>> innerStructure = getSensitiveElements(*context, *element, chId, boundsFactory);
162
163 for(auto& surface: innerStructure.second){
164 vol->addSurface(surface);
165 }
166
167 //calculate the bounds of the cylinder container
168 for(const auto& surface: vol->boundarySurfaces()){
169 const auto& surfaceRepr = surface->surfaceRepresentation();
170 const Acts::Polyhedron& polyhedron = surfaceRepr.polyhedronRepresentation(gctx);
171 const Amg::Vector3D& center = surfaceRepr.center(gctx);
172
173 maxZ = std::max(maxZ, center.z());
174 minZ = std::min(minZ, center.z());
175
176 // Outer radius needs to be treated differently due to curvature of cylindrical surface
177 for(const Amg::Vector3D& vertex: polyhedron.vertices){
178 outerRadius = std::max(outerRadius, vertex.perp());
179 }
180 }
181 if(m_dumpVolumes){
182 //for visualizing each chamber volume individually
183 Acts::ObjVisualization3D helper;
184 vol->visualize(helper, gctx, {.visible = true},
185 {.visible = true}, {.visible = true});
186 helper.write(volName + ".obj");
187 helper.clear();
188 }
189
190 std::shared_ptr<Acts::Experimental::StaticBlueprintNode> node;
191
192 const bool isSingleMdt =
193 (element->readoutEles().size() == 1 &&
194 element->readoutEles().front()->detectorType() == DetectorType::Mdt);
195
196 if (isSingleMdt) {
197 // Take ownership of the single existing node
198 node = std::move(innerStructure.first.front());
199 innerStructure.first.clear();
200 } else {
201 node = std::make_shared<Acts::Experimental::StaticBlueprintNode>(std::move(vol));
202
203 for (auto& childNode : innerStructure.first) {
204 node->addChild(std::move(childNode));
205 }
206 innerStructure.first.clear();
207 }
208
209 if (!node) {
210 THROW_EXCEPTION("No blueprint node constructed");
211 }
212
213 nodes.emplace_back(std::move(node));
214
215 }
216
217 }, elements);
218
219 double halfLengthZ = 0.5 * std::abs(maxZ - minZ);
220 ATH_MSG_DEBUG("Inner radius: " << innerRadius);
221 ATH_MSG_DEBUG("Outer radius: " << outerRadius);
222 ATH_MSG_DEBUG("Max Z: " << maxZ);
223 ATH_MSG_DEBUG("Min Z: " << minZ);
224 ATH_MSG_DEBUG("Half length Z: " << halfLengthZ);
225
226 Amg::Transform3D trf = Amg::getTranslateZ3D(halfLengthZ + minZ);
227
228 auto bounds = boundsFactory.makeBounds<Acts::CylinderVolumeBounds>(innerRadius, outerRadius, halfLengthZ);
229 auto volume = std::make_unique<Acts::TrackingVolume>(trf, bounds, name);
230 volume->assignGeometryId(id);
231 auto muonNode = std::make_shared<Acts::Experimental::StaticBlueprintNode>(std::move(volume));
232
233 ATH_MSG_DEBUG("There are " << nodes.size() << " nodes");
234 std::ranges::for_each(nodes, [&muonNode](auto& node) {
235 muonNode->addChild(std::move(node));
236 });
237 return muonNode;
238 }
#define ATH_MSG_DEBUG(x)
std::shared_ptr< Acts::Surface > blendMaterial(const T &element) const
Blend the sector's/chamber's material as plane surface.
std::pair< std::vector< staticNodePtr >, std::vector< surfacePtr > > getSensitiveElements(const ActsTrk::GeometryContext &gctx, const T &element, const Acts::GeometryIdentifier &chId, Acts::VolumeBoundFactory &boundsFactory) const
Get the chamber's sensitive elements.
@ Mdt
MuonSpectrometer.
Amg::Transform3D getTranslateZ3D(const double Z)
: Returns a shift transformation along the z-axis
Eigen::Affine3d Transform3D
Amg::Vector3D transform(Amg::Vector3D &v, Amg::Transform3D &tr)
Transform a point from a Trasformation3D.
Eigen::Matrix< double, 3, 1 > Vector3D
#define THROW_EXCEPTION(MESSAGE)
Definition throwExcept.h:10

◆ getSensitiveElements()

template<typename T>
std::pair< std::vector< staticNodePtr >, std::vector< surfacePtr > > ActsTrk::MuonBlueprintNodeBuilder::getSensitiveElements ( const ActsTrk::GeometryContext & gctx,
const T & element,
const Acts::GeometryIdentifier & chId,
Acts::VolumeBoundFactory & boundsFactory ) const
private

Get the chamber's sensitive elements.

Parameters
gctxThe geometry context
elementThe element for which to get the sensitive elements (chamber or sector)
chIdThe geometry identifier of the chamber
boundsFactoryThe factory for volume bounds This function constructs and returns the sensitive elements (volumes and surfaces) of the sector.

Definition at line 242 of file MuonBlueprintNodeBuilder.cxx.

246 {
247
248 std::vector<staticNodePtr> readoutVolumes;
249 std::vector<surfacePtr> readoutSurfaces;
250 Acts::GeometryIdentifier::Value mdtId{1};
251
252 for (const MuonGMR4::MuonReadoutElement* readoutEle : element.readoutEles()) {
253
254 std::vector<surfacePtr> detSurfaces = readoutEle->getSurfaces();
255 switch(readoutEle->detectorType()){
256 case DetectorType::Mdt: {
257 const auto* mdtReadoutEle = static_cast<const MuonGMR4::MdtReadoutElement*>(readoutEle);
258 const MuonGMR4::MdtReadoutElement::parameterBook& parameters{mdtReadoutEle->getParameters()};
259
260 // get the transform to the sector's frame
261 const Amg::Vector3D toChamber = element.globalToLocalTrans(gctx)*mdtReadoutEle->center(gctx);
262 const Acts::Transform3 mdtTransform = element.localToGlobalTrans(gctx) * Amg::getTranslate3D(toChamber);
263
264 // create the MDT multilayer volume with the dedicated builder
265 Acts::Experimental::MultiWireVolumeBuilder::Config mwCfg;
266 mwCfg.name = m_detMgr->idHelperSvc()->toStringDetEl(mdtReadoutEle->identify());
267 mwCfg.mlSurfaces = detSurfaces;
268 mwCfg.transform = mdtTransform;
269
270 //check for rectangular or trapezoidal shape bounds
271 std::shared_ptr<Acts::VolumeBounds> mdtBounds{nullptr};
272
273 if(std::abs(parameters.shortHalfX - parameters.longHalfX) < Acts::s_epsilon){
274
275 mdtBounds = boundsFactory.makeBounds<Acts::CuboidVolumeBounds>(parameters.shortHalfX, parameters.halfY, parameters.halfHeight);
276
277 } else {
278
279 mdtBounds = boundsFactory.makeBounds<Acts::TrapezoidVolumeBounds>(parameters.shortHalfX,
280 parameters.longHalfX, parameters.halfY, parameters.halfHeight);
281 }
282
283 mwCfg.bounds = mdtBounds;
284 using BoundsV = Acts::TrapezoidVolumeBounds::BoundValues;
285 mwCfg.binning = {{{Acts::AxisDirection::AxisY, Acts::AxisBoundaryType::Bound,
286 -parameters.halfY,
287 parameters.halfY,
288 static_cast<std::size_t>(std::lround(2 * parameters.halfY / parameters.tubePitch))}, 2u},
289 {{Acts::AxisDirection::AxisZ, Acts::AxisBoundaryType::Bound,
290 -parameters.halfHeight,
291 parameters.halfHeight,
292 static_cast<std::size_t>(std::lround(2 * parameters.halfHeight / parameters.tubePitch))}, 1u}};
293 Acts::Experimental::MultiWireVolumeBuilder mdtBuilder{mwCfg};
294 std::unique_ptr<Acts::TrackingVolume> mdtVolume = mdtBuilder.buildVolume();
295
296 mdtVolume->assignGeometryId(chId.withExtra(mdtId++));
297 //create the blueprint node for the mdt multilayers
298 std::shared_ptr<Acts::Experimental::StaticBlueprintNode> mdtNode = std::make_shared<Acts::Experimental::StaticBlueprintNode>(std::move(mdtVolume));
299 mdtNode->setNavigationPolicyFactory(mdtBuilder.createNavigationPolicyFactory());
300 readoutVolumes.push_back(std::move(mdtNode));
301
302 break;
303
304 } case DetectorType::Rpc:
307 case DetectorType::Mm: {
308
309 readoutSurfaces.insert(readoutSurfaces.end(), std::make_move_iterator(detSurfaces.begin()),
310 std::make_move_iterator(detSurfaces.end()));
311
312 break;
313
314 } default:
315 THROW_EXCEPTION("Unknown detector type for readout element: " << ActsTrk::to_string(readoutEle->detectorType()));
316 break;
317
318 }
319 }
320
321 return std::make_pair(std::move(readoutVolumes), std::move(readoutSurfaces));
322}
std::string to_string(const DetectorType &type)
@ Mm
Maybe not needed in the migration.
@ Tgc
Resitive Plate Chambers.
@ sTgc
Micromegas (NSW)
@ Rpc
Monitored Drift Tubes.
Amg::Transform3D getTranslate3D(const double X, const double Y, const double Z)
: Returns a shift transformation along an arbitrary axis

◆ initialize()

StatusCode ActsTrk::MuonBlueprintNodeBuilder::initialize ( )
override

Definition at line 45 of file MuonBlueprintNodeBuilder.cxx.

45 {
47 return StatusCode::SUCCESS;
48 }
#define ATH_CHECK
Evaluate an expression and check for errors.
retrieve(aClass, aKey=None)
Definition PyKernel.py:110

◆ isElementInTheStation()

template<typename T>
bool ActsTrk::MuonBlueprintNodeBuilder::isElementInTheStation ( const T & element,
const std::vector< StIdx > & stationNames,
const EndcapSide & side ) const
private

Check if the chamber is in this node.

Parameters
elementThe element to check (chamber or sector)
stationNamesThe names of the stations to check against
sideThe side of the endcap (A, C or Both) This function checks if the chamber is part of the configured chambers in this node. It is used to filter out chambers that are not part of this muon node.

Definition at line 349 of file MuonBlueprintNodeBuilder.cxx.

349 {
350 StIdx stationIdx = toStationIndex(element.chamberIndex());
351 auto stationSide = element.side();
352 bool matchesName = std::ranges::any_of(stationIndex.begin(), stationIndex.end(), [&](const auto& n){
353 return stationIdx == n;
354 });
355
356 bool etaSignCorrect = ((stationSide > 0 && side == EndcapSide::A) || (stationSide < 0 && side == EndcapSide::C) || (side == EndcapSide::Both));
357 return matchesName && etaSignCorrect;
358}
Muon::MuonStationIndex::StIndex StIdx
StIndex toStationIndex(ChIndex index)
convert ChIndex into StIndex

Member Data Documentation

◆ m_detMgr

const MuonGMR4::MuonDetectorManager* ActsTrk::MuonBlueprintNodeBuilder::m_detMgr {nullptr}
private

Definition at line 72 of file MuonBlueprintNodeBuilder.h.

72{nullptr};

◆ m_dumpVolumes

Gaudi::Property<bool> ActsTrk::MuonBlueprintNodeBuilder::m_dumpVolumes {this, "dumpVolumes", false}
private

Definition at line 74 of file MuonBlueprintNodeBuilder.h.

74{this, "dumpVolumes", false}; // Flag to control if we want to visualize each chamber volume individually

◆ m_useSectors

Gaudi::Property<bool> ActsTrk::MuonBlueprintNodeBuilder::m_useSectors {this, "UseSectors", false}
private

Definition at line 76 of file MuonBlueprintNodeBuilder.h.

76{this, "UseSectors", false}; // Flag to control if we want to build the muon node from sectors or chambers

The documentation for this class was generated from the following files: