274 const Acts::GeometryContext& gctx,
275 Acts::BlueprintNode&
node) {
280 throw std::runtime_error(
"ITkPixel manager not available");
287 std::vector<std::shared_ptr<ActsDetectorElement>> elements;
290 for (
const auto* element : *
m_itkPixelMgr->getDetectorElementCollection()) {
293 if (siDetElement ==
nullptr) {
295 throw std::runtime_error{
"Corrupt detector element collection"};
297 elements.push_back(std::make_shared<ActsDetectorElement>(*siDetElement));
303 elements.begin(), elements.end());
306 auto& innerPixel =
node.addCylinderContainer(
"InnerPixel", AxisR);
307 innerPixel.setAttachmentStrategy(AttachmentStrategy::Gap);
313 innerPixel.setResizeStrategies(ResizeStrategy::Expand, ResizeStrategy::Gap);
315 innerPixel.addMaterial(
"InnerPixelMaterial", [&](
auto& mat) {
316 mat.configureFace(OuterCylinder,
317 AxisSpec::DeferredEquidistant(50, AxisRPhi),
318 AxisSpec::DeferredEquidistant(100, AxisZ),
319 "InnerPixelMaterial");
321 auto& innerPixelContainer = mat.addCylinderContainer(
"InnerPixel", AxisZ);
324 auto& barrelGeoId = innerPixelContainer.withGeometryIdentifier();
326 .incrementLayerIds(1)
327 .sortBy([](
auto&
a,
auto& b) {
329 dynamic_cast<const Acts::CylinderVolumeBounds&
>(
a.volumeBounds());
331 dynamic_cast<const Acts::CylinderVolumeBounds&
>(b.volumeBounds());
333 using enum Acts::CylinderVolumeBounds::BoundValues;
334 double aMidR = (boundsA.get(eMinR) + boundsA.get(eMaxR)) / 2.0;
335 double bMidR = (boundsB.get(eMinR) + boundsB.get(eMaxR)) / 2.0;
337 return aMidR < bMidR;
341 barrelGeoId.addMaterial(
"InnerPixel_Material", [&](
auto& material) {
342 material.configureFace(NegativeDisc,
343 AxisSpec::DeferredEquidistant(50, AxisR),
344 AxisSpec::DeferredEquidistant(50, AxisPhi),
345 "InnerPixel_Material_NegativeDisc");
346 material.configureFace(PositiveDisc,
347 AxisSpec::DeferredEquidistant(50, AxisR),
348 AxisSpec::DeferredEquidistant(50, AxisPhi),
349 "InnerPixel_Material_PositiveDisc");
351 auto&
barrel = brl_mat.addCylinderContainer(
"InnerPixel_Brl", AxisR);
357 barrel.setAttachmentStrategy(AttachmentStrategy::Second);
367 barrel.setResizeStrategies(ResizeStrategy::Expand, ResizeStrategy::Expand);
369 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
371 for (
auto& element : elements) {
377 if (
id.layer_disk() >= 2) {
382 layers[elementLayer].push_back(element->surface().getSharedPtr());
385 ATH_MSG_DEBUG(
"Adding " << layers.size() <<
" layers to InnerPixel barrel");
387 const int outermostBrlLayer = layers.rbegin()->first;
388 for (
const auto& [ilayer, surfaces] : layers) {
389 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
392 auto configureLayer = [&](
auto&
node) {
393 auto& layer =
node.addLayer(std::format(
"InnerPixel_Brl_{}", ilayer));
394 layer.setNavigationPolicyFactory(
395 Acts::NavigationPolicyFactory{}
396 .add<Acts::SurfaceArrayNavigationPolicy>(
397 Acts::SurfaceArrayNavigationPolicy::Config{
398 .layerType = Cylinder,
399 .bins = {0, 0}, .numberOfBinsFactor = 5.0})
400 .add<Acts::CylinderNavigationPolicy>()
402 layer.setSurfaces(surfaces);
403 layer.setEnvelope(Acts::ExtentEnvelope{{
412 if (ilayer != outermostBrlLayer) {
413 const std::string materialName =
414 std::format(
"InnerPixel_Brl_{}_Material", ilayer);
418 lmat.configureFace(OuterCylinder,
419 AxisSpec::DeferredEquidistant(50, AxisRPhi),
420 AxisSpec::DeferredEquidistant(100, AxisZ),
422 configureLayer(lmat);
430 for (
int bec : {-2, 2}) {
431 std::string s = bec > 0 ?
"p" :
"n";
432 auto& ecGeoId = innerPixelContainer.withGeometryIdentifier();
434 .incrementLayerIds(1);
435 auto& ec = ecGeoId.addCylinderContainer(std::format(
"InnerPixel_{:}EC", s), AxisZ);
440 ec.setAttachmentStrategy(bec > 0 ? AttachmentStrategy::Second
441 : AttachmentStrategy::First);
448 ec.setResizeStrategies(
449 bec > 0 ? ResizeStrategy::Expand : ResizeStrategy::Gap,
450 bec > 0 ? ResizeStrategy::Gap : ResizeStrategy::Expand);
452 std::map<std::tuple<int, int, int>,
453 std::vector<std::shared_ptr<Acts::Surface>>>
456 for (
auto& element : elements) {
458 if (
id.bec() * bec <= 0) {
462 if (
id.layer_disk() >= 3) {
466 std::tuple<int, int, int> key{
id.bec(),
id.layer_disk(),
468 initialLayers[key].push_back(element->surface().getSharedPtr());
472 <<
" initial layers to InnerPixel " << s <<
"EC");
474 std::vector<LayerData> protoLayers;
475 protoLayers.reserve(initialLayers.size());
477 for (
const auto& [key, surfaces] : initialLayers) {
478 auto& layer = protoLayers.emplace_back(gctx, surfaces);
479 layer.protoLayer.envelope[AxisR] = {2_mm, 2_mm};
480 layer.protoLayer.envelope[AxisZ] = {1_mm, 1_mm};
483 std::ranges::sort(protoLayers,
484 [](
const LayerData&
a,
const LayerData& b) {
485 return std::abs(
a.protoLayer.medium(AxisZ)) <
486 std::abs(b.protoLayer.medium(AxisZ));
489 ATH_MSG_DEBUG(
"Found " << protoLayers.size() <<
" initial layers");
491 std::vector<LayerData> mergedLayers;
493 mergedLayers = mergeLayers(gctx, std::move(protoLayers));
495 mergedLayers = std::move(protoLayers);
498 ATH_MSG_DEBUG(
"After merging: " << mergedLayers.size() <<
" layers");
500 for (
const auto [key, pl] : Acts::enumerate(mergedLayers)) {
501 ATH_MSG_DEBUG(
"- Layer " << key <<
" has " << pl.surfaces.size()
504 pl.protoLayer.medium(AxisZ);
505 auto layerName = std::format(
"InnerPixel_{}EC_{}", key, s);
507 auto addLayer = [&layerName, &pl](
auto& parent) {
508 auto& layer = parent.addLayer(layerName);
510 layer.setNavigationPolicyFactory(
511 Acts::NavigationPolicyFactory{}
512 .add<Acts::SurfaceArrayNavigationPolicy>(
513 Acts::SurfaceArrayNavigationPolicy::Config{
515 .bins = {0, 0}, .numberOfBinsFactor = 5.0})
516 .add<Acts::CylinderNavigationPolicy>()
519 layer.setSurfaces(pl.surfaces);
520 layer.setEnvelope(Acts::ExtentEnvelope{{
527 << key <<
" / " << mergedLayers.size()
528 <<
" at z = " << pl.protoLayer.medium(AxisZ));
536 const auto outwardDisc = (bec > 0) ? PositiveDisc : NegativeDisc;
537 const std::string materialName = layerName +
"_Material";
538 ec.addMaterial(materialName, [&](
auto& lmat) {
539 lmat.configureFace(outwardDisc,
540 AxisSpec::DeferredEquidistant(50, AxisR),
541 AxisSpec::DeferredEquidistant(50, AxisPhi),
550 auto& outerPixel =
node.addCylinderContainer(
"OuterPixel", AxisR);
551 outerPixel.setAttachmentStrategy(AttachmentStrategy::Gap);
557 outerPixel.setResizeStrategies(ResizeStrategy::Expand, ResizeStrategy::Gap);
559 outerPixel.addMaterial(
"OuterPixelMaterial", [&](
auto& opmat) {
560 opmat.configureFace(OuterCylinder,
561 AxisSpec::DeferredEquidistant(50, AxisRPhi),
562 AxisSpec::DeferredEquidistant(100, AxisZ),
563 "OuterPixelMaterial");
565 auto& outerPixelContainer = opmat.addCylinderContainer(
"OuterPixel", AxisZ);
567 auto& barrelGeoId = outerPixelContainer.withGeometryIdentifier();
571 barrelGeoId.addMaterial(
"OuterPixel_Material", [&](
auto& bmat) {
572 bmat.configureFace(NegativeDisc,
573 AxisSpec::DeferredEquidistant(50, AxisR),
574 AxisSpec::DeferredEquidistant(50, AxisPhi),
575 "OuterPixel_Material_NegativeDisc");
576 bmat.configureFace(PositiveDisc,
577 AxisSpec::DeferredEquidistant(50, AxisR),
578 AxisSpec::DeferredEquidistant(50, AxisPhi),
579 "OuterPixel_Material_PositiveDisc");
581 auto&
barrel = brl_mat.addCylinderContainer(
"OuterPixel_Brl", AxisR);
586 barrel.setAttachmentStrategy(AttachmentStrategy::Second);
594 barrel.setResizeStrategies(ResizeStrategy::Expand, ResizeStrategy::Expand);
596 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
598 for (
auto& element : elements) {
604 if (
id.layer_disk() <= 1) {
609 layers[elementLayer].push_back(element->surface().getSharedPtr());
612 ATH_MSG_DEBUG(
"Adding " << layers.size() <<
" layers to OuterPixel barrel");
614 const int outermostBrlLayer = layers.rbegin()->first;
615 for (
const auto& [ilayer, surfaces] : layers) {
616 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
619 auto configureLayer = [&](
auto&
node) {
620 auto& layer =
node.addLayer(std::format(
"OuterPixel_Brl_{:}", ilayer));
621 layer.setNavigationPolicyFactory(
622 Acts::NavigationPolicyFactory{}
623 .add<Acts::SurfaceArrayNavigationPolicy>(
624 Acts::SurfaceArrayNavigationPolicy::Config{
625 .layerType = Cylinder,
626 .bins = {0, 0}, .numberOfBinsFactor = 5.0})
627 .add<Acts::CylinderNavigationPolicy>()
629 layer.setSurfaces(surfaces);
630 layer.setEnvelope(Acts::ExtentEnvelope{{
639 if (ilayer != outermostBrlLayer) {
640 const std::string materialName =
641 std::format(
"OuterPixel_Brl_{}_Material", ilayer);
645 lmat.configureFace(OuterCylinder,
646 AxisSpec::DeferredEquidistant(50, AxisRPhi),
647 AxisSpec::DeferredEquidistant(100, AxisZ),
649 configureLayer(lmat);
656 constexpr static auto addEndcapLayer = [](
auto& parent,
const auto& name,
657 const auto& surfaces) {
658 parent.addLayer(name, [&surfaces](
auto& layer) {
659 layer.setNavigationPolicyFactory(
660 Acts::NavigationPolicyFactory{}
661 .add<Acts::SurfaceArrayNavigationPolicy>(
662 Acts::SurfaceArrayNavigationPolicy::Config{
663 .layerType = Disc, .bins = {0, 0}, .numberOfBinsFactor = 5.0})
664 .add<Acts::CylinderNavigationPolicy>()
667 layer.setSurfaces(surfaces);
671 for (
int bec : {-2, 2}) {
672 const std::string s = bec > 0 ?
"p" :
"n";
674 auto& ec_outer_geoId = outerPixelContainer.withGeometryIdentifier();
677 .incrementLayerIds(1);
680 ec_outer_geoId.addCylinderContainer(std::format(
"OuterPixel_{:}EC", s), AxisR);
683 std::array diskGroups{std::pair{3, 4}, std::pair{6, 5}, std::pair{7, 8}};
685 for (
size_t idx = 0; idx < diskGroups.size(); ++idx) {
686 auto [disk1, disk2] = diskGroups[idx];
688 Acts::MaterialDesignatorBlueprintNode* material =
nullptr;
689 if (idx < (diskGroups.size() - 1)) {
690 const std::string materialName =
691 "OuterPixel_" + s +
"EC_" + std::to_string(idx) +
"_Material";
692 material = &ec_outer.addMaterial(
695 mat.configureFace(OuterCylinder,
696 AxisSpec::DeferredEquidistant(50, AxisRPhi),
697 AxisSpec::DeferredEquidistant(100, AxisZ),
704 ? material->addCylinderContainer(
705 std::format(
"OuterPixel_{:}EC_{:}", s, idx), AxisZ)
706 : ec_outer.addCylinderContainer(
707 std::format(
"OuterPixel_{:}EC_{:}", s, idx), AxisZ);
712 ec_stack.setAttachmentStrategy(bec > 0 ? AttachmentStrategy::Second
713 : AttachmentStrategy::First);
718 ec_stack.setResizeStrategies(
719 bec > 0 ? ResizeStrategy::Expand : ResizeStrategy::Gap,
720 bec > 0 ? ResizeStrategy::Gap : ResizeStrategy::Expand);
722 std::map<std::tuple<int, int>,
723 std::vector<std::shared_ptr<Acts::Surface>>>
726 for (
auto& element : elements) {
728 if (
id.bec() != bec ||
729 (
id.layer_disk() != disk1 &&
id.layer_disk() != disk2)) {
732 std::tuple<int, int> key{
id.layer_disk(),
id.eta_module()};
733 eta_rings[key].push_back(element->surface().getSharedPtr());
736 ATH_MSG_DEBUG(
"Found " << eta_rings.size() <<
" eta rings in group "
739 std::vector<std::vector<std::shared_ptr<Acts::Surface>>> sorted_rings;
740 sorted_rings.reserve(eta_rings.size());
741 for (
const auto& [key, surfaces] : eta_rings) {
742 sorted_rings.push_back(surfaces);
745 std::ranges::sort(sorted_rings, [&gctx](
const auto&
a,
const auto& b) {
746 Acts::ProtoLayer pl_a(gctx, Acts::unpackConstSmartPointers(
a));
747 Acts::ProtoLayer pl_b(gctx, Acts::unpackConstSmartPointers(b));
748 return std::abs(pl_a.min(AxisZ)) < std::abs(pl_b.min(AxisZ));
751 for (
size_t i = 0; i < sorted_rings.size(); ++i) {
752 const auto& surfaces = sorted_rings[i];
753 const std::string layerName = std::format(
"OuterPixel_{:}EC_{:}_{:}", s,idx, i);
755 const auto outwardDisc = (bec > 0) ? PositiveDisc : NegativeDisc;
756 const std::string materialName = layerName +
"_Material";
757 ec_stack.addMaterial(materialName, [&](
auto& mat) {
758 mat.configureFace(outwardDisc,
759 AxisSpec::DeferredEquidistant(50, AxisR),
760 AxisSpec::DeferredEquidistant(50, AxisPhi),
762 addEndcapLayer(mat, layerName, surfaces);
771 const Acts::GeometryContext& gctx,
772 Acts::BlueprintNode&
node) {
777 throw std::runtime_error(
"ITkStrip manager not available");
784 std::vector<std::shared_ptr<ActsDetectorElement>> elements;
787 for (
const auto* element : *
m_itkStripMgr->getDetectorElementCollection()) {
790 if (siDetElement ==
nullptr) {
792 throw std::runtime_error{
"Corrupt detector element collection"};
794 elements.push_back(std::make_shared<ActsDetectorElement>(*siDetElement));
800 elements.begin(), elements.end());
802 auto&
strip =
node.addCylinderContainer(
"Strip", AxisR);
803 strip.setAttachmentStrategy(AttachmentStrategy::Gap);
810 strip.setResizeStrategies(ResizeStrategy::Expand, ResizeStrategy::Gap);
812 strip.addMaterial(
"StripMaterial", [&](
auto& mat) {
813 mat.configureFace(OuterCylinder,
814 AxisSpec::DeferredEquidistant(50, AxisRPhi),
815 AxisSpec::DeferredEquidistant(100, AxisZ),
818 auto& stripContainer = mat.addCylinderContainer(
"Strip", AxisZ);
821 stripContainer.withGeometryIdentifier([
this, &elements](
auto& geoId) {
825 geoId.addMaterial(
"Strip_Brl_Material", [&](
auto& material) {
826 material.configureFace(NegativeDisc,
827 AxisSpec::DeferredEquidistant(50, AxisR),
828 AxisSpec::DeferredEquidistant(50, AxisPhi),
829 "Strip_Brl_Material_NegativeDisc");
830 material.configureFace(PositiveDisc,
831 AxisSpec::DeferredEquidistant(50, AxisR),
832 AxisSpec::DeferredEquidistant(50, AxisPhi),
833 "Strip_Brl_Material_PositiveDisc");
835 brl_mat.addCylinderContainer(
836 "Strip_Brl", AxisR, [
this, &elements](
auto&
barrel) {
840 barrel.setAttachmentStrategy(AttachmentStrategy::Second);
847 barrel.setResizeStrategies(ResizeStrategy::Expand,
848 ResizeStrategy::Gap);
850 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
852 for (
auto& element : elements) {
859 layers[elementLayer].push_back(element->surface().getSharedPtr());
863 <<
" layers to Strip barrel");
865 for (
const auto& [ilayer, surfaces] : layers) {
866 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
868 addStripBarrelLayer(
barrel, ilayer, surfaces);
874 for (
int bec : {-2, 2}) {
875 const std::string s = bec > 0 ?
"p" :
"n";
877 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
879 for (
auto& element : elements) {
881 if (
id.bec() * bec <= 0) {
885 layers[
id.layer_disk()].push_back(element->surface().getSharedPtr());
888 ATH_MSG_DEBUG(
"Found " << layers.size() <<
" layers in Strip " << s
891 std::vector<std::vector<std::shared_ptr<Acts::Surface>>> sorted_layers;
892 sorted_layers.reserve(layers.size());
893 for (
const auto& [key, surfaces] : layers) {
894 sorted_layers.push_back(surfaces);
897 std::sort(sorted_layers.begin(), sorted_layers.end(),
898 [&gctx](
const auto&
a,
const auto& b) {
899 Acts::ProtoLayer pl_a(gctx, Acts::unpackConstSmartPointers(a));
900 Acts::ProtoLayer pl_b(gctx, Acts::unpackConstSmartPointers(b));
901 return std::abs(pl_a.min(AxisZ)) < std::abs(pl_b.min(AxisZ));
904 stripContainer.withGeometryIdentifier([&sorted_layers, bec,
907 .incrementLayerIds(1);
909 geoId.addCylinderContainer(
910 std::format(
"Strip_{:}_EC", s), AxisZ, [&sorted_layers, &s, bec](
auto& ec) {
913 ec.setAttachmentStrategy(bec > 0 ? AttachmentStrategy::Second
914 : AttachmentStrategy::First);
919 ec.setResizeStrategies(
920 bec > 0 ? ResizeStrategy::Expand : ResizeStrategy::Gap,
921 bec > 0 ? ResizeStrategy::Gap : ResizeStrategy::Expand);
923 for (
size_t i = 0; i < sorted_layers.size(); ++i) {
924 const auto& surfaces = sorted_layers[i];
925 auto layerName = std::format(
"Strip_{:}EC_{:}", s, i);
926 addStripEndcapLayer(ec, layerName, surfaces, bec);
936 std::vector<std::shared_ptr<Acts::Surface>> allStripSurfaces;
937 allStripSurfaces.reserve(elements.size());
938 for (
auto& element : elements) {
939 allStripSurfaces.push_back(element->surface().getSharedPtr());
941 Acts::ProtoLayer stripExtent(gctx, Acts::unpackConstSmartPointers(allStripSurfaces));
943 constexpr double spacerClearance = 5_mm;
944 constexpr double spacerThickness = 5_mm;
945 double spacerRmin = stripExtent.max(AxisR) + spacerClearance;
946 double spacerHalfZ = std::max(std::abs(stripExtent.min(AxisZ)),
947 std::abs(stripExtent.max(AxisZ))) +
950 strip.addStaticVolume(
951 Acts::Transform3::Identity(),
952 std::make_shared<Acts::CylinderVolumeBounds>(
953 spacerRmin, spacerRmin + spacerThickness, spacerHalfZ),
954 "Strip_OuterSpacer");