273 const Acts::GeometryContext& gctx,
274 Acts::BlueprintNode&
node) {
279 throw std::runtime_error(
"ITkPixel manager not available");
286 std::vector<std::shared_ptr<ActsDetectorElement>> elements;
289 for (
const auto* element : *
m_itkPixelMgr->getDetectorElementCollection()) {
292 if (siDetElement ==
nullptr) {
294 throw std::runtime_error{
"Corrupt detector element collection"};
296 elements.push_back(std::make_shared<ActsDetectorElement>(*siDetElement));
302 elements.begin(), elements.end());
305 auto& innerPixel =
node.addCylinderContainer(
"InnerPixel", AxisR);
306 innerPixel.setAttachmentStrategy(AttachmentStrategy::Gap);
312 innerPixel.setResizeStrategies(ResizeStrategy::Expand, ResizeStrategy::Gap);
314 innerPixel.addMaterial(
"InnerPixelMaterial", [&](
auto& mat) {
315 mat.configureFace(OuterCylinder,
316 AxisSpec::DeferredEquidistant(50, AxisRPhi),
317 AxisSpec::DeferredEquidistant(100, AxisZ));
319 auto& innerPixelContainer = mat.addCylinderContainer(
"InnerPixel", AxisZ);
322 auto& barrelGeoId = innerPixelContainer.withGeometryIdentifier();
324 .incrementLayerIds(1)
325 .sortBy([](
auto&
a,
auto& b) {
327 dynamic_cast<const Acts::CylinderVolumeBounds&
>(
a.volumeBounds());
329 dynamic_cast<const Acts::CylinderVolumeBounds&
>(b.volumeBounds());
331 using enum Acts::CylinderVolumeBounds::BoundValues;
332 double aMidR = (boundsA.get(eMinR) + boundsA.get(eMaxR)) / 2.0;
333 double bMidR = (boundsB.get(eMinR) + boundsB.get(eMaxR)) / 2.0;
335 return aMidR < bMidR;
339 barrelGeoId.addMaterial(
"InnerPixel_Material", [&](
auto& material) {
340 material.configureFace(NegativeDisc,
341 AxisSpec::DeferredEquidistant(50, AxisR),
342 AxisSpec::DeferredEquidistant(50, AxisPhi));
343 material.configureFace(PositiveDisc,
344 AxisSpec::DeferredEquidistant(50, AxisR),
345 AxisSpec::DeferredEquidistant(50, AxisPhi));
347 auto&
barrel = brl_mat.addCylinderContainer(
"InnerPixel_Brl", AxisR);
353 barrel.setAttachmentStrategy(AttachmentStrategy::Second);
363 barrel.setResizeStrategies(ResizeStrategy::Expand, ResizeStrategy::Expand);
365 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
367 for (
auto& element : elements) {
373 if (
id.layer_disk() >= 2) {
378 layers[elementLayer].push_back(element->surface().getSharedPtr());
381 ATH_MSG_DEBUG(
"Adding " << layers.size() <<
" layers to InnerPixel barrel");
383 const int outermostBrlLayer = layers.rbegin()->first;
384 for (
const auto& [ilayer, surfaces] : layers) {
385 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
388 auto configureLayer = [&](
auto&
node) {
389 auto& layer =
node.addLayer(std::format(
"InnerPixel_Brl_{}", ilayer));
390 layer.setNavigationPolicyFactory(
391 Acts::NavigationPolicyFactory{}
392 .add<Acts::SurfaceArrayNavigationPolicy>(
393 Acts::SurfaceArrayNavigationPolicy::Config{
394 .layerType = Cylinder,
395 .bins = {0, 0}, .numberOfBinsFactor = 5.0})
396 .add<Acts::CylinderNavigationPolicy>()
398 layer.setSurfaces(surfaces);
399 layer.setEnvelope(Acts::ExtentEnvelope{{
408 if (ilayer != outermostBrlLayer) {
410 std::format(
"InnerPixel_Brl_{}_Material", ilayer),
412 lmat.configureFace(OuterCylinder,
413 AxisSpec::DeferredEquidistant(50, AxisRPhi),
414 AxisSpec::DeferredEquidistant(100, AxisZ));
415 configureLayer(lmat);
423 for (
int bec : {-2, 2}) {
424 std::string s = bec > 0 ?
"p" :
"n";
425 auto& ecGeoId = innerPixelContainer.withGeometryIdentifier();
427 .incrementLayerIds(1);
428 auto& ec = ecGeoId.addCylinderContainer(
"InnerPixel_" + s +
"EC", AxisZ);
433 ec.setAttachmentStrategy(bec > 0 ? AttachmentStrategy::Second
434 : AttachmentStrategy::First);
441 ec.setResizeStrategies(
442 bec > 0 ? ResizeStrategy::Expand : ResizeStrategy::Gap,
443 bec > 0 ? ResizeStrategy::Gap : ResizeStrategy::Expand);
445 std::map<std::tuple<int, int, int>,
446 std::vector<std::shared_ptr<Acts::Surface>>>
449 for (
auto& element : elements) {
451 if (
id.bec() * bec <= 0) {
455 if (
id.layer_disk() >= 3) {
459 std::tuple<int, int, int> key{
id.bec(),
id.layer_disk(),
461 initialLayers[key].push_back(element->surface().getSharedPtr());
465 <<
" initial layers to InnerPixel " << s <<
"EC");
467 std::vector<LayerData> protoLayers;
468 protoLayers.reserve(initialLayers.size());
470 for (
const auto& [key, surfaces] : initialLayers) {
471 auto& layer = protoLayers.emplace_back(gctx, surfaces);
472 layer.protoLayer.envelope[AxisR] = {2_mm, 2_mm};
473 layer.protoLayer.envelope[AxisZ] = {1_mm, 1_mm};
476 std::ranges::sort(protoLayers,
477 [](
const LayerData&
a,
const LayerData& b) {
478 return std::abs(
a.protoLayer.medium(AxisZ)) <
479 std::abs(b.protoLayer.medium(AxisZ));
482 ATH_MSG_DEBUG(
"Found " << protoLayers.size() <<
" initial layers");
484 std::vector<LayerData> mergedLayers;
486 mergedLayers = mergeLayers(gctx, std::move(protoLayers));
488 mergedLayers = std::move(protoLayers);
491 ATH_MSG_DEBUG(
"After merging: " << mergedLayers.size() <<
" layers");
493 for (
const auto [key, pl] : Acts::enumerate(mergedLayers)) {
494 ATH_MSG_DEBUG(
"- Layer " << key <<
" has " << pl.surfaces.size()
497 pl.protoLayer.medium(AxisZ);
498 auto layerName = std::format(
"InnerPixel_{}EC_{}", key, s);
500 auto addLayer = [&layerName, &pl](
auto& parent) {
501 auto& layer = parent.addLayer(layerName);
503 layer.setNavigationPolicyFactory(
504 Acts::NavigationPolicyFactory{}
505 .add<Acts::SurfaceArrayNavigationPolicy>(
506 Acts::SurfaceArrayNavigationPolicy::Config{
508 .bins = {0, 0}, .numberOfBinsFactor = 5.0})
509 .add<Acts::CylinderNavigationPolicy>()
512 layer.setSurfaces(pl.surfaces);
513 layer.setEnvelope(Acts::ExtentEnvelope{{
520 << key <<
" / " << mergedLayers.size()
521 <<
" at z = " << pl.protoLayer.medium(AxisZ));
529 const auto outwardDisc = (bec > 0) ? PositiveDisc : NegativeDisc;
530 ec.addMaterial(layerName +
"_Material", [&](
auto& lmat) {
531 lmat.configureFace(outwardDisc,
532 AxisSpec::DeferredEquidistant(50, AxisR),
533 AxisSpec::DeferredEquidistant(50, AxisPhi));
541 auto& outerPixel =
node.addCylinderContainer(
"OuterPixel", AxisR);
542 outerPixel.setAttachmentStrategy(AttachmentStrategy::Gap);
548 outerPixel.setResizeStrategies(ResizeStrategy::Expand, ResizeStrategy::Gap);
550 outerPixel.addMaterial(
"OuterPixelMaterial", [&](
auto& opmat) {
551 opmat.configureFace(OuterCylinder,
552 AxisSpec::DeferredEquidistant(50, AxisRPhi),
553 AxisSpec::DeferredEquidistant(100, AxisZ));
555 auto& outerPixelContainer = opmat.addCylinderContainer(
"OuterPixel", AxisZ);
557 auto& barrelGeoId = outerPixelContainer.withGeometryIdentifier();
561 barrelGeoId.addMaterial(
"OuterPixel_Material", [&](
auto& bmat) {
562 bmat.configureFace(NegativeDisc,
563 AxisSpec::DeferredEquidistant(50, AxisR),
564 AxisSpec::DeferredEquidistant(50, AxisPhi));
565 bmat.configureFace(PositiveDisc,
566 AxisSpec::DeferredEquidistant(50, AxisR),
567 AxisSpec::DeferredEquidistant(50, AxisPhi));
569 auto&
barrel = brl_mat.addCylinderContainer(
"OuterPixel_Brl", AxisR);
574 barrel.setAttachmentStrategy(AttachmentStrategy::Second);
582 barrel.setResizeStrategies(ResizeStrategy::Expand, ResizeStrategy::Expand);
584 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
586 for (
auto& element : elements) {
592 if (
id.layer_disk() <= 1) {
597 layers[elementLayer].push_back(element->surface().getSharedPtr());
600 ATH_MSG_DEBUG(
"Adding " << layers.size() <<
" layers to OuterPixel barrel");
602 const int outermostBrlLayer = layers.rbegin()->first;
603 for (
const auto& [ilayer, surfaces] : layers) {
604 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
607 auto configureLayer = [&](
auto&
node) {
608 auto& layer =
node.addLayer(
"OuterPixel_Brl_" + std::to_string(ilayer));
609 layer.setNavigationPolicyFactory(
610 Acts::NavigationPolicyFactory{}
611 .add<Acts::SurfaceArrayNavigationPolicy>(
612 Acts::SurfaceArrayNavigationPolicy::Config{
613 .layerType = Cylinder,
614 .bins = {0, 0}, .numberOfBinsFactor = 5.0})
615 .add<Acts::CylinderNavigationPolicy>()
617 layer.setSurfaces(surfaces);
618 layer.setEnvelope(Acts::ExtentEnvelope{{
627 if (ilayer != outermostBrlLayer) {
629 std::format(
"OuterPixel_Brl_{}_Material", ilayer),
631 lmat.configureFace(OuterCylinder,
632 AxisSpec::DeferredEquidistant(50, AxisRPhi),
633 AxisSpec::DeferredEquidistant(100, AxisZ));
634 configureLayer(lmat);
641 constexpr static auto addEndcapLayer = [](
auto& parent,
const auto& name,
642 const auto& surfaces) {
643 parent.addLayer(name, [&surfaces](
auto& layer) {
644 layer.setNavigationPolicyFactory(
645 Acts::NavigationPolicyFactory{}
646 .add<Acts::SurfaceArrayNavigationPolicy>(
647 Acts::SurfaceArrayNavigationPolicy::Config{
648 .layerType = Disc, .bins = {0, 0}, .numberOfBinsFactor = 5.0})
649 .add<Acts::CylinderNavigationPolicy>()
652 layer.setSurfaces(surfaces);
656 for (
int bec : {-2, 2}) {
657 const std::string s = bec > 0 ?
"p" :
"n";
659 auto& ec_outer_geoId = outerPixelContainer.withGeometryIdentifier();
662 .incrementLayerIds(1);
665 ec_outer_geoId.addCylinderContainer(
"OuterPixel_" + s +
"EC", AxisR);
668 std::array diskGroups{std::pair{3, 4}, std::pair{6, 5}, std::pair{7, 8}};
670 for (
size_t idx = 0; idx < diskGroups.size(); ++idx) {
671 auto [disk1, disk2] = diskGroups[idx];
673 Acts::MaterialDesignatorBlueprintNode* material =
nullptr;
674 if (idx < (diskGroups.size() - 1)) {
675 material = &ec_outer.addMaterial(
676 "OuterPixel_" + s +
"EC_" + std::to_string(idx) +
"_Material",
678 mat.configureFace(OuterCylinder,
679 AxisSpec::DeferredEquidistant(50, AxisRPhi),
680 AxisSpec::DeferredEquidistant(100, AxisZ));
686 ? material->addCylinderContainer(
687 "OuterPixel_" + s +
"EC_" + std::to_string(idx), AxisZ)
688 : ec_outer.addCylinderContainer(
689 "OuterPixel_" + s +
"EC_" + std::to_string(idx), AxisZ);
694 ec_stack.setAttachmentStrategy(bec > 0 ? AttachmentStrategy::Second
695 : AttachmentStrategy::First);
700 ec_stack.setResizeStrategies(
701 bec > 0 ? ResizeStrategy::Expand : ResizeStrategy::Gap,
702 bec > 0 ? ResizeStrategy::Gap : ResizeStrategy::Expand);
704 std::map<std::tuple<int, int>,
705 std::vector<std::shared_ptr<Acts::Surface>>>
708 for (
auto& element : elements) {
710 if (
id.bec() != bec ||
711 (
id.layer_disk() != disk1 &&
id.layer_disk() != disk2)) {
714 std::tuple<int, int> key{
id.layer_disk(),
id.eta_module()};
715 eta_rings[key].push_back(element->surface().getSharedPtr());
718 ATH_MSG_DEBUG(
"Found " << eta_rings.size() <<
" eta rings in group "
721 std::vector<std::vector<std::shared_ptr<Acts::Surface>>> sorted_rings;
722 sorted_rings.reserve(eta_rings.size());
723 for (
const auto& [key, surfaces] : eta_rings) {
724 sorted_rings.push_back(surfaces);
727 std::ranges::sort(sorted_rings, [&gctx](
const auto&
a,
const auto& b) {
728 Acts::ProtoLayer pl_a(gctx, makeConstPtrVector(
a));
729 Acts::ProtoLayer pl_b(gctx, makeConstPtrVector(b));
730 return std::abs(pl_a.min(AxisZ)) < std::abs(pl_b.min(AxisZ));
733 for (
size_t i = 0; i < sorted_rings.size(); ++i) {
734 const auto& surfaces = sorted_rings[i];
735 auto layerName =
"OuterPixel_" + s +
"EC_" + std::to_string(idx) +
736 "_" + std::to_string(i);
738 const auto outwardDisc = (bec > 0) ? PositiveDisc : NegativeDisc;
739 ec_stack.addMaterial(layerName +
"_Material", [&](
auto& mat) {
740 mat.configureFace(outwardDisc,
741 AxisSpec::DeferredEquidistant(50, AxisR),
742 AxisSpec::DeferredEquidistant(50, AxisPhi));
743 addEndcapLayer(mat, layerName, surfaces);
752 const Acts::GeometryContext& gctx,
753 Acts::BlueprintNode&
node) {
758 throw std::runtime_error(
"ITkStrip manager not available");
765 std::vector<std::shared_ptr<ActsDetectorElement>> elements;
768 for (
const auto* element : *
m_itkStripMgr->getDetectorElementCollection()) {
771 if (siDetElement ==
nullptr) {
773 throw std::runtime_error{
"Corrupt detector element collection"};
775 elements.push_back(std::make_shared<ActsDetectorElement>(*siDetElement));
781 elements.begin(), elements.end());
783 auto&
strip =
node.addCylinderContainer(
"Strip", AxisR);
784 strip.setAttachmentStrategy(AttachmentStrategy::Gap);
791 strip.setResizeStrategies(ResizeStrategy::Expand, ResizeStrategy::Gap);
793 strip.addMaterial(
"StripMaterial", [&](
auto& mat) {
794 mat.configureFace(OuterCylinder,
795 AxisSpec::DeferredEquidistant(50, AxisRPhi),
796 AxisSpec::DeferredEquidistant(100, AxisZ));
798 auto& stripContainer = mat.addCylinderContainer(
"Strip", AxisZ);
801 stripContainer.withGeometryIdentifier([
this, &elements](
auto& geoId) {
805 geoId.addMaterial(
"Strip_Brl_Material", [&](
auto& material) {
806 material.configureFace(NegativeDisc,
807 AxisSpec::DeferredEquidistant(50, AxisR),
808 AxisSpec::DeferredEquidistant(50, AxisPhi));
809 material.configureFace(PositiveDisc,
810 AxisSpec::DeferredEquidistant(50, AxisR),
811 AxisSpec::DeferredEquidistant(50, AxisPhi));
813 brl_mat.addCylinderContainer(
814 "Strip_Brl", AxisR, [
this, &elements](
auto&
barrel) {
818 barrel.setAttachmentStrategy(AttachmentStrategy::Second);
825 barrel.setResizeStrategies(ResizeStrategy::Expand,
826 ResizeStrategy::Gap);
828 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
830 for (
auto& element : elements) {
837 layers[elementLayer].push_back(element->surface().getSharedPtr());
841 <<
" layers to Strip barrel");
843 for (
const auto& [ilayer, surfaces] : layers) {
844 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
846 addStripBarrelLayer(
barrel, ilayer, surfaces);
852 for (
int bec : {-2, 2}) {
853 const std::string s = bec > 0 ?
"p" :
"n";
855 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
857 for (
auto& element : elements) {
859 if (
id.bec() * bec <= 0) {
863 layers[
id.layer_disk()].push_back(element->surface().getSharedPtr());
866 ATH_MSG_DEBUG(
"Found " << layers.size() <<
" layers in Strip " << s
869 std::vector<std::vector<std::shared_ptr<Acts::Surface>>> sorted_layers;
870 sorted_layers.reserve(layers.size());
871 for (
const auto& [key, surfaces] : layers) {
872 sorted_layers.push_back(surfaces);
875 std::sort(sorted_layers.begin(), sorted_layers.end(),
876 [&gctx](
const auto&
a,
const auto& b) {
877 Acts::ProtoLayer pl_a(gctx, makeConstPtrVector(a));
878 Acts::ProtoLayer pl_b(gctx, makeConstPtrVector(b));
879 return std::abs(pl_a.min(AxisZ)) < std::abs(pl_b.min(AxisZ));
882 stripContainer.withGeometryIdentifier([&sorted_layers, bec,
885 .incrementLayerIds(1);
887 geoId.addCylinderContainer(
888 "Strip_" + s +
"EC", AxisZ, [&sorted_layers, &s, bec](
auto& ec) {
891 ec.setAttachmentStrategy(bec > 0 ? AttachmentStrategy::Second
892 : AttachmentStrategy::First);
897 ec.setResizeStrategies(
898 bec > 0 ? ResizeStrategy::Expand : ResizeStrategy::Gap,
899 bec > 0 ? ResizeStrategy::Gap : ResizeStrategy::Expand);
901 for (
size_t i = 0; i < sorted_layers.size(); ++i) {
902 const auto& surfaces = sorted_layers[i];
903 auto layerName =
"Strip_" + s +
"EC_" + std::to_string(i);
904 addStripEndcapLayer(ec, layerName, surfaces, bec);
914 std::vector<std::shared_ptr<Acts::Surface>> allStripSurfaces;
915 allStripSurfaces.reserve(elements.size());
916 for (
auto& element : elements) {
917 allStripSurfaces.push_back(element->surface().getSharedPtr());
919 Acts::ProtoLayer stripExtent(gctx, makeConstPtrVector(allStripSurfaces));
921 constexpr double spacerClearance = 5_mm;
922 constexpr double spacerThickness = 5_mm;
923 double spacerRmin = stripExtent.max(AxisR) + spacerClearance;
924 double spacerHalfZ = std::max(std::abs(stripExtent.min(AxisZ)),
925 std::abs(stripExtent.max(AxisZ))) +
928 strip.addStaticVolume(
929 Acts::Transform3::Identity(),
930 std::make_shared<Acts::CylinderVolumeBounds>(
931 spacerRmin, spacerRmin + spacerThickness, spacerHalfZ),
932 "Strip_OuterSpacer");