ATLAS Offline Software
Loading...
Searching...
No Matches
CaloBlueprintNodeBuilder.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
8
9#include "Acts/Geometry/Blueprint.hpp"
10#include "Acts/Geometry/PortalShell.hpp"
11#include "Acts/Geometry/Volume.hpp"
12#include "Acts/Geometry/StaticBlueprintNode.hpp"
13#include "Acts/Geometry/GeometryIdentifierBlueprintNode.hpp"
14#include <Acts/Navigation/SurfaceArrayNavigationPolicy.hpp>
15#include <Acts/Navigation/TryAllNavigationPolicy.hpp>
16#include <Acts/Utilities/AxisDefinitions.hpp>
17#include <Acts/Geometry/ContainerBlueprintNode.hpp>
18#include <Acts/Geometry/Extent.hpp>
19#include <Acts/Definitions/Units.hpp>
20#include <Acts/Geometry/LayerBlueprintNode.hpp>
21#include <Acts/Geometry/VolumeResizeStrategy.hpp>
22#include <Acts/Geometry/VolumeAttachmentStrategy.hpp>
23#include <Acts/Geometry/TrackingVolume.hpp>
24#include <Acts/Geometry/CylinderVolumeBounds.hpp>
25#include <Acts/Utilities/Helpers.hpp>
26
28
29#include <Acts/Surfaces/SurfaceArray.hpp>
31
32using namespace Acts;
33using namespace Acts::UnitLiterals;
34using AttachmentStrategy = Acts::VolumeAttachmentStrategy;
35using ResizeStrategy = Acts::VolumeResizeStrategy;
36
37using namespace ActsTrk::detail::GeoVolIds;
38
40 ATH_MSG_DEBUG("Initializing CaloBlueprintNodeBuilder");
41
43
44 return StatusCode::SUCCESS;
45}
46
47std::shared_ptr<BlueprintNode> ActsTrk::CaloBlueprintNodeBuilder::buildBlueprintNode(const GeometryContext& /*gctx*/,
48 std::shared_ptr<BlueprintNode>&& childNode) {
49
50
51 std::map<caloRegion, caloSampleSurfaceMap_t> caloRegionSampleSurfaceMap;
52 std::map<caloRegion, caloSampleDDEElementsMap_t> caloRegionSampleDDEElementsMap;
53 std::map<std::string, double> caloDimensions;
54
55 fillMaps(caloRegionSampleDDEElementsMap, caloDimensions);
56
57 ATH_MSG_DEBUG("Have filled first two maps");
58
59 generateCylinderSurfaces(caloRegionSampleSurfaceMap[caloRegion::CylinderSymmetricZZero], caloRegionSampleDDEElementsMap[caloRegion::CylinderSymmetricZZero],false);
60 generateCylinderSurfaces(caloRegionSampleSurfaceMap[caloRegion::CylinderNegativeZ], caloRegionSampleDDEElementsMap[caloRegion::CylinderNegativeZ],true);
61 generateCylinderSurfaces(caloRegionSampleSurfaceMap[caloRegion::CylinderPositiveZ], caloRegionSampleDDEElementsMap[caloRegion::CylinderPositiveZ],true);
62 generateDiscSurfaces(caloRegionSampleSurfaceMap[caloRegion::DiscNegativeZ], caloRegionSampleDDEElementsMap[caloRegion::DiscNegativeZ]);
63 generateDiscSurfaces(caloRegionSampleSurfaceMap[caloRegion::DiscPositiveZ], caloRegionSampleDDEElementsMap[caloRegion::DiscPositiveZ]);
64
65 ATH_MSG_DEBUG("Have generated calorimeter cylindrical surfaces");
66
67 // The calo node is a container node that will hold the itk and calo nodes as children.
68 // The calo cylinder is static in order to avoid merging issues with the itk portals
69 // that are supposed to carry material.
70 // The envelope of the calo node is set to the maximum radius and half length in z of the calorimeter,
71 // which is via a loop over all CaloDetDescrElements in the CaloDetDescrManager in the fillMaps function.
72
73 double caloEvelopeMaxR = caloDimensions.at("maxR") + 5._mm;
74 double caloEnvelopeHalfLenghtZ = (caloDimensions.at("maxPosZ") - caloDimensions.at("minNegZ"))/2.0 + 5._mm;
75
76 ATH_MSG_INFO("Calo envelope dimensions: maxR = " << caloEvelopeMaxR << ", halfLengthZ = " << caloEnvelopeHalfLenghtZ);
77 std::shared_ptr<StaticBlueprintNode> itkCaloNode{};
78 {
79 auto envelope = std::make_unique<TrackingVolume>(Amg::Transform3D::Identity(),
80 std::make_shared<CylinderVolumeBounds>(0., caloEvelopeMaxR, caloEnvelopeHalfLenghtZ),"ITkCalo");
81 envelope->assignGeometryId(Acts::GeometryIdentifier{}.withVolume(s_caloEnvelopeID));
82 itkCaloNode = std::make_shared<StaticBlueprintNode>(std::move(envelope));
83 }
84 if (childNode) {
85 itkCaloNode->addChild(std::move(childNode));
86 }
87
88 ATH_MSG_DEBUG("Top level calorimeter node created");
89
90 auto caloNode = std::make_shared<CylinderContainerBlueprintNode>("CaloNode", AxisDirection::AxisZ);
91 CylinderContainerBlueprintNode& caloBarrelCylinderNode = caloNode->addCylinderContainer("CaloBarrelSymmetricZZeroCylinders", AxisDirection::AxisR);
92 caloBarrelCylinderNode.setAttachmentStrategy(VolumeAttachmentStrategy::Gap);
93 caloBarrelCylinderNode.setResizeStrategy(ResizeStrategy::Gap);
94
95 ATH_MSG_DEBUG("EM Barrel container node created");
96
97 unsigned int volumeCounter = 0;
98
99 //Barrel cylinders symmetric about z = 0
100 for (unsigned int sampleIndex = 0; sampleIndex < m_caloCylinderSymmetricSampleList.size(); ++sampleIndex) {
101 auto& sampleName = m_caloCylinderSymmetricSampleList.at(sampleIndex).first;
102 addCylindricalTrackingVolumeToCaloNode(caloBarrelCylinderNode, sampleName, caloRegionSampleSurfaceMap[caloRegion::CylinderSymmetricZZero].at({sampleName, getSampleEnum(sampleName)}), volumeCounter, false);
103 volumeCounter++;
104 }
105
106 //now do asymmetric cylinders
107 for (unsigned int sampleIndex = 0; sampleIndex < m_caloCylinderAsymmetricSampleList.size(); ++sampleIndex) {
108 auto& sampleName = m_caloCylinderAsymmetricSampleList.at(sampleIndex).first;
109 //The tile extended barrel and gap must be added to top level node directly because they always overlap in R
110 //or Z with other calorimeter surfaces, volumes etc.
111 //Note there is a speed penalty to do it this way.
112 itkCaloNode->addLayer(sampleName+"NegZ_Layer", [&](auto& layer) {
113 layer.setSurfaces(caloRegionSampleSurfaceMap[caloRegion::CylinderNegativeZ].at({sampleName, getSampleEnum(sampleName)}));
114 layer.setEnvelope(Acts::ExtentEnvelope{{
115 .z = {0.1_mm, 0.1_mm},
116 .r = {2_mm, 2_mm},
117 }});
118 });
119 itkCaloNode->addLayer(sampleName+"PosZ_Layer", [&](auto& layer) {
120 layer.setSurfaces(caloRegionSampleSurfaceMap[caloRegion::CylinderPositiveZ].at({sampleName, getSampleEnum(sampleName)}));
121 layer.setEnvelope(Acts::ExtentEnvelope{{
122 .z = {0.1_mm, 0.1_mm},
123 .r = {2_mm, 2_mm},
124 }});
125 });
126 }
127
128 auto caloEndCapNegativeNode = std::make_shared<CylinderContainerBlueprintNode>("CaloNode", AxisDirection::AxisZ);
129
130 CylinderContainerBlueprintNode& caloEndCapDiscNegativeZNode = caloEndCapNegativeNode->addCylinderContainer("CaloEndCapDiscNegativeZ", AxisDirection::AxisZ);
131 caloEndCapDiscNegativeZNode.setAttachmentStrategy(VolumeAttachmentStrategy::Gap);
132 // The -z end of this container defines the calorimeter's global minZ, so the
133 // enclosing envelope's -z edge coincides with this container's own -z edge to
134 // within floating-point rounding. With ResizeStrategy::Gap on that side, the
135 // resize mints a degenerate (~1e-13 mm) end-gap volume whose two disc faces
136 // coincide, which CylinderNavigationPolicy cannot resolve. Expand the
137 // outermost wheel on the boundary (-z) side instead; keep Gap on the interior
138 // (+z) side. NOTE: (inner, outer) map to (minZ, maxZ) for an AxisZ stack.
139 caloEndCapDiscNegativeZNode.setResizeStrategies(ResizeStrategy::Expand, ResizeStrategy::Gap);
140
141 auto caloEndCapPositiveNode = std::make_shared<CylinderContainerBlueprintNode>("CaloNode", AxisDirection::AxisZ);
142 CylinderContainerBlueprintNode& caloEndCapDiscPositiveZNode = caloEndCapPositiveNode->addCylinderContainer("CaloEndCapDiscPositiveZ", AxisDirection::AxisZ);
143 caloEndCapDiscPositiveZNode.setAttachmentStrategy(VolumeAttachmentStrategy::Gap);
144 // Mirror of the negative endcap: the +z (maxZ, outer) end is the global maxZ
145 // boundary, so Expand there and keep Gap on the interior (-z) side.
146 caloEndCapDiscPositiveZNode.setResizeStrategies(ResizeStrategy::Gap, ResizeStrategy::Expand);
147
148 for (unsigned int sampleIndex = 0; sampleIndex < m_caloDiscSampleList.size(); ++sampleIndex) {
149 auto& sampleName = m_caloDiscSampleList.at(sampleIndex).first;
150 addCylindricalTrackingVolumeToCaloNode(caloEndCapDiscNegativeZNode, sampleName+"NegZ", caloRegionSampleSurfaceMap[caloRegion::DiscNegativeZ].at({sampleName, getSampleEnum(sampleName)}), volumeCounter, true);
151 volumeCounter++;
152 addCylindricalTrackingVolumeToCaloNode(caloEndCapDiscPositiveZNode, sampleName+"PosZ", caloRegionSampleSurfaceMap[caloRegion::DiscPositiveZ].at({sampleName, getSampleEnum(sampleName)}), volumeCounter, true);
153 volumeCounter++;
154 }
155
156 ATH_MSG_DEBUG("Have added all Barrel layers to caloBarrelCylinderNode");
157
158 // Add calo barrel node to the top level calo node.
159 itkCaloNode->addChild(caloNode);
160 itkCaloNode->addChild(caloEndCapNegativeNode);
161 itkCaloNode->addChild(caloEndCapPositiveNode);
162
163 //return the top level calo node
164 return itkCaloNode;
165}
166
168 ATH_MSG_DEBUG("Finalizing CaloBlueprintNodeBuilder");
169 return StatusCode::SUCCESS;
170}
171
173 std::map<caloRegion, caloSampleDDEElementsMap_t>& caloRegionSampleDDEElementsMap, std::map<std::string, double>& caloDimensions) const {
174
175
176 //loop over all possible calo sampling layers
177 //and create empty vectors of surfaces in the map
178
179 //Create map between each calorimeter sampling and a vector of
180 //cylinder surfaces. We can have N cylinders in a given sampling,
181 //and the value of N is determined by how often the average radius
182 //calculated for a given phi ring, at fixed Z, changes by more than
183 //a tolerance value
184
185 float maxR{0.}, maxPosZ{-std::numeric_limits<float>::max()}, minNegZ{std::numeric_limits<float>::max()};
186
187 //for each calo sampling collect all the DDE in a vector
188 for (const CaloDetDescrElement* theDDE : m_caloDetSecrMgr->element_range()){
189 if (!theDDE){
190 ATH_MSG_ERROR("Null pointer to CaloDetDescrElement");
191 continue;
192 }
193
194 maxR = std::max(theDDE->r(), maxR);
195 maxPosZ = std::max(maxPosZ, theDDE->z());
196 minNegZ = std::min(minNegZ, theDDE->z());
197
198 CaloCell_ID::CaloSample currentSample=theDDE->getSampling();
199 std::pair <std::string, CaloCell_ID::CaloSample> samplePair = std::make_pair(getSampleName(currentSample), currentSample);
200
201 //check if have cylinder symmetric about z = 0
202 if (Acts::rangeContainsValue(m_caloCylinderSymmetricSampleList, samplePair)){
203 caloRegionSampleDDEElementsMap[caloRegion::CylinderSymmetricZZero][samplePair].push_back(theDDE);
204 }
205
206 //check if have cylinder asymmetric about z = 0, if so check if in negative or positive z
207 if (Acts::rangeContainsValue(m_caloCylinderAsymmetricSampleList, samplePair)){
208 if (theDDE->z() < 0.0) {
209 caloRegionSampleDDEElementsMap[caloRegion::CylinderNegativeZ][samplePair].push_back(theDDE);
210 }
211 else {
212 caloRegionSampleDDEElementsMap[caloRegion::CylinderPositiveZ][samplePair].push_back(theDDE);
213 }
214 }
215
216 //check if sampling is in disc list
217 if (Acts::rangeContainsValue(m_caloDiscSampleList, samplePair)) {
218 //check if in negative or positive z
219 if (theDDE->z() < 0.0) {
220 caloRegionSampleDDEElementsMap[caloRegion::DiscNegativeZ][samplePair].push_back(theDDE);
221 } else {
222 caloRegionSampleDDEElementsMap[caloRegion::DiscPositiveZ][samplePair].push_back(theDDE);
223 }
224 }
225 }
226
227 caloDimensions["maxR"] = maxR;
228 caloDimensions["maxPosZ"] = maxPosZ;
229 caloDimensions["minNegZ"] = minNegZ;
230
231 auto sortAllLayersInZ = [&caloRegionSampleDDEElementsMap](const std::vector<std::pair<std::string, CaloCell_ID::CaloSample>>& caloSampleList, const caloRegion& region) {
232 for (const auto & currentSample : caloSampleList) {
233 std::vector<const CaloDetDescrElement*>& currentElements = caloRegionSampleDDEElementsMap[region][currentSample];
234 std::ranges::sort(currentElements,
235 [](const CaloDetDescrElement* a,
236 const CaloDetDescrElement* b) {
237 return a->z() < b->z();
238 });
239 }
240 };
241
242 //Sort the DDE, by Z, in all possible layers
246
247 auto sortAllLayersInR = [&caloRegionSampleDDEElementsMap](const std::vector<std::pair<std::string, CaloCell_ID::CaloSample>>& caloSampleList, const caloRegion& region) {
248 for (const auto& currentSample : caloSampleList) {
249 std::vector<const CaloDetDescrElement*>& currentElements = caloRegionSampleDDEElementsMap[region][currentSample];
250 std::ranges::sort(currentElements,
251 [](const CaloDetDescrElement* a,
252 const CaloDetDescrElement* b) {
253 return a->r() < b->r();
254 });
255 }
256 };
257
258 //Sort the DDE, by R, in all possible layers
261
262}
263
264void ActsTrk::CaloBlueprintNodeBuilder::generateCylinderSurfaces(caloSampleSurfaceMap_t& caloSampleSurfaceMap, caloSampleDDEElementsMap_t& caloSampleDDEElementsMap, bool asymmetricZ) const{
265
266 const std::vector<std::pair<std::string, CaloCell_ID::CaloSample>>& sampleList{asymmetricZ ?
268
269 for (const auto & currentSample : sampleList) {
270
271 const std::vector<const CaloDetDescrElement*>& currentElements = caloSampleDDEElementsMap[currentSample];
272
273 double maxLArBRadius = 0.0, minLArBRadius = std::numeric_limits<double>::max();
274 double lowZLarB = std::numeric_limits<double>::max(),
275 highZLarB = -std::numeric_limits<double>::max();
276
277 //loop over cells runs from -z to +z in a given sampling layer
278 //There are many cells with the same z value, but different phi values
279 //We will find the average radius of the cells in a given phi ring
280 double totalRadiusFixedPhi = 0.0;
281 bool firstCellInPhiRing = true;
282 unsigned int phiCounter = 0;
283
284 //Then we will also track changes in radius as we move in Z from
285 //each ring of cells in phi to the next ring of cells in phi
286 bool firstPhiRing = true;
287 double initialRadius = 0.0;
288 double initialZ = -std::numeric_limits<double>::max();
289
290 //check if we ever move along in Z value
291 bool movedInZ = false;
292
293 for (const CaloDetDescrElement* theDDE : currentElements){
294
295 double z = theDDE->z();
296 double radius = theDDE->r();
297
298 ATH_MSG_DEBUG(" Calo Sampling is " << currentSample.first);
299
300 if (firstCellInPhiRing) {
301 ATH_MSG_DEBUG("First Cell in phi ring " << currentSample.first << " has z = " << z << " and r = " << radius);
302 initialZ = z;
303 firstCellInPhiRing = false;
304 }
305
306 if (firstPhiRing) {
307 ATH_MSG_DEBUG("First Cell in layer " << currentSample.first << " has z = " << z << " and r = " << radius);
308 initialRadius = theDDE->r();
309 firstPhiRing = false;
310 lowZLarB = z;
311 }
312
313 ATH_MSG_DEBUG("Z and initialZ are " << z << " and " << initialZ);
314
315 //if z has not changed then we add the radius to the summed radius for this phi ring
316 //and increment the counter of cells in this phi ring
317 if (std::abs(z - initialZ) < 0.0001) {
318 ATH_MSG_DEBUG("phiCounter is " << phiCounter << " and radius is " << radius << " and totalRadiusFixedPhi is " << totalRadiusFixedPhi << " and hash is " << theDDE->calo_hash());
319 totalRadiusFixedPhi += radius;
320 phiCounter++;
321 continue;
322 }
323 else {
324 movedInZ = true;
325 firstCellInPhiRing = true;
326 if (phiCounter > 0) {
327 double cellRingRadius = totalRadiusFixedPhi / phiCounter;
328 totalRadiusFixedPhi = 0.0;
329 phiCounter = 0;
330
331 maxLArBRadius = std::max(maxLArBRadius, cellRingRadius);
332 minLArBRadius = std::min(minLArBRadius, cellRingRadius);
333
334 //if radius changes by more than tolerance, then we will create a cylinder
335 //with the average cell radius and length from neg to pos z
336 highZLarB = z;
337 ATH_MSG_DEBUG("Values of cellRingRadius, initialRadius, highZLarB and lowZLarB are " << cellRingRadius << ", " << initialRadius << ", " << highZLarB << " and " << lowZLarB);
338 if (std::abs(cellRingRadius - initialRadius) > m_radiusTolerance &&
339 highZLarB - lowZLarB > 0.0) {
340 ATH_MSG_DEBUG("CYLINDER: Create cylinder for layer " << currentSample.first);
341 ATH_MSG_DEBUG("CYLINDER: Create Cylinder: Min and Max LAr B radius are " << minLArBRadius << " " << maxLArBRadius);
342 ATH_MSG_DEBUG("CYLINDER: Create Cylinder: Min and Max LAr B z are " << lowZLarB << " " << highZLarB);
343
344 caloSampleSurfaceMap[currentSample].push_back(generateCylinderSurface(maxLArBRadius, minLArBRadius, lowZLarB, highZLarB));
345
346 //reset the dimensions of the cylinder to the initial conditions, in
347 //preparation for the next cylinder
348 firstPhiRing = true;
349 minLArBRadius = std::numeric_limits<double>::max();
350 maxLArBRadius = 0.0;
351 lowZLarB = 0.0;
352 highZLarB = 0.0;
353 }//if radius changes by more than tolerance
354 }//if at least one cell in phi (should always be the case!)
355 else ATH_MSG_ERROR("phiCounter is zero!");
356 }//if z has changed
357 }//loop over calorimeter DDE
358
359 if (0 == caloSampleSurfaceMap[currentSample].size()){
360 //If we never found any shift in Z whilst looping over the DDE
361 //then thee min/max Z and radius were not set
362 //so we set them here.
363 if (!movedInZ) {
364 lowZLarB = initialZ;
365 highZLarB = initialZ+0.001;
366 if (phiCounter > 0) {
367 maxLArBRadius = totalRadiusFixedPhi / phiCounter;
368 minLArBRadius = 0.0;
369 }
370 }
371 ATH_MSG_DEBUG("CYLINDER: Zero size Vector: Create cylinder for layer " << currentSample.first);
372 ATH_MSG_DEBUG("CYLINDER: Create Cylinder: Min and Max LAr B radius are " << minLArBRadius << " " << maxLArBRadius);
373 ATH_MSG_DEBUG("CYLINDER: Create Cylinder: Min and Max LAr B z are " << lowZLarB << " " << highZLarB);
374 caloSampleSurfaceMap[currentSample].push_back(generateCylinderSurface(maxLArBRadius, minLArBRadius, lowZLarB, highZLarB));
375 }
376 }
377}
378
379std::shared_ptr<CylinderSurface> ActsTrk::CaloBlueprintNodeBuilder::generateCylinderSurface(const double maxLArBRadius,
380 const double minLArBRadius,
381 const double lowZLarB,
382 const double highZLarB) const{
383
384 //Characterise the dimensions of the cylinder
385 double LArBRadius = (maxLArBRadius + minLArBRadius) / 2.0;
386 double LArBLength = std::abs(highZLarB - lowZLarB);
387
388 double zShift = (highZLarB + lowZLarB) / 2.0;
389 ATH_MSG_DEBUG("Cylinder radius and length are " << LArBRadius << " and " << 0.5*(LArBLength) << " with shift of " << zShift
390 <<"lowZLarB: "<<lowZLarB<<", highZLarB: "<<highZLarB);
391 return Surface::makeShared<CylinderSurface>(Amg::getTranslateZ3D(zShift), LArBRadius, LArBLength/2);
392
393}
394
396
397 for (const auto & currentSample : m_caloDiscSampleList) {
398
399 const std::vector<const CaloDetDescrElement*> & currentElements = caloSampleDDEElementsMap[currentSample];
400
401 //FCAL is treated differently because it is non-projective
402 //We create one surface for each of FCAL0, FCAL1 and FCAL2
403 if (CaloCell_ID::FCAL0 == currentSample.second || CaloCell_ID::FCAL1 == currentSample.second || CaloCell_ID::FCAL2 == currentSample.second) {
404 ATH_MSG_DEBUG("TOM3: FCAL sampling " << currentSample.second);
405
406 double fcalRMin = std::numeric_limits<double>::max();
407 double fcalRMax = std::numeric_limits<double>::min();
408 double fcalZSum = 0;
409 size_t cellCount = 0;
410
411 for (const CaloDetDescrElement* theDDE : currentElements) {
412 double r = theDDE->r();
413 fcalRMin = std::min(fcalRMin,r);
414 fcalRMax = std::max(fcalRMax,r);
415 fcalZSum += theDDE->z();
416 cellCount++;
417 }
418 if (cellCount == 0)[[unlikely]]{
419 ATH_MSG_WARNING("cellCount is zero in CaloBlueprintNodeBuilder::generateDiscSurfaces");
420 continue;
421 }
422 double fcalZ = fcalZSum / cellCount;
423 caloSampleSurfaceMap[currentSample].push_back(generateDiscSurface(fcalZ,fcalRMax, fcalRMin));
424 //now continue to the next sampling
425 continue;
426 }
427
428 //For other disc calorimeter layers we proceed to create many surfaces as needed.
429 double totalZFixedPhi = 0.0;
430 bool firstCellInPhiRing = true;
431 unsigned int phiCounter = 0;
432
433 bool firstPhiRing = true;
434 double initialRadius = 0.0;
435 double initialZ = -std::numeric_limits<double>::max();
436
437 //loop over cells runs from -z to +z in a given sampling layer
438 //There are many cells with the same z value, but different phi values
439 //We will find a min amd max radius in this phi ring.
440 double minDiscRadius = std::numeric_limits<double>::max(), maxDiscRadius = 0.0;
441
442 unsigned int currentElementsSize = currentElements.size();
443 unsigned int DDECounter = 0;
444
445 for (const CaloDetDescrElement* theDDE : currentElements){
446
447 bool isLastDDE = (DDECounter == (currentElementsSize-1));
448
449 ATH_MSG_DEBUG("Disc DDE with sampling, r and z of " << currentSample << ", " << theDDE->r() << ", " << theDDE->z());
450 ATH_MSG_DEBUG("isLastDDE is " << isLastDDE);
451
452 double z = theDDE->z();
453 double radius = theDDE->r();
454
455 if (firstCellInPhiRing) {
456 initialRadius = radius;
457 firstCellInPhiRing = false;
458 }
459
460 if (firstPhiRing) {
461 initialZ = z;
462 firstPhiRing = false;
463 minDiscRadius = radius;
464 }
465
466 //if radius is unchanged then we add the z to the summed z for this phi ring
467 //and increment the counter of cells in this phi ring
468 if (std::abs(radius - initialRadius) < 0.0001 && !isLastDDE) {
469 totalZFixedPhi += z;
470 phiCounter++;
471 DDECounter++;
472 continue;
473 }
474 else {
475 firstCellInPhiRing = true;
476 if (phiCounter > 0) {
477 double cellRingZ = totalZFixedPhi / phiCounter;
478 totalZFixedPhi = 0.0;
479 phiCounter = 0;
480
481 //if z changes by more than tolerance, then we will create a disc
482 //with the min and max radius found
483 //if we reach the last DDE and no new surface has been created, then we also create a disc surface
484 maxDiscRadius = radius;
485 ATH_MSG_DEBUG("cellRingZ, initialZ and z tolerance are " << cellRingZ << ", " << initialZ << " and " << m_zTolerance);
486 if (std::abs(cellRingZ - initialZ) > m_zTolerance || isLastDDE) {
487 ATH_MSG_DEBUG("DISC: About to create disc surface for sampling " << currentSample);
488 caloSampleSurfaceMap[currentSample].push_back(generateDiscSurface(cellRingZ,maxDiscRadius, minDiscRadius));
489 //reset the dimensions of the disc to the initial conditions, in
490 //preparation for the next disc
491 minDiscRadius = std::numeric_limits<double>::max();
492 maxDiscRadius = 0.0;
493 firstPhiRing = true;
494 }//if z changes by more than tolerance
495 }//if at least one cell in phi (should always be the case!)
496 else ATH_MSG_ERROR("phiCounter is zero!");
497 }//if radius has changed
498 DDECounter++;
499 }//loop over calorimeter DDE
500 }//loop over calo samplings
501}
502
503std::shared_ptr<Acts::DiscSurface> ActsTrk::CaloBlueprintNodeBuilder::generateDiscSurface(const double& z, const double& maxLArBRadius, const double& minLArBRadius) const{
504
505 ATH_MSG_DEBUG("DISC: Disc min and max radius are " << minLArBRadius << " and " << maxLArBRadius << " with z of " << z);
506 auto surface = Surface::makeShared<DiscSurface>(Amg::getTranslateZ3D(z), minLArBRadius, maxLArBRadius);
507
508 return surface;
509
510}
511
512void ActsTrk::CaloBlueprintNodeBuilder::addCylindricalTrackingVolumeToCaloNode(CylinderContainerBlueprintNode& containerNode, const std::string& volumeName,const std::vector<std::shared_ptr<Acts::Surface>>& surfaces, int layerIndex, const bool& isDisc) const{
513
514 // Construct the container node with geometry identifier and layer, and add the surfaces to the layer.
515 Acts::GeometryIdentifierBlueprintNode& geoIdNode = containerNode.withGeometryIdentifier();
516 geoIdNode.setAllVolumeIdsTo(s_caloBarrelId +
517 layerIndex);
518
519 AxisDirection axis = AxisDirection::AxisZ;
520 if (isDisc) axis = AxisDirection::AxisR;
521 CylinderContainerBlueprintNode& cylinder = geoIdNode.addCylinderContainer(volumeName,
522 axis);
523
524 cylinder.addLayer(volumeName + "_Layer", [&](auto& layer) {
525 layer.setSurfaces(surfaces);
526 layer.setEnvelope(Acts::ExtentEnvelope{{
527 .z = {0.1_mm, 0.1_mm},
528 .r = {2_mm, 2_mm},
529 }});
530 });
531
532}
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_INFO(x,...)
Acts::VolumeResizeStrategy ResizeStrategy
Acts::VolumeAttachmentStrategy AttachmentStrategy
std::map< std::pair< std::string, CaloCell_ID::CaloSample >, std::vector< std::shared_ptr< Acts::Surface > > > caloSampleSurfaceMap_t
std::map< std::pair< std::string, CaloCell_ID::CaloSample >, std::vector< const CaloDetDescrElement * > > caloSampleDDEElementsMap_t
std::unique_ptr< CaloDetDescrManager > buildCaloDetDescrNoAlign(ISvcLocator *svcLocator, IMessageSvc *msgSvc)
static Double_t a
size_t size() const
Number of registered mappings.
#define z
void addCylindricalTrackingVolumeToCaloNode(Acts::CylinderContainerBlueprintNode &containerNode, const std::string &volumeName, const std::vector< std::shared_ptr< Acts::Surface > > &surfaces, int layerIndex, const bool &isDisc) const
addCylindricalTrackingVolumeToCaloNode adds a cylindrical tracking volume to the calo node.
std::vector< std::pair< std::string, CaloCell_ID::CaloSample > > m_caloDiscSampleList
std::string getSampleName(CaloCell_ID::CaloSample currentSample) const
std::shared_ptr< Acts::DiscSurface > generateDiscSurface(const double &z, const double &maxLArBRadius, const double &minLArBRadius) const
std::vector< std::pair< std::string, CaloCell_ID::CaloSample > > m_caloCylinderAsymmetricSampleList
void generateCylinderSurfaces(caloSampleSurfaceMap_t &caloSampleSurfaceMap, caloSampleDDEElementsMap_t &caloSampleDDEElementsMap, bool asymmetricZ) const
generateCylinderSurfaces generates cylindrical surfaces for each calo sampling.
std::shared_ptr< Acts::CylinderSurface > generateCylinderSurface(const double maxLArBRadius, const double minLArBRadius, const double lowZLarB, const double highZLarB) const
generateCylinderSurface generates a cylindrical surface for a given set of parameters.
std::shared_ptr< Acts::BlueprintNode > buildBlueprintNode(const Acts::GeometryContext &gctx, std::shared_ptr< Acts::BlueprintNode > &&childNode) override
Build the Itk Blueprint Node.
std::vector< std::pair< std::string, CaloCell_ID::CaloSample > > m_caloCylinderSymmetricSampleList
void fillMaps(std::map< caloRegion, caloSampleDDEElementsMap_t > &caloRegionSampleDDEElementsMap, std::map< std::string, double > &caloDimensions) const
fillMaps fills two maps.
std::unique_ptr< CaloDetDescrManager > m_caloDetSecrMgr
CaloCell_ID::CaloSample getSampleEnum(const std::string &sampleName) const
void generateDiscSurfaces(caloSampleSurfaceMap_t &caloSampleSurfaceMap, caloSampleDDEElementsMap_t &caloSampleDDEElementsMap) const
CaloSampling::CaloSample CaloSample
Definition CaloCell_ID.h:53
This class groups all DetDescr information related to a CaloCell.
int r
Definition globals.cxx:22
Define the volume parts of the GeometryIdentifier for each ATLAS subsystem centrally.
constexpr std::size_t s_caloEnvelopeID
Volume Ids ofthe Calorimeter.
constexpr std::size_t s_caloBarrelId
Amg::Isometry3D getTranslateZ3D(const double Z)
: Returns a shift transformation along the z-axis
IMessageSvc * getMessageSvc(bool quiet=false)
#define unlikely(x)