File indexing completed on 2025-10-13 08:19:45
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Definitions/Units.hpp"
0012 #include "Acts/Detector/Detector.hpp"
0013 #include "Acts/Geometry/Blueprint.hpp"
0014 #include "Acts/Geometry/BlueprintNode.hpp"
0015 #include "Acts/Geometry/ContainerBlueprintNode.hpp"
0016 #include "Acts/Geometry/GeometryContext.hpp"
0017 #include "Acts/Geometry/GeometryIdentifierBlueprintNode.hpp"
0018 #include "Acts/Geometry/LayerBlueprintNode.hpp"
0019 #include "Acts/Geometry/MaterialDesignatorBlueprintNode.hpp"
0020 #include "Acts/Geometry/VolumeAttachmentStrategy.hpp"
0021 #include "Acts/Navigation/SurfaceArrayNavigationPolicy.hpp"
0022 #include "Acts/Navigation/TryAllNavigationPolicy.hpp"
0023 #include "Acts/Surfaces/Surface.hpp"
0024 #include "Acts/Surfaces/SurfaceArray.hpp"
0025 #include "Acts/Surfaces/SurfaceBounds.hpp"
0026 #include "Acts/Utilities/Enumerate.hpp"
0027 #include "Acts/Utilities/Logger.hpp"
0028 #include "Acts/Utilities/TransformRange.hpp"
0029 #include "ActsPlugins/DD4hep/DD4hepConversionHelpers.hpp"
0030 #include "ActsPlugins/DD4hep/DD4hepDetectorElement.hpp"
0031 #include "ActsTests/CommonHelpers/CylindricalTrackingGeometry.hpp"
0032 #include "ActsTests/CommonHelpers/TemporaryDirectory.hpp"
0033
0034 #include <format>
0035 #include <fstream>
0036 #include <string>
0037
0038 #include <DD4hep/DetElement.h>
0039 #include <DD4hep/DetFactoryHelper.h>
0040 #include <DD4hep/Detector.h>
0041 #include <XML/Utilities.h>
0042 #include <XMLFragments.hpp>
0043
0044 #include "DD4hepTestsHelper.hpp"
0045
0046 using namespace Acts;
0047 using namespace ActsPlugins;
0048
0049 namespace ActsTests {
0050
0051 GeometryContext tContext;
0052 CylindricalTrackingGeometry cGeometry = CylindricalTrackingGeometry(tContext);
0053
0054 const char* beampipe_head_xml =
0055 R""""(
0056 <detectors>
0057 <detector id="0" name="BeamPipe" type="BarrelDetector">
0058 <type_flags type="DetType_TRACKER + DetType_BEAMPIPE"/>
0059 <layers>
0060 <layer id="0" name="BeamPipeLayer">
0061 )"""";
0062
0063 const char* nec_head_xml =
0064 R""""(
0065 <detector id="1" name="PixelNegativeEndcap" type="EndcapDetector" readout="PixelReadout">
0066 <type_flags type="DetType_TRACKER + DetType_BARREL"/>
0067 )"""";
0068
0069 const char* barrel_head_xml =
0070 R""""(
0071 <detector id="2" name="PixelBarrel" type="BarrelDetector" readout="PixelReadout">
0072 <type_flags type="DetType_TRACKER + DetType_BARREL"/>
0073 )"""";
0074
0075 const char* pec_head_xml =
0076 R""""(
0077 <detector id="3" name="PixelPositiveEndcap" type="EndcapDetector" readout="PixelReadout">
0078 <type_flags type="DetType_TRACKER + DetType_BARREL"/>
0079 )"""";
0080
0081 const char* plugin_xml =
0082 R"""(<plugins>
0083 <plugin name="DD4hep_ParametersPlugin">
0084 <argument value="world"/>
0085 <argument value="acts_world: bool = true"/>
0086 <argument value="acts_world_type: int = 3"/>
0087 <argument value="acts_world_bvalues_n: int = 3"/>
0088 <argument value="acts_world_bvalues_0: double = 0"/>
0089 <argument value="acts_world_bvalues_1: double = 150*mm"/>
0090 <argument value="acts_world_bvalues_2: double = 1000*mm"/>
0091 <argument value="acts_world_binning: str = r"/>
0092 <argument value="acts_world_geo_id: str = incremental"/>
0093 <argument value="acts_world_root_volume_finder: str = indexed"/>
0094 </plugin>
0095 <plugin name="DD4hep_ParametersPlugin">
0096 <argument value="BeamPipe"/>
0097 <argument value="acts_volume: bool = true"/>
0098 <argument value="acts_volume_type: int = 3"/>
0099 <argument value="acts_volume_bvalues_n: int = 3"/>
0100 <argument value="acts_volume_bvalues_0: double = 0"/>
0101 <argument value="acts_volume_bvalues_1: double = 20*mm"/>
0102 <argument value="acts_volume_bvalues_2: double = 1000*mm"/>
0103 <argument value="acts_volume_internals: bool = true"/>
0104 <argument value="acts_volume_internals_type: str = layer"/>
0105 </plugin>
0106 <plugin name="DD4hep_ParametersPlugin">
0107 <argument value="Pixel"/>
0108 <argument value="acts_container: bool = true"/>
0109 <argument value="acts_container_type: int = 3"/>
0110 <argument value="acts_container_bvalues_n: int = 3"/>
0111 <argument value="acts_container_bvalues_0: double = 20*mm"/>
0112 <argument value="acts_container_bvalues_1: double = 150*mm"/>
0113 <argument value="acts_container_bvalues_2: double = 1000*mm"/>
0114 <argument value="acts_container_binning: str = z"/>
0115 </plugin>
0116 <plugin name="DD4hep_ParametersPlugin">
0117 <argument value="PixelNegativeEndcap"/>
0118 <argument value="acts_container: bool = true"/>
0119 <argument value="acts_container_type: int = 3"/>
0120 <argument value="acts_container_bvalues_n: int = 3"/>
0121 <argument value="acts_container_bvalues_0: double = 20*mm"/>
0122 <argument value="acts_container_bvalues_1: double = 150*mm"/>
0123 <argument value="acts_container_bvalues_2: double = 200*mm"/>
0124 <argument value="acts_container_binning: str = z"/>
0125 <argument value="acts_container_z: double = -800*mm"/>
0126 </plugin>
0127 <plugin name="DD4hep_ParametersPlugin">
0128 <argument value="PixelBarrel"/>
0129 <argument value="acts_container: bool = true"/>
0130 <argument value="acts_container_type: int = 3"/>
0131 <argument value="acts_container_bvalues_n: int = 3"/>
0132 <argument value="acts_container_bvalues_0: double = 20*mm"/>
0133 <argument value="acts_container_bvalues_1: double = 150*mm"/>
0134 <argument value="acts_container_bvalues_2: double = 600*mm"/>
0135 <argument value="acts_container_binning: str = r"/>
0136 </plugin>
0137 <plugin name="DD4hep_ParametersPlugin">
0138 <argument value="PixelPositiveEndcap"/>
0139 <argument value="acts_container: bool = true"/>
0140 <argument value="acts_container_type: int = 3"/>
0141 <argument value="acts_container_bvalues_n: int = 3"/>
0142 <argument value="acts_container_bvalues_0: double = 20*mm"/>
0143 <argument value="acts_container_bvalues_1: double = 150*mm"/>
0144 <argument value="acts_container_bvalues_2: double = 200*mm"/>
0145 <argument value="acts_container_binning: str = z"/>
0146 <argument value="acts_container_z: double = 800*mm"/>
0147 </plugin>
0148 </plugins>
0149 )""";
0150
0151 const char* indent_4_xml = " ";
0152 const char* indent_8_xml = " ";
0153 const char* indent_12_xml = " ";
0154
0155 void generateXML(const std::filesystem::path& xmlPath) {
0156 CylindricalTrackingGeometry::DetectorStore dStore;
0157
0158
0159 double necZ = -800.;
0160 auto necR0Surfaces = cGeometry.surfacesRing(dStore, 6.4, 12.4, 18., 0.125, 0.,
0161 42., necZ, 2., 22u);
0162
0163 auto necR1Surfaces = cGeometry.surfacesRing(dStore, 12.4, 20.4, 30., 0.125,
0164 0., 80., necZ, 2., 22u);
0165
0166 std::vector<std::vector<Surface*>> necSurfaces = {necR0Surfaces,
0167 necR1Surfaces};
0168
0169
0170 std::vector<std::array<double, 2u>> innerOuter = {
0171 {25., 35.}, {65., 75.}, {110., 120.}};
0172 auto b0Surfaces = cGeometry.surfacesCylinder(dStore, 8.4, 36., 0.15, 0.14,
0173 31., 3., 2., {16, 14});
0174
0175 auto b1Surfaces = cGeometry.surfacesCylinder(dStore, 8.4, 36., 0.15, 0.14,
0176 71., 3., 2., {32, 14});
0177
0178 auto b2Surfaces = cGeometry.surfacesCylinder(dStore, 8.4, 36., 0.15, 0.14,
0179 116., 3., 2., {52, 14});
0180
0181 std::vector<std::vector<Surface*>> barrelSurfaces = {b0Surfaces, b1Surfaces,
0182 b2Surfaces};
0183
0184
0185 double pecZ = 800.;
0186 auto pecR0Surfaces = cGeometry.surfacesRing(dStore, 6.4, 12.4, 18., 0.125, 0.,
0187 42., pecZ, 2., 22u);
0188
0189 auto pecR1Surfaces = cGeometry.surfacesRing(dStore, 12.4, 20.4, 30., 0.125,
0190 0., 80., pecZ, 2., 22u);
0191
0192 std::vector<std::vector<Surface*>> pecSurfaces = {pecR0Surfaces,
0193 pecR1Surfaces};
0194
0195
0196 std::ofstream cxml;
0197 cxml.open(xmlPath);
0198 cxml << head_xml;
0199 cxml << segmentation_xml;
0200
0201
0202 cxml << beampipe_head_xml << '\n';
0203 cxml << indent_12_xml << "<acts_passive_surface>" << '\n';
0204 cxml << indent_12_xml
0205 << "<tubs rmin=\"19*mm\" rmax=\"20*mm\" dz=\"800*mm\" "
0206 "material=\"Air\"/>"
0207 << '\n';
0208 cxml << indent_12_xml << "</acts_passive_surface>" << '\n';
0209 cxml << indent_12_xml << "</layer> " << '\n';
0210 cxml << indent_8_xml << "</layers>" << '\n';
0211 cxml << indent_8_xml << "</detector>" << '\n';
0212
0213
0214 const char* pixel_assembly_xml =
0215 R"""(<detector id="4" name="Pixel" type="DD4hep_SubdetectorAssembly" vis="invisible">
0216 <shape name="PixelVolume" type="Tube" rmin="20*mm" rmax="150*mm" dz="1000*mm" material="Air"/>
0217 <composite name="PixelNegativeEndcap"/>
0218 <composite name="PixelBarrel"/>
0219 <composite name="PixelPositiveEndcap"/>
0220 </detector>)""";
0221
0222 cxml << pixel_assembly_xml << '\n';
0223 cxml << "</detectors>" << '\n';
0224
0225
0226
0227
0228 cxml << "<detectors>" << '\n';
0229
0230 cxml << nec_head_xml << '\n';
0231 cxml << indent_8_xml << "<layers>" << '\n';
0232 cxml << indent_8_xml << "<acts_container/> " << '\n';
0233 cxml << indent_4_xml << "<layer name=\"NegEndcapLayer_0\" id=\"0\">" << '\n';
0234 cxml << indent_4_xml << "<acts_volume dz=\"20*mm\" cz=\"-800.*mm\"/>" << '\n';
0235 cxml << indent_8_xml << "<modules>" << '\n';
0236 for (const auto& ring : necSurfaces) {
0237 for (const auto& s : ring) {
0238 cxml << indent_12_xml
0239 << DD4hepTestsHelper::surfaceToXML(tContext, *s,
0240 Transform3::Identity())
0241 << "\n";
0242 }
0243 }
0244 cxml << indent_8_xml << "</modules>" << '\n';
0245 cxml << indent_8_xml << "</layer> " << '\n';
0246 cxml << indent_8_xml << "</layers>" << '\n';
0247 cxml << indent_8_xml << "</detector>" << '\n';
0248
0249
0250 cxml << barrel_head_xml << '\n';
0251 cxml << indent_8_xml << "<layers>" << '\n';
0252 cxml << indent_8_xml << "<acts_container/> " << '\n';
0253 for (const auto [ib, bs] : enumerate(barrelSurfaces)) {
0254 cxml << indent_4_xml << "<layer name=\"PixelBarrel_" << ib << "\" id=\""
0255 << ib << "\">" << '\n';
0256 cxml << indent_4_xml << "<acts_volume rmin=\"" << innerOuter[ib][0u]
0257 << "*mm\" rmax=\"" << innerOuter[ib][1u] << "*mm\"/>";
0258 cxml << indent_8_xml << "<modules>" << '\n';
0259 for (const auto& s : bs) {
0260 cxml << indent_12_xml
0261 << DD4hepTestsHelper::surfaceToXML(tContext, *s,
0262 Transform3::Identity())
0263 << "\n";
0264 }
0265 cxml << indent_8_xml << "</modules>" << '\n';
0266 cxml << indent_8_xml << "</layer>" << '\n';
0267 }
0268 cxml << indent_8_xml << "</layers>" << '\n';
0269 cxml << indent_8_xml << "</detector>" << '\n';
0270
0271
0272 cxml << pec_head_xml << '\n';
0273 cxml << indent_8_xml << "<layers>" << '\n';
0274 cxml << indent_8_xml << "<acts_container/> " << '\n';
0275 cxml << indent_4_xml << "<layer name=\"PosEndcapLayer_0\" id=\"0\">" << '\n';
0276 cxml << indent_4_xml << "<acts_volume dz=\"20*mm\" cz=\"800.*mm\"/>" << '\n';
0277 cxml << indent_8_xml << "<modules>" << '\n';
0278 for (const auto& ring : pecSurfaces) {
0279 for (const auto& s : ring) {
0280 cxml << indent_12_xml
0281 << DD4hepTestsHelper::surfaceToXML(tContext, *s,
0282 Transform3::Identity())
0283 << "\n";
0284 }
0285 }
0286 cxml << indent_8_xml << "</modules>" << '\n';
0287 cxml << indent_8_xml << "</layer> " << '\n';
0288 cxml << indent_8_xml << "</layers>" << '\n';
0289 cxml << indent_8_xml << "</detector>" << '\n';
0290 cxml << indent_8_xml << "</detectors>" << '\n';
0291
0292 cxml << plugin_xml << '\n';
0293 cxml << end_xml << '\n';
0294 cxml.close();
0295 }
0296
0297 using namespace dd4hep;
0298 using namespace UnitLiterals;
0299
0300 using enum AxisBoundaryType;
0301 using enum AxisDirection;
0302 using enum CylinderVolumeBounds::Face;
0303 using enum SurfaceArrayNavigationPolicy::LayerType;
0304 using AttachmentStrategy = VolumeAttachmentStrategy;
0305 using ResizeStrategy = VolumeResizeStrategy;
0306
0307
0308
0309 void print_elements(const DetElement& el, unsigned int level = 0) {
0310 for (const auto& [name, child] : el.children()) {
0311 for (unsigned int i = 0; i < level; ++i) {
0312 std::cout << "\t";
0313 }
0314 std::cout << "-> " << name << std::endl;
0315 print_elements(child, level + 1);
0316 }
0317 }
0318
0319
0320 const DetElement* find_element(const DetElement& el, const std::string& el_name,
0321 unsigned int search_depth = 0) {
0322 static unsigned int level = 0;
0323 static bool abort_search = false;
0324 for (const auto& [name, child] : el.children()) {
0325 if (el_name == name) {
0326 abort_search = true;
0327 return &child;
0328 }
0329 if (++level <= search_depth) {
0330 auto el_child = find_element(child, el_name, search_depth);
0331 if (abort_search) {
0332 return el_child;
0333 }
0334 }
0335 }
0336 return nullptr;
0337 }
0338
0339
0340 std::vector<const Surface*> makeConstPtrVector(
0341 const std::vector<std::shared_ptr<Surface>>& surfs) {
0342 std::vector<const Surface*> constPtrs;
0343 constPtrs.reserve(surfs.size());
0344 for (const auto& surf : surfs) {
0345 constPtrs.push_back(surf.get());
0346 }
0347 return constPtrs;
0348 }
0349
0350
0351 struct LayerData {
0352 ProtoLayer protoLayer;
0353 std::vector<std::shared_ptr<Surface>> surfaces;
0354
0355 LayerData(const GeometryContext& gctx,
0356 std::vector<std::shared_ptr<Surface>> surfs)
0357 : protoLayer(gctx, makeConstPtrVector(surfs)),
0358 surfaces(std::move(surfs)) {}
0359 };
0360
0361
0362 std::vector<LayerData> mergeLayers(const GeometryContext& gctx,
0363 std::vector<LayerData> layers) {
0364 using enum AxisDirection;
0365
0366 std::vector<LayerData> mergedLayers;
0367 if (layers.empty()) {
0368 return mergedLayers;
0369 }
0370
0371 mergedLayers.push_back(std::move(layers.front()));
0372
0373 for (std::size_t i = 1; i < layers.size(); i++) {
0374 auto& current = layers[i];
0375 auto& prev = mergedLayers.back();
0376
0377
0378 bool overlap =
0379 (current.protoLayer.min(AxisZ) <= prev.protoLayer.max(AxisZ) &&
0380 current.protoLayer.max(AxisZ) >= prev.protoLayer.min(AxisZ));
0381
0382 if (overlap) {
0383
0384 std::vector<std::shared_ptr<Surface>> mergedSurfaces;
0385 mergedSurfaces.reserve(current.surfaces.size() + prev.surfaces.size());
0386 mergedSurfaces.insert(mergedSurfaces.end(), current.surfaces.begin(),
0387 current.surfaces.end());
0388 mergedSurfaces.insert(mergedSurfaces.end(), prev.surfaces.begin(),
0389 prev.surfaces.end());
0390
0391 mergedLayers.pop_back();
0392 mergedLayers.emplace_back(gctx, std::move(mergedSurfaces));
0393 auto& merged = mergedLayers.back();
0394 merged.protoLayer.envelope[AxisR] = current.protoLayer.envelope[AxisR];
0395 merged.protoLayer.envelope[AxisZ] = current.protoLayer.envelope[AxisZ];
0396 } else {
0397 mergedLayers.push_back(std::move(current));
0398 }
0399 }
0400
0401 return mergedLayers;
0402 }
0403
0404
0405
0406 BOOST_AUTO_TEST_SUITE(DD4hepPlugin)
0407
0408 BOOST_AUTO_TEST_CASE(DD4hepCylidricalDetectorExplicit) {
0409 TemporaryDirectory tempDir{};
0410 auto xmlPath = tempDir.path() / "CylindricalDetector.xml";
0411 generateXML(xmlPath);
0412
0413 auto lcdd = &(dd4hep::Detector::getInstance());
0414 lcdd->fromCompact(xmlPath.string());
0415 lcdd->volumeManager();
0416 lcdd->apply("DD4hepVolumeManager", 0, nullptr);
0417
0418 constexpr std::size_t s_beamPipeVolumeId =
0419 1;
0420 constexpr std::size_t s_pixelVolumeId = 10;
0421
0422 DetElement world = lcdd->world();
0423
0424
0425
0426
0427 auto worldSolidDim = lcdd->worldVolume().solid().dimensions();
0428
0429 Experimental::Blueprint::Config cfg;
0430
0431 cfg.envelope[AxisX] = {worldSolidDim[0], worldSolidDim[0]};
0432 cfg.envelope[AxisY] = {worldSolidDim[1], worldSolidDim[1]};
0433 cfg.envelope[AxisZ] = {worldSolidDim[2], worldSolidDim[2]};
0434
0435
0436 auto blueprint = std::make_unique<Experimental::Blueprint>(cfg);
0437 auto& cylinder = blueprint->addCylinderContainer("Detector", AxisR);
0438
0439
0440 auto level1_elements = world.children();
0441 DetElement bpipe_top = level1_elements["BeamPipe"];
0442 auto bpipe_top_position = bpipe_top.placement().position();
0443
0444 Transform3 beamPipeTransform;
0445 beamPipeTransform.setIdentity();
0446 beamPipeTransform = Translation3(
0447 bpipe_top_position.x(), bpipe_top_position.y(), bpipe_top_position.z());
0448
0449 auto beamPipeDim = bpipe_top.solid().dimensions();
0450
0451 double beamPipeRMax = beamPipeDim[1] * 1_cm;
0452 double beamPipeHalfZ = beamPipeDim[2] * 1_cm;
0453
0454 std::vector<std::shared_ptr<DD4hepDetectorElement>> detectorElements;
0455
0456 cylinder.withGeometryIdentifier([&](auto& geoId) {
0457 geoId.setAllVolumeIdsTo(s_beamPipeVolumeId);
0458 geoId.addMaterial("BeamPipe_Material", [&](auto& mat) {
0459 mat.configureFace(
0460 OuterCylinder,
0461 {AxisRPhi, Bound,
0462 20},
0463 {AxisZ, Bound, 20});
0464 mat.addStaticVolume(beamPipeTransform,
0465 std::make_shared<CylinderVolumeBounds>(
0466 0, beamPipeRMax, beamPipeHalfZ),
0467 "BeamPipe");
0468 });
0469 });
0470
0471
0472
0473 auto pixelElement = find_element(world, "Pixel");
0474 auto pixelBarrelElement = find_element(*pixelElement, "PixelBarrel");
0475
0476 cylinder.addMaterial("Pixel_Material", [&](auto& mat) {
0477 mat.configureFace(OuterCylinder, {AxisRPhi, Bound, 20}, {AxisZ, Bound, 20});
0478 auto& pixelContainer = mat.addCylinderContainer("Pixel", AxisZ);
0479
0480
0481 auto& barrelGeoId = pixelContainer.withGeometryIdentifier();
0482 barrelGeoId.setAllVolumeIdsTo(s_pixelVolumeId)
0483 .incrementLayerIds(1)
0484 .sortBy([](auto& a, auto& b) {
0485 auto& boundsA =
0486 dynamic_cast<const CylinderVolumeBounds&>(a.volumeBounds());
0487 auto& boundsB =
0488 dynamic_cast<const CylinderVolumeBounds&>(b.volumeBounds());
0489 using enum CylinderVolumeBounds::BoundValues;
0490 double aMidR = (boundsA.get(eMinR) + boundsA.get(eMaxR)) / 2.0;
0491 double bMidR = (boundsB.get(eMinR) + boundsB.get(eMaxR)) / 2.0;
0492 return aMidR < bMidR;
0493 });
0494
0495 auto& barrel = barrelGeoId.addCylinderContainer("Pixel_Barrel", AxisR);
0496 barrel.setAttachmentStrategy(AttachmentStrategy::Gap);
0497 barrel.setResizeStrategy(ResizeStrategy::Gap);
0498
0499 std::map<int, std::vector<std::shared_ptr<Surface>>> layers{};
0500 int layerId{0};
0501 for (const auto& [nameLayer, layer] : pixelBarrelElement->children()) {
0502 for (const auto& [nameModule, module] : layer.children()) {
0503 std::string detAxis =
0504 getParamOr<std::string>("axis_definitions", module, "XYZ");
0505 auto dd4hepDetEl = std::make_shared<DD4hepDetectorElement>(
0506 module, detAxis, 1_cm, false, nullptr);
0507 detectorElements.push_back(dd4hepDetEl);
0508 layers[layerId].push_back(dd4hepDetEl->surface().getSharedPtr());
0509 }
0510 layerId++;
0511 }
0512
0513 for (const auto& [ilayer, surfaces] : layers) {
0514 Experimental::BlueprintNode* lparent = nullptr;
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543 if (ilayer < static_cast<int>(layers.size() - 1)) {
0544 auto& lmat = barrel.addMaterial(
0545 std::format("Pixel_Barrel_L{}_Material", ilayer));
0546 lmat.configureFace(OuterCylinder, {AxisRPhi, Bound, 40},
0547 {AxisZ, Bound, 20});
0548 lparent = &lmat;
0549 } else {
0550 lparent = &barrel;
0551 }
0552
0553
0554 auto& layer = lparent->addLayer(std::format("Pixel_Barrel_L{}", ilayer));
0555
0556
0557 layer.setNavigationPolicyFactory(
0558 NavigationPolicyFactory{}
0559 .add<SurfaceArrayNavigationPolicy>(
0560 SurfaceArrayNavigationPolicy::Config{.layerType = Cylinder,
0561 .bins = {30, 10}})
0562 .add<TryAllNavigationPolicy>(
0563 TryAllNavigationPolicy::Config{.sensitives = false})
0564 .asUniquePtr());
0565
0566 layer.setSurfaces(surfaces);
0567 layer.setEnvelope(ExtentEnvelope{{
0568 .z = {5_mm, 5_mm},
0569 .r = {2_mm, 2_mm},
0570 }});
0571 }
0572
0573
0574 for (int ecid : {-1, 1}) {
0575 const std::string_view s = ecid == 1 ? "p" : "n";
0576 auto& ecGeoId = pixelContainer.withGeometryIdentifier();
0577 ecGeoId.setAllVolumeIdsTo(s_pixelVolumeId + ecid).incrementLayerIds(1);
0578 auto& ec =
0579 ecGeoId.addCylinderContainer(std::format("Pixel_{}EC", s), AxisZ);
0580 ec.setAttachmentStrategy(AttachmentStrategy::Gap);
0581 ec.setResizeStrategy(ResizeStrategy::Expand);
0582
0583 std::map<int, std::vector<std::shared_ptr<Surface>>> initialLayers{};
0584 const DetElement* pixelEndcapElement =
0585 ecid == 1 ? find_element(*pixelElement, "PixelPositiveEndcap")
0586 : find_element(*pixelElement, "PixelNegativeEndcap");
0587 layerId = 0;
0588 for (const auto& [nameLayer, layer] : pixelEndcapElement->children()) {
0589 for (const auto& [nameModule, module] : layer.children()) {
0590 std::string detAxis =
0591 getParamOr<std::string>("axis_definitions", module, "XYZ");
0592 auto dd4hepDetEl = std::make_shared<DD4hepDetectorElement>(
0593 module, detAxis, 1_cm, false, nullptr);
0594 detectorElements.push_back(dd4hepDetEl);
0595 initialLayers[layerId].push_back(
0596 dd4hepDetEl->surface().getSharedPtr());
0597 }
0598 layerId++;
0599 }
0600
0601
0602 std::vector<LayerData> protoLayers;
0603 protoLayers.reserve(initialLayers.size());
0604 for (const auto& [key, surfaces] : initialLayers) {
0605 auto& layer = protoLayers.emplace_back(GeometryContext(), surfaces);
0606 layer.protoLayer.envelope[AxisR] = {2_mm, 2_mm};
0607 layer.protoLayer.envelope[AxisZ] = {1_mm, 1_mm};
0608 }
0609
0610 std::ranges::sort(protoLayers,
0611 [](const LayerData& a, const LayerData& b) {
0612 return std::abs(a.protoLayer.medium(AxisZ)) <
0613 std::abs(b.protoLayer.medium(AxisZ));
0614 });
0615
0616 std::vector<LayerData> mergedLayers =
0617 mergeLayers(GeometryContext(), protoLayers);
0618
0619
0620 for (const auto& [key, pl] : enumerate(mergedLayers)) {
0621 pl.protoLayer.medium(AxisZ);
0622 auto layerName = std::format("Pixel_{}EC_L{}", s, key);
0623 auto addLayer = [&layerName, &pl](auto& parent) {
0624
0625 auto& layer = parent.addLayer(layerName);
0626
0627 layer.setNavigationPolicyFactory(
0628 NavigationPolicyFactory{}
0629 .add<SurfaceArrayNavigationPolicy>(
0630 SurfaceArrayNavigationPolicy::Config{.layerType = Disc,
0631 .bins = {30, 30}})
0632 .add<TryAllNavigationPolicy>(
0633 TryAllNavigationPolicy::Config{.sensitives = false})
0634 .asUniquePtr());
0635
0636 layer.setSurfaces(pl.surfaces);
0637 layer.setEnvelope(ExtentEnvelope{{
0638 .z = {1_mm, 1_mm},
0639 .r = {2_mm, 2_mm},
0640 }});
0641 };
0642
0643 if (key < mergedLayers.size() - 1) {
0644 ec.addMaterial(layerName + "_Material", [&](auto& lmat) {
0645 lmat.configureFace(ecid < 0 ? NegativeDisc : PositiveDisc,
0646 {AxisR, Bound, 40}, {AxisPhi, Bound, 40});
0647 addLayer(lmat);
0648 });
0649 } else {
0650 addLayer(ec);
0651 }
0652 }
0653 }
0654 });
0655
0656
0657 std::cout << tempDir.path() << std::endl;
0658 std::ofstream dotOut{tempDir.path() / "CylindricalDetector.dot"};
0659 blueprint->graphviz(dotOut);
0660
0661
0662 GeometryContext gctx;
0663 auto logger = getDefaultLogger("Geo", Logging::VERBOSE);
0664 auto trackingGeometry = blueprint->construct({}, gctx, *logger);
0665
0666 BOOST_REQUIRE_NE(&world, nullptr);
0667 BOOST_REQUIRE_NE(trackingGeometry.get(), nullptr);
0668
0669
0670 lcdd->destroyInstance();
0671 }
0672
0673 BOOST_AUTO_TEST_SUITE_END()
0674
0675 }