249 const Acts::GeometryContext& gctx,
250 Acts::BlueprintNode&
node) {
255 throw std::runtime_error(
"ITkPixel manager not available");
262 std::vector<std::shared_ptr<ActsDetectorElement>> elements;
265 for (
const auto* element : *
m_itkPixelMgr->getDetectorElementCollection()) {
268 if (siDetElement ==
nullptr) {
270 throw std::runtime_error{
"Corrupt detector element collection"};
272 elements.push_back(std::make_shared<ActsDetectorElement>(*siDetElement));
278 elements.begin(), elements.end());
281 auto& innerPixel =
node.addCylinderContainer(
"InnerPixel", AxisR);
282 innerPixel.setAttachmentStrategy(AttachmentStrategy::Gap);
283 innerPixel.setResizeStrategy(ResizeStrategy::Gap);
285 innerPixel.addMaterial(
"InnerPixelMaterial", [&](
auto& mat) {
286 mat.configureFace(OuterCylinder,
287 AxisSpec::DeferredEquidistant(20, AxisRPhi),
288 AxisSpec::DeferredEquidistant(20, AxisZ));
289 mat.configureFace(InnerCylinder,
290 AxisSpec::DeferredEquidistant(20, AxisRPhi),
291 AxisSpec::DeferredEquidistant(20, AxisZ));
293 auto& innerPixelContainer = mat.addCylinderContainer(
"InnerPixel", AxisZ);
296 auto& barrelGeoId = innerPixelContainer.withGeometryIdentifier();
298 .incrementLayerIds(1)
299 .sortBy([](
auto&
a,
auto& b) {
301 dynamic_cast<const Acts::CylinderVolumeBounds&
>(
a.volumeBounds());
303 dynamic_cast<const Acts::CylinderVolumeBounds&
>(b.volumeBounds());
305 using enum Acts::CylinderVolumeBounds::BoundValues;
306 double aMidR = (boundsA.get(eMinR) + boundsA.get(eMaxR)) / 2.0;
307 double bMidR = (boundsB.get(eMinR) + boundsB.get(eMaxR)) / 2.0;
309 return aMidR < bMidR;
313 barrelGeoId.addMaterial(
"InnerPixel_Material", [&](
auto& material) {
314 material.configureFace(NegativeDisc,
315 AxisSpec::DeferredEquidistant(10, AxisR),
316 AxisSpec::DeferredEquidistant(10, AxisPhi));
317 material.configureFace(PositiveDisc,
318 AxisSpec::DeferredEquidistant(10, AxisR),
319 AxisSpec::DeferredEquidistant(10, AxisPhi));
321 auto&
barrel = brl_mat.addCylinderContainer(
"InnerPixel_Brl", AxisR);
323 barrel.setAttachmentStrategy(AttachmentStrategy::Gap);
324 barrel.setResizeStrategy(ResizeStrategy::Gap);
326 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
328 for (
auto& element : elements) {
334 if (
id.layer_disk() >= 2) {
339 layers[elementLayer].push_back(element->surface().getSharedPtr());
342 ATH_MSG_DEBUG(
"Adding " << layers.size() <<
" layers to InnerPixel barrel");
344 for (
const auto& [ilayer, surfaces] : layers) {
345 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
349 std::format(
"InnerPixel_Brl_{}_Material", ilayer), [&](
auto& lmat) {
350 lmat.configureFace(OuterCylinder,
351 AxisSpec::DeferredEquidistant(40, AxisRPhi),
352 AxisSpec::DeferredEquidistant(20, AxisZ));
355 lmat.addLayer(std::format(
"InnerPixel_Brl_{}", ilayer));
357 layer.setNavigationPolicyFactory(
358 Acts::NavigationPolicyFactory{}
359 .add<Acts::SurfaceArrayNavigationPolicy>(
360 Acts::SurfaceArrayNavigationPolicy::Config{
361 .layerType = Cylinder,
363 .add<Acts::TryAllNavigationPolicy>(
364 Acts::TryAllNavigationPolicy::Config{.sensitives =
368 layer.setSurfaces(surfaces);
369 layer.setEnvelope(Acts::ExtentEnvelope{{
377 for (
int bec : {-2, 2}) {
378 std::string s = bec > 0 ?
"p" :
"n";
379 auto& ecGeoId = innerPixelContainer.withGeometryIdentifier();
381 .incrementLayerIds(1);
382 auto& ec = ecGeoId.addCylinderContainer(
"InnerPixel_" + s +
"EC", AxisZ);
383 ec.setAttachmentStrategy(AttachmentStrategy::Gap);
384 ec.setResizeStrategy(ResizeStrategy::Gap);
386 std::map<std::tuple<int, int, int>,
387 std::vector<std::shared_ptr<Acts::Surface>>>
390 for (
auto& element : elements) {
392 if (
id.bec() * bec <= 0) {
396 if (
id.layer_disk() >= 3) {
400 std::tuple<int, int, int> key{
id.bec(),
id.layer_disk(),
402 initialLayers[key].push_back(element->surface().getSharedPtr());
406 <<
" initial layers to InnerPixel " << s <<
"EC");
408 std::vector<LayerData> protoLayers;
409 protoLayers.reserve(initialLayers.size());
411 for (
const auto& [key, surfaces] : initialLayers) {
412 auto& layer = protoLayers.emplace_back(gctx, surfaces);
413 layer.protoLayer.envelope[AxisR] = {2_mm, 2_mm};
414 layer.protoLayer.envelope[AxisZ] = {1_mm, 1_mm};
417 std::ranges::sort(protoLayers,
418 [](
const LayerData&
a,
const LayerData& b) {
419 return std::abs(
a.protoLayer.medium(AxisZ)) <
420 std::abs(b.protoLayer.medium(AxisZ));
423 ATH_MSG_DEBUG(
"Found " << protoLayers.size() <<
" initial layers");
425 std::vector<LayerData> mergedLayers;
427 mergedLayers = mergeLayers(gctx, std::move(protoLayers));
429 mergedLayers = std::move(protoLayers);
432 ATH_MSG_DEBUG(
"After merging: " << mergedLayers.size() <<
" layers");
434 for (
const auto [key, pl] : Acts::enumerate(mergedLayers)) {
435 ATH_MSG_DEBUG(
"- Layer " << key <<
" has " << pl.surfaces.size()
438 pl.protoLayer.medium(AxisZ);
439 auto layerName = std::format(
"InnerPixel_{}EC_{}", key, s);
441 auto addLayer = [&layerName, &pl](
auto& parent) {
442 auto& layer = parent.addLayer(layerName);
444 layer.setNavigationPolicyFactory(
445 Acts::NavigationPolicyFactory{}
446 .add<Acts::SurfaceArrayNavigationPolicy>(
447 Acts::SurfaceArrayNavigationPolicy::Config{
450 .add<Acts::TryAllNavigationPolicy>(
451 Acts::TryAllNavigationPolicy::Config{.sensitives =
false})
454 layer.setSurfaces(pl.surfaces);
455 layer.setEnvelope(Acts::ExtentEnvelope{{
462 << key <<
" / " << mergedLayers.size()
463 <<
" at z = " << pl.protoLayer.medium(AxisZ));
465 ec.addMaterial(layerName +
"_Material", [&](
auto& lmat) {
466 lmat.configureFace(NegativeDisc,
467 AxisSpec::DeferredEquidistant(10, AxisR),
468 AxisSpec::DeferredEquidistant(40, AxisPhi));
469 lmat.configureFace(PositiveDisc,
470 AxisSpec::DeferredEquidistant(10, AxisR),
471 AxisSpec::DeferredEquidistant(40, AxisPhi));
479 auto& outerPixel =
node.addCylinderContainer(
"OuterPixel", AxisR);
480 outerPixel.setAttachmentStrategy(AttachmentStrategy::Gap);
481 outerPixel.setResizeStrategy(ResizeStrategy::Gap);
483 outerPixel.addMaterial(
"OuterPixelMaterial", [&](
auto& opmat) {
484 opmat.configureFace(OuterCylinder,
485 AxisSpec::DeferredEquidistant(20, AxisRPhi),
486 AxisSpec::DeferredEquidistant(20, AxisZ));
487 opmat.configureFace(InnerCylinder,
488 AxisSpec::DeferredEquidistant(20, AxisRPhi),
489 AxisSpec::DeferredEquidistant(20, AxisZ));
491 auto& outerPixelContainer = opmat.addCylinderContainer(
"OuterPixel", AxisZ);
493 auto& barrelGeoId = outerPixelContainer.withGeometryIdentifier();
497 barrelGeoId.addMaterial(
"OuterPixel_Material", [&](
auto& bmat) {
498 bmat.configureFace(NegativeDisc,
499 AxisSpec::DeferredEquidistant(10, AxisR),
500 AxisSpec::DeferredEquidistant(10, AxisPhi));
501 bmat.configureFace(PositiveDisc,
502 AxisSpec::DeferredEquidistant(10, AxisR),
503 AxisSpec::DeferredEquidistant(10, AxisPhi));
505 auto&
barrel = brl_mat.addCylinderContainer(
"OuterPixel_Brl", AxisR);
507 barrel.setAttachmentStrategy(AttachmentStrategy::Gap);
508 barrel.setResizeStrategy(ResizeStrategy::Gap);
510 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
512 for (
auto& element : elements) {
518 if (
id.layer_disk() <= 1) {
523 layers[elementLayer].push_back(element->surface().getSharedPtr());
526 ATH_MSG_DEBUG(
"Adding " << layers.size() <<
" layers to OuterPixel barrel");
528 for (
const auto& [ilayer, surfaces] : layers) {
529 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
533 std::format(
"OuterPixel_Brl_{}_Material", ilayer), [&](
auto& lmat) {
534 lmat.configureFace(OuterCylinder,
535 AxisSpec::DeferredEquidistant(40, AxisRPhi),
536 AxisSpec::DeferredEquidistant(20, AxisZ));
539 lmat.addLayer(
"OuterPixel_Brl_" + std::to_string(ilayer));
541 layer.setNavigationPolicyFactory(
542 Acts::NavigationPolicyFactory{}
543 .add<Acts::SurfaceArrayNavigationPolicy>(
544 Acts::SurfaceArrayNavigationPolicy::Config{
545 .layerType = Cylinder,
547 .add<Acts::TryAllNavigationPolicy>(
548 Acts::TryAllNavigationPolicy::Config{.sensitives =
552 layer.setSurfaces(surfaces);
553 layer.setEnvelope(Acts::ExtentEnvelope{{
560 constexpr static auto addEndcapLayer = [](
auto& parent,
const auto& name,
561 const auto& surfaces) {
562 parent.addLayer(name, [&surfaces](
auto& layer) {
563 layer.setNavigationPolicyFactory(
564 Acts::NavigationPolicyFactory{}
565 .add<Acts::SurfaceArrayNavigationPolicy>(
566 Acts::SurfaceArrayNavigationPolicy::Config{
567 .layerType = Disc, .bins = {30, 30}})
568 .add<Acts::TryAllNavigationPolicy>(
569 Acts::TryAllNavigationPolicy::Config{.sensitives =
false})
572 layer.setSurfaces(surfaces);
576 for (
int bec : {-2, 2}) {
577 const std::string s = bec > 0 ?
"p" :
"n";
579 auto& ec_outer_geoId = outerPixelContainer.withGeometryIdentifier();
582 .incrementLayerIds(1);
585 ec_outer_geoId.addCylinderContainer(
"OuterPixel_" + s +
"EC", AxisR);
588 std::array diskGroups{std::pair{3, 4}, std::pair{6, 5}, std::pair{7, 8}};
590 for (
size_t idx = 0; idx < diskGroups.size(); ++idx) {
591 auto [disk1, disk2] = diskGroups[idx];
593 Acts::MaterialDesignatorBlueprintNode* material =
nullptr;
594 if (idx < (diskGroups.size() - 1)) {
595 material = &ec_outer.addMaterial(
596 "OuterPixel_" + s +
"EC_" + std::to_string(idx) +
"_Material",
598 mat.configureFace(OuterCylinder,
599 AxisSpec::DeferredEquidistant(20, AxisRPhi),
600 AxisSpec::DeferredEquidistant(20, AxisZ));
606 ? material->addCylinderContainer(
607 "OuterPixel_" + s +
"EC_" + std::to_string(idx), AxisZ)
608 : ec_outer.addCylinderContainer(
609 "OuterPixel_" + s +
"EC_" + std::to_string(idx), AxisZ);
611 ec_stack.setAttachmentStrategy(AttachmentStrategy::Gap);
612 ec_stack.setResizeStrategy(ResizeStrategy::Gap);
614 std::map<std::tuple<int, int>,
615 std::vector<std::shared_ptr<Acts::Surface>>>
618 for (
auto& element : elements) {
620 if (
id.bec() != bec ||
621 (
id.layer_disk() != disk1 &&
id.layer_disk() != disk2)) {
624 std::tuple<int, int> key{
id.layer_disk(),
id.eta_module()};
625 eta_rings[key].push_back(element->surface().getSharedPtr());
628 ATH_MSG_DEBUG(
"Found " << eta_rings.size() <<
" eta rings in group "
631 std::vector<std::vector<std::shared_ptr<Acts::Surface>>> sorted_rings;
632 sorted_rings.reserve(eta_rings.size());
633 for (
const auto& [key, surfaces] : eta_rings) {
634 sorted_rings.push_back(surfaces);
637 std::ranges::sort(sorted_rings, [&gctx](
const auto&
a,
const auto& b) {
638 Acts::ProtoLayer pl_a(gctx, makeConstPtrVector(
a));
639 Acts::ProtoLayer pl_b(gctx, makeConstPtrVector(b));
640 return std::abs(pl_a.min(AxisZ)) < std::abs(pl_b.min(AxisZ));
643 for (
size_t i = 0; i < sorted_rings.size(); ++i) {
644 const auto& surfaces = sorted_rings[i];
645 auto layerName =
"OuterPixel_" + s +
"EC_" + std::to_string(idx) +
646 "_" + std::to_string(i);
648 ec_stack.addMaterial(layerName +
"_Material", [&](
auto& mat) {
649 mat.configureFace(PositiveDisc,
650 AxisSpec::DeferredEquidistant(10, AxisR),
651 AxisSpec::DeferredEquidistant(40, AxisPhi));
652 mat.configureFace(NegativeDisc,
653 AxisSpec::DeferredEquidistant(10, AxisR),
654 AxisSpec::DeferredEquidistant(40, AxisPhi));
655 addEndcapLayer(mat, layerName, surfaces);
664 const Acts::GeometryContext& gctx,
665 Acts::BlueprintNode&
node) {
670 throw std::runtime_error(
"ITkStrip manager not available");
677 std::vector<std::shared_ptr<ActsDetectorElement>> elements;
680 for (
const auto* element : *
m_itkStripMgr->getDetectorElementCollection()) {
683 if (siDetElement ==
nullptr) {
685 throw std::runtime_error{
"Corrupt detector element collection"};
687 elements.push_back(std::make_shared<ActsDetectorElement>(*siDetElement));
693 elements.begin(), elements.end());
695 auto&
strip =
node.addCylinderContainer(
"Strip", AxisR);
696 strip.setAttachmentStrategy(AttachmentStrategy::Gap);
697 strip.setResizeStrategy(ResizeStrategy::Gap);
699 strip.addMaterial(
"StripMaterial", [&](
auto& mat) {
700 mat.configureFace(OuterCylinder,
701 AxisSpec::DeferredEquidistant(20, AxisRPhi),
702 AxisSpec::DeferredEquidistant(20, AxisZ));
703 mat.configureFace(InnerCylinder,
704 AxisSpec::DeferredEquidistant(20, AxisRPhi),
705 AxisSpec::DeferredEquidistant(20, AxisZ));
707 auto& stripContainer = mat.addCylinderContainer(
"Strip", AxisZ);
710 stripContainer.withGeometryIdentifier([
this, &elements](
auto& geoId) {
714 geoId.addMaterial(
"Strip_Brl_Material", [&](
auto& material) {
715 material.configureFace(NegativeDisc,
716 AxisSpec::DeferredEquidistant(10, AxisR),
717 AxisSpec::DeferredEquidistant(10, AxisPhi));
718 material.configureFace(PositiveDisc,
719 AxisSpec::DeferredEquidistant(10, AxisR),
720 AxisSpec::DeferredEquidistant(10, AxisPhi));
722 brl_mat.addCylinderContainer(
723 "Strip_Brl", AxisR, [
this, &elements](
auto&
barrel) {
724 barrel.setAttachmentStrategy(AttachmentStrategy::Gap);
725 barrel.setResizeStrategy(ResizeStrategy::Gap);
727 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
729 for (
auto& element : elements) {
736 layers[elementLayer].push_back(element->surface().getSharedPtr());
740 <<
" layers to Strip barrel");
742 for (
const auto& [ilayer, surfaces] : layers) {
743 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
745 addStripBarrelLayer(
barrel, ilayer, surfaces);
751 for (
int bec : {-2, 2}) {
752 const std::string s = bec > 0 ?
"p" :
"n";
754 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
756 for (
auto& element : elements) {
758 if (
id.bec() * bec <= 0) {
762 layers[
id.layer_disk()].push_back(element->surface().getSharedPtr());
765 ATH_MSG_DEBUG(
"Found " << layers.size() <<
" layers in Strip " << s
768 std::vector<std::vector<std::shared_ptr<Acts::Surface>>> sorted_layers;
769 sorted_layers.reserve(layers.size());
770 for (
const auto& [key, surfaces] : layers) {
771 sorted_layers.push_back(surfaces);
774 std::sort(sorted_layers.begin(), sorted_layers.end(),
775 [&gctx](
const auto&
a,
const auto& b) {
776 Acts::ProtoLayer pl_a(gctx, makeConstPtrVector(a));
777 Acts::ProtoLayer pl_b(gctx, makeConstPtrVector(b));
778 return std::abs(pl_a.min(AxisZ)) < std::abs(pl_b.min(AxisZ));
781 stripContainer.withGeometryIdentifier([&sorted_layers, bec,
784 .incrementLayerIds(1);
786 geoId.addCylinderContainer(
787 "Strip_" + s +
"EC", AxisZ, [&sorted_layers, &s](
auto& ec) {
788 ec.setAttachmentStrategy(AttachmentStrategy::Gap);
789 ec.setResizeStrategy(ResizeStrategy::Gap);
791 for (
size_t i = 0; i < sorted_layers.size(); ++i) {
792 const auto& surfaces = sorted_layers[i];
793 auto layerName =
"Strip_" + s +
"EC_" + std::to_string(i);
794 addStripEndcapLayer(ec, layerName, surfaces);
804 std::vector<std::shared_ptr<Acts::Surface>> allStripSurfaces;
805 allStripSurfaces.reserve(elements.size());
806 for (
auto& element : elements) {
807 allStripSurfaces.push_back(element->surface().getSharedPtr());
809 Acts::ProtoLayer stripExtent(gctx, makeConstPtrVector(allStripSurfaces));
811 constexpr double spacerClearance = 5_mm;
812 constexpr double spacerThickness = 5_mm;
813 double spacerRmin = stripExtent.max(AxisR) + spacerClearance;
814 double spacerHalfZ = std::max(std::abs(stripExtent.min(AxisZ)),
815 std::abs(stripExtent.max(AxisZ))) +
818 strip.addStaticVolume(
819 Acts::Transform3::Identity(),
820 std::make_shared<Acts::CylinderVolumeBounds>(
821 spacerRmin, spacerRmin + spacerThickness, spacerHalfZ),
822 "Strip_OuterSpacer");