10#include "Acts/Geometry/Blueprint.hpp"
11#include "Acts/Geometry/StaticBlueprintNode.hpp"
13#include "Acts/Surfaces/RadialBounds.hpp"
14#include "Acts/Surfaces/CylinderBounds.hpp"
15#include "Acts/Geometry/ContainerBlueprintNode.hpp"
16#include "Acts/Geometry/Extent.hpp"
17#include "Acts/Definitions/Units.hpp"
18#include "Acts/Geometry/LayerBlueprintNode.hpp"
19#include "Acts/Geometry/VolumeResizeStrategy.hpp"
20#include "Acts/Geometry/VolumeAttachmentStrategy.hpp"
21#include "Acts/Geometry/TrackingVolume.hpp"
22#include "Acts/Geometry/CylinderVolumeBounds.hpp"
23#include "Acts/Geometry/PadBlueprintNode.hpp"
24#include "Acts/Geometry/GeometryIdentifierBlueprintNode.hpp"
26#include "Acts/Utilities/Helpers.hpp"
27#include "Acts/Utilities/AxisDefinitions.hpp"
31#include "CaloGeoHelpers/CaloSampling.h"
36using namespace Acts::UnitLiterals;
39using SampleSet_t = std::unordered_set<CaloCell_ID::CaloSample>;
47 CaloCell_ID::PreSamplerE,
48 CaloCell_ID::EME1, CaloCell_ID::EME2, CaloCell_ID::EME3,
49 CaloCell_ID::HEC0, CaloCell_ID::HEC1, CaloCell_ID::HEC2, CaloCell_ID::HEC3,
50 CaloCell_ID::TileGap3,
51 CaloCell_ID::FCAL0, CaloCell_ID::FCAL1, CaloCell_ID::FCAL2};
53 static const SampleSet_t s_caloCylinderSymmetricSampleList{
54 CaloCell_ID::PreSamplerB,
55 CaloCell_ID::EMB1, CaloCell_ID::EMB2, CaloCell_ID::EMB3,
56 CaloCell_ID::TileBar0, CaloCell_ID::TileBar1, CaloCell_ID::TileBar2};
58 static const SampleSet_t s_caloCylinderAsymmetricSampleList{
59 CaloCell_ID::TileGap1, CaloCell_ID::TileGap2,
60 CaloCell_ID::TileExt0, CaloCell_ID::TileExt1, CaloCell_ID::TileExt2};
62 std::string
print(std::span<const CaloDetDescrElement* const> elements) {
63 std::stringstream sstr{};
66 sstr<<
" - "<<(counter++)<<
") "
68 <<
", radius: ["<< (theDDE->r() - 0.5*theDDE->dr())<<
";"
69 <<(theDDE->r() + 0.5*theDDE->dr())
70 <<
"], z: ["<<(theDDE->z() -0.5* theDDE->dz())<<
";"
71 <<(theDDE->z() +0.5* theDDE->dz())<<
"]"<<std::endl;
85 return StatusCode::FAILURE;
87 return StatusCode::SUCCESS;
94 sortedElements[Acts::toUnderlying(sample)].push_back(theDDE);
97 if (detElVec.empty()) {
103 if (!s_caloDiscSampleList.count(sample)) {
104 if (std::abs(
a->r() - b->r()) > Acts::s_epsilon) {
105 return a->r() < b->r();
107 return a->z() < b->z();
110 if (std::abs(
a->z() - b->z()) > Acts::s_epsilon) {
111 return a->z() < b->z();
113 return a->r() < b->r();
116 auto [begin, end] = std::ranges::unique(detElVec,
118 return std::abs(
a->r() - b->r()) < Acts::s_onSurfaceTolerance &&
119 std::abs(
a->z() - b->z()) < Acts::s_onSurfaceTolerance;
121 const std::size_t nBefore = detElVec.size();
122 detElVec.erase(begin, end);
123 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - Removed "<<(nBefore - detElVec.size())
125 <<
", current size: "<<detElVec.size()<<
"\n"<<
print(detElVec));
131 DetElVec_t& gapVec = sortedElements[CaloSampling::TileGap2];
132 DetElVec_t& barVec = sortedElements[CaloSampling::TileBar2];
133 barVec.insert(barVec.end(), gapVec.begin(), gapVec.end());
135 return sortedElements;
140 float zMin{std::numeric_limits<float>::max()},
141 zMax{-std::numeric_limits<float>::max()},
142 rMin{std::numeric_limits<float>::max()}, rMax{0.f};
144 zMin = std::min(zMin, detEl->z() - 0.5f*detEl->dz());
145 zMax = std::max(zMax, detEl->z() + 0.5f*detEl->dz());
146 rMin = std::min(rMin, detEl->r() - 0.5f*detEl->dr());
147 rMax = std::max(rMax, detEl->r() + 0.5f*detEl->dr());
149 const float cylinderR = 0.5*(rMin + rMax);
150 const float cylinderZ = 0.5*(zMax - zMin);
151 const float surfaceZ = 0.5*(zMin + zMax);
152 auto cylinder = Acts::Surface::makeShared<Acts::CylinderSurface>(
Amg::getTranslateZ3D(surfaceZ), cylinderR, cylinderZ);
153 cylinder->assignThickness(0.5*(rMax - rMin));
154 cylinder->assignGeometryId(Acts::GeometryIdentifier{}.withLayer(detElVec.front()->getSampling()));
156 <<
" r["<<rMin<<
";"<<rMax<<
"] z["<<zMin<<
";"<<zMax<<
"]"
157 <<
" -> surface parameters R: "<<cylinder->bounds()<<
", Z position: "<<surfaceZ
158 <<
", "<<cylinder->geometryId());
163 float zMin{std::numeric_limits<float>::max()},
164 zMax{-std::numeric_limits<float>::max()},
165 rMin{std::numeric_limits<float>::max()}, rMax{0.f};
167 zMin = std::min(zMin, detEl->z() - 0.5f*detEl->dz());
168 zMax = std::max(zMax, detEl->z() + 0.5f*detEl->dz());
169 rMin = std::min(rMin, detEl->r() - 0.5f*detEl->dr());
170 rMax = std::max(rMax, detEl->r() + 0.5f*detEl->dr());
172 const float surfaceZ = 0.5*(zMin + zMax);
173 const auto sampling = detElVec.front()->getSampling();
175 <<
" r["<<rMin<<
";"<<rMax<<
"] z["<<zMin<<
";"<<zMax<<
"]"
176 <<
" -> surface position: "<<surfaceZ);
177 auto disc = Acts::Surface::makeShared<Acts::DiscSurface>(
Amg::getTranslateZ3D(surfaceZ), rMin, rMax);
178 disc->assignThickness(0.5*(zMax - zMin));
179 disc->assignGeometryId(Acts::GeometryIdentifier{}.withLayer(sampling));
185 for (
const DetElVec_t& detElVec : sortedElements) {
186 if (detElVec.empty()) {
191 if (s_caloCylinderSymmetricSampleList.count(sample)) {
193 }
else if (s_caloCylinderAsymmetricSampleList.count(sample)) {
194 for (DetElVec_t::const_iterator itr = detElVec.begin();
195 itr != detElVec.end(); ) {
197 auto next = std::ranges::find_if(itr, detElVec.end(), [&](
const CaloDetDescrElement* testMe){
198 return detEl->z() * testMe->z() < 0.;
204 for (DetElVec_t::const_iterator itr = detElVec.begin();
205 itr != detElVec.end(); ) {
207 auto next = std::ranges::find_if(itr, detElVec.end(), [&](
const CaloDetDescrElement* testMe){
208 return detEl->z() * testMe->z() < 0.;
210 const auto idx = detEl->
z() > 0 ? Acts::toUnderlying(
DiscPositiveZ)
219std::shared_ptr<Acts::BlueprintNode>
221 std::shared_ptr<Acts::BlueprintNode>&& childNode) {
228 std::shared_ptr<Acts::BlueprintNode> caloNode{};
230 Acts::TrackingVolume* caloVolume{};
233 caloVolume = caloEnvelope.get();
234 caloNode = std::make_unique<Acts::StaticBlueprintNode>(std::move(caloEnvelope));
236 auto barrelNode = std::make_shared<Acts::CylinderContainerBlueprintNode>(
237 "CaloBarrelCylinder", Acts::AxisDirection::AxisR);
238 barrelNode->setAttachmentStrategy(Acts::VolumeAttachmentStrategy::Second);
239 barrelNode->setResizeStrategy(Acts::VolumeResizeStrategy::Expand);
241 barrelNode->addChild(std::move(childNode));
243 std::unordered_map<CaloSampling::CaloSample, unsigned> barrelExtraCounts{};
246 if (s_caloCylinderAsymmetricSampleList.count(layer) ||
247 layer == CaloSampling::TileBar2) {
248 std::ranges::for_each(
fillLayer(tgContext, std::move(surface)),
249 [&](std::shared_ptr<Acts::Surface>& surfToAdd){
250 surfToAdd->assignGeometryId(Acts::GeometryIdentifier{}.withVolume(
s_caloEnvelopeID)
252 .withSensitive(barrelExtraCounts[layer]++));
253 caloVolume->addSurface(std::move(surfToAdd));
258 layerNode->setSurfaces(
fillLayer(tgContext, std::move(surface)));
259 layerNode->setEnvelope(Acts::ExtentEnvelope{{
260 .z = {0.1_mm, 0.1_mm},
261 .r = {1._cm, 1._cm}}});
262 auto idNode = std::make_shared<Acts::GeometryIdentifierBlueprintNode>();
263 idNode->addChild(std::move(layerNode));
265 idNode->setLayerIdTo(layer);
266 barrelNode->addChild(std::move(idNode));
268 caloNode->addChild(std::move(barrelNode));
270 auto layerNode = std::make_shared<Acts::LayerBlueprintNode>(std::format(
"CaloLayer{:}", disc));
271 layerNode->setEnvelope(Acts::ExtentEnvelope{{
273 .r = {2_mm, 2_mm}, }});
276 std::vector<std::shared_ptr<Acts::Surface>> layerSurfaces{};
278 for (
auto& surface : sensitives[Acts::toUnderlying(disc)]) {
281 if (layer != CaloSampling::TileGap3) {
282 std::ranges::for_each(
fillLayer(tgContext, std::move(surface)),
283 [&](std::shared_ptr<Acts::Surface>& surf) {
284 surf->assignGeometryId(Acts::GeometryIdentifier{}.withVolume(volId).
285 withLayer(layer).withSensitive(layerSurfaces.size()+1));
286 layerSurfaces.push_back(std::move(surf));
289 surface->assignGeometryId(surface->geometryId().withVolume(
s_caloEnvelopeID)
290 .withSensitive(barrelExtraCounts[layer]++));
291 caloVolume->addSurface(std::move(surface));
294 layerNode->setSurfaces(std::move(layerSurfaces));
295 auto idNode = std::make_shared<Acts::GeometryIdentifierBlueprintNode>();
296 idNode->addChild(std::move(layerNode));
297 idNode->setAllVolumeIdsTo(volId);
298 caloNode->addChild(std::move(idNode));
304 double maxR{0.}, minZ{std::numeric_limits<double>::max()}, maxZ{-std::numeric_limits<double>::max()};
305 for (
auto& surfaces : surfacePerRegion) {
306 for (
auto& surface : surfaces) {
308 if (surface->type() == Acts::Surface::SurfaceType::Disc) {
309 minZ = std::min(minZ, center.z() - 0.5*surface->thickness());
310 maxZ = std::max(maxZ, center.z() + 0.5*surface->thickness());
311 const auto& bounds =
static_cast<const Acts::RadialBounds&
>(surface->bounds());
312 maxR = std::max(maxR, bounds.rMax());
314 const auto& bounds =
static_cast<const Acts::CylinderBounds&
>(surface->bounds());
315 using enum Acts::CylinderBounds::BoundValues;
316 minZ = std::min(minZ, center.z() - bounds.get(eHalfLengthZ));
317 maxZ = std::max(maxZ, center.z() + bounds.get(eHalfLengthZ));
318 maxR = std::max(maxR, bounds.get(eR) + 0.5*surface->thickness());
322 auto volBounds = std::make_shared<Acts::CylinderVolumeBounds>(0, maxR + 1_cm, 0.5*(maxZ - minZ) + 1._cm);
323 ATH_MSG_DEBUG(__func__<<
"() Create envelope volume with bounds "<<(*volBounds));
325 volBounds,
"ITkCalo");
326 volume->assignGeometryId(Acts::GeometryIdentifier{}.withVolume(
s_caloEnvelopeID));
329 std::vector<std::shared_ptr<Acts::Surface>>
331 std::shared_ptr<Acts::Surface>&& centralSurf)
const{
333 centralSurf->assignGeometryId(Acts::GeometryIdentifier{});
334 if (extraSurf == 0) {
335 return {std::move(centralSurf)};
337 const double stepLength = centralSurf->thickness() / (extraSurf +1u);
338 const Acts::Transform3& trf = centralSurf->localToGlobalTransform(tgContext);
339 std::vector<std::shared_ptr<Acts::Surface>> surfaces{};
340 if (centralSurf->type() == Acts::Surface::SurfaceType::Cylinder) {
341 const auto& bounds =
static_cast<const Acts::CylinderBounds&
>(centralSurf->bounds());
342 const double radius = bounds.get(Acts::CylinderBounds::BoundValues::eR);
343 const double halfZ = bounds.get(Acts::CylinderBounds::BoundValues::eHalfLengthZ);
344 for (
unsigned extra = 1ul; extra <= extraSurf; ++extra) {
345 surfaces.emplace_back(Acts::Surface::makeShared<Acts::CylinderSurface>(trf, radius - stepLength* extra, halfZ));
346 surfaces.emplace_back(Acts::Surface::makeShared<Acts::CylinderSurface>(trf, radius + stepLength* extra, halfZ));
348 }
else if (centralSurf->type() == Acts::Surface::SurfaceType::Disc) {
349 using DiscB = Acts::RadialBounds;
350 auto bounds = std::make_shared<DiscB>(
static_cast<const DiscB&
>(centralSurf->bounds()));
351 for (
unsigned extra = 1ul; extra <= extraSurf; ++extra) {
352 const double shiftZ = stepLength *extra;
353 surfaces.emplace_back(Acts::Surface::makeShared<Acts::DiscSurface>(trf *
Amg::getTranslateZ3D(shiftZ),
355 surfaces.emplace_back(Acts::Surface::makeShared<Acts::DiscSurface>(trf *
Amg::getTranslateZ3D(-shiftZ),
359 surfaces.push_back(std::move(centralSurf));
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
std::unordered_set< CaloCell_ID::CaloSample > SampleSet_t
std::unique_ptr< CaloDetDescrManager > buildCaloDetDescrNoAlign(ISvcLocator *svcLocator, IMessageSvc *msgSvc)
void print(char *figname, TCanvas *c1)
DetElementMap_t fillDetectorElements(const CaloDetDescrManager &detDecrMgr) const
Fill the detector elements per calorimeter layer and sort them in ascending r(z) for the barrel (endc...
Gaudi::Property< std::vector< std::uint32_t > > m_surfaceDuplicates
Configure the insert of extra surfaces per each calorimeter layer.
std::vector< const CaloDetDescrElement * > DetElVec_t
std::vector< std::shared_ptr< Acts::Surface > > fillLayer(const Acts::GeometryContext &tgContext, std::shared_ptr< Acts::Surface > &¢ralSurf) const
Fill the layer with extra surfaces.
SurfaceMap_t translateToSurfaces(const DetElementMap_t &detElements) const
Translate all detector elements to a Cylinder and Disc surfaces.
std::shared_ptr< Acts::Surface > createDiscSurface(std::span< const CaloDetDescrElement *const > detElements) const
Create a disc surface from the passed calo description elements.
std::unique_ptr< Acts::TrackingVolume > envelopeVolume(const Acts::GeometryContext &tgContext, const SurfaceMap_t &surfacesPerRegion) const
Create the envelope volume of the Calo Tracking Geometry.
std::array< std::vector< std::shared_ptr< Acts::Surface > >, Acts::toUnderlying(caloRegion::nRegions)> SurfaceMap_t
Vector of surfaces per calorimeter region.
std::shared_ptr< Acts::Surface > createCylinderSurface(std::span< const CaloDetDescrElement *const > detElements) const
Create a cylinder surface from a list of Calo detector description elements.
std::array< DetElVec_t, CaloSampling::getNumberOfSamplings()> DetElementMap_t
Vector of Detector Elements per calorimeter layer.
virtual StatusCode initialize() override final
std::shared_ptr< Acts::BlueprintNode > buildBlueprintNode(const Acts::GeometryContext &gctx, std::shared_ptr< Acts::BlueprintNode > &&childNode) override
CaloSampling::CaloSample CaloSample
This class groups all DetDescr information related to a CaloCell.
calo_element_range element_range() const
Range over element vector.
This class provides the client interface for accessing the detector description information common to...
static std::string getSamplingName(CaloSample theSample)
Returns a string (name) for each CaloSampling.
static constexpr unsigned int getNumberOfSamplings()
Get number of available samplings.
Define the volume parts of the GeometryIdentifier for each ATLAS subsystem centrally.
constexpr std::size_t s_caloEndcapAId
constexpr std::size_t s_caloEnvelopeID
Volume Ids ofthe Calorimeter.
constexpr std::size_t s_caloBarrelId
constexpr std::size_t s_caloEndcapCId
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
CaloBlueprintNodeBuilder::DetElementMap_t DetElementMap_t
CaloBlueprintNodeBuilder::SurfaceMap_t SurfaceMap_t
Eigen::Matrix< double, 3, 1 > Vector3D
Amg::Isometry3D getTranslateZ3D(const double Z)
: Returns a shift transformation along the z-axis
IMessageSvc * getMessageSvc(bool quiet=false)