244 const Acts::GeometryContext& gctx,
245 Acts::Experimental::BlueprintNode&
node) {
250 throw std::runtime_error(
"ITkPixel manager not available");
257 std::vector<std::shared_ptr<ActsDetectorElement>> elements;
260 for (
const auto* element : *
m_itkPixelMgr->getDetectorElementCollection()) {
263 if (siDetElement ==
nullptr) {
265 throw std::runtime_error{
"Corrupt detector element collection"};
267 elements.push_back(std::make_shared<ActsDetectorElement>(*siDetElement));
273 elements.begin(), elements.end());
276 node.addMaterial(
"InnerPixelMaterial", [&](
auto& mat) {
277 mat.configureFace(OuterCylinder, {AxisRPhi, Closed, 20},
280 auto& innerPixelContainer = mat.addCylinderContainer(
"InnerPixel", AxisZ);
283 auto& barrelGeoId = innerPixelContainer.withGeometryIdentifier();
284 barrelGeoId.setAllVolumeIdsTo(s_innerPixelVolumeId)
285 .incrementLayerIds(1)
286 .sortBy([](
auto&
a,
auto& b) {
288 dynamic_cast<const Acts::CylinderVolumeBounds&
>(
a.volumeBounds());
290 dynamic_cast<const Acts::CylinderVolumeBounds&
>(b.volumeBounds());
292 using enum Acts::CylinderVolumeBounds::BoundValues;
293 double aMidR = (boundsA.get(eMinR) + boundsA.get(eMaxR)) / 2.0;
294 double bMidR = (boundsB.get(eMinR) + boundsB.get(eMaxR)) / 2.0;
296 return aMidR < bMidR;
302 barrelGeoId.addMaterial(
"InnerPixel_Material", [&](
auto& mat) {
303 mat.configureFace(NegativeDisc, {AxisR, Bound, 10},
304 {AxisPhi, Closed, 10});
305 mat.configureFace(PositiveDisc, {AxisR, Bound, 10},
306 {AxisPhi, Closed, 10});
308 auto&
barrel = brl_mat.addCylinderContainer(
"InnerPixel_Brl", AxisR);
310 barrel.setAttachmentStrategy(AttachmentStrategy::Gap);
311 barrel.setResizeStrategy(ResizeStrategy::Gap);
313 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
315 for (
auto& element : elements) {
321 if (
id.layer_disk() >= 2) {
326 layers[elementLayer].push_back(element->surface().getSharedPtr());
329 ATH_MSG_DEBUG(
"Adding " << layers.size() <<
" layers to InnerPixel barrel");
331 for (
const auto& [ilayer, surfaces] : layers) {
332 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
336 std::format(
"InnerPixel_Brl_{}_Material", ilayer), [&](
auto& lmat) {
338 lmat.configureFace(OuterCylinder, {AxisRPhi, Closed, 40},
343 lmat.addLayer(std::format(
"InnerPixel_Brl_{}", ilayer));
346 layer.setNavigationPolicyFactory(
347 Acts::NavigationPolicyFactory{}
348 .add<Acts::SurfaceArrayNavigationPolicy>(
349 Acts::SurfaceArrayNavigationPolicy::Config{
350 .layerType = Cylinder,
352 .add<Acts::TryAllNavigationPolicy>(
353 Acts::TryAllNavigationPolicy::Config{.sensitives =
357 layer.setSurfaces(surfaces);
358 layer.setEnvelope(Acts::ExtentEnvelope{{
366 for (
int bec : {-2, 2}) {
367 std::string s = bec > 0 ?
"p" :
"n";
368 auto& ecGeoId = innerPixelContainer.withGeometryIdentifier();
369 ecGeoId.setAllVolumeIdsTo(s_innerPixelVolumeId + std::floor(bec / 2))
370 .incrementLayerIds(1);
371 auto& ec = ecGeoId.addCylinderContainer(
"InnerPixel_" + s +
"EC", AxisZ);
372 ec.setAttachmentStrategy(AttachmentStrategy::Gap);
373 ec.setResizeStrategy(ResizeStrategy::Expand);
375 std::map<std::tuple<int, int, int>,
376 std::vector<std::shared_ptr<Acts::Surface>>>
379 for (
auto& element : elements) {
381 if (
id.bec() * bec <= 0) {
385 if (
id.layer_disk() >= 3) {
389 std::tuple<int, int, int> key{
id.bec(),
id.layer_disk(),
391 initialLayers[key].push_back(element->surface().getSharedPtr());
395 <<
" initial layers to InnerPixel " << s <<
"EC");
398 std::vector<LayerData> protoLayers;
399 protoLayers.reserve(initialLayers.size());
401 for (
const auto& [key, surfaces] : initialLayers) {
402 auto& layer = protoLayers.emplace_back(gctx, surfaces);
403 layer.protoLayer.envelope[AxisR] = {2_mm, 2_mm};
404 layer.protoLayer.envelope[AxisZ] = {1_mm, 1_mm};
408 std::ranges::sort(protoLayers,
409 [](
const LayerData&
a,
const LayerData& b) {
410 return std::abs(
a.protoLayer.medium(AxisZ)) <
411 std::abs(b.protoLayer.medium(AxisZ));
414 ATH_MSG_DEBUG(
"Found " << protoLayers.size() <<
" initial layers");
417 std::vector<LayerData> mergedLayers;
419 mergedLayers = mergeLayers(gctx, std::move(protoLayers));
421 mergedLayers = std::move(protoLayers);
424 ATH_MSG_DEBUG(
"After merging: " << mergedLayers.size() <<
" layers");
427 for (
const auto [key, pl] : Acts::enumerate(mergedLayers)) {
428 ATH_MSG_DEBUG(
"- Layer " << key <<
" has " << pl.surfaces.size()
431 pl.protoLayer.medium(AxisZ);
432 auto layerName = std::format(
"InnerPixel_{}EC_{}", key, s);
434 auto addLayer = [&layerName, &pl](
auto& parent) {
436 auto& layer = parent.addLayer(layerName);
439 layer.setNavigationPolicyFactory(
440 Acts::NavigationPolicyFactory{}
441 .add<Acts::SurfaceArrayNavigationPolicy>(
442 Acts::SurfaceArrayNavigationPolicy::Config{
445 .add<Acts::TryAllNavigationPolicy>(
446 Acts::TryAllNavigationPolicy::Config{.sensitives =
false})
449 layer.setSurfaces(pl.surfaces);
450 layer.setEnvelope(Acts::ExtentEnvelope{{
457 << key <<
" / " << mergedLayers.size()
458 <<
" at z = " << pl.protoLayer.medium(AxisZ));
459 if (key < mergedLayers.size() - 1) {
461 ec.addMaterial(layerName +
"_Material", [&](
auto& lmat) {
463 lmat.configureFace(bec < 0 ? NegativeDisc : PositiveDisc,
464 {AxisR, Bound, 40}, {AxisPhi, Closed, 40});
475 node.addMaterial(
"OuterPixelMaterial", [&](
auto& mat) {
476 mat.configureFace(OuterCylinder, {AxisRPhi, Bound, 20}, {AxisZ, Bound, 20});
478 auto& outerPixelContainer = mat.addCylinderContainer(
"OuterPixel", AxisZ);
481 auto& barrelGeoId = outerPixelContainer.withGeometryIdentifier();
482 barrelGeoId.setAllVolumeIdsTo(s_outerPixelVolumeId).incrementLayerIds(1);
487 barrelGeoId.addMaterial(
"OuterPixel_Material", [&](
auto& mat) {
488 mat.configureFace(NegativeDisc, {AxisR, Bound, 10},
489 {AxisPhi, Closed, 10});
490 mat.configureFace(PositiveDisc, {AxisR, Bound, 10},
491 {AxisPhi, Closed, 10});
493 auto&
barrel = brl_mat.addCylinderContainer(
"OuterPixel_Brl", AxisR);
495 barrel.setAttachmentStrategy(AttachmentStrategy::Gap);
496 barrel.setResizeStrategy(ResizeStrategy::Gap);
498 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
500 for (
auto& element : elements) {
506 if (
id.layer_disk() <= 1) {
511 layers[elementLayer].push_back(element->surface().getSharedPtr());
514 ATH_MSG_DEBUG(
"Adding " << layers.size() <<
" layers to OuterPixel barrel");
516 for (
const auto& [ilayer, surfaces] : layers) {
517 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
521 std::format(
"OuterPixel_Brl_{}_Material", ilayer), [&](
auto& lmat) {
523 lmat.configureFace(OuterCylinder, {AxisRPhi, Closed, 40},
528 lmat.addLayer(
"OuterPixel_Brl_" + std::to_string(ilayer));
531 layer.setNavigationPolicyFactory(
532 Acts::NavigationPolicyFactory{}
533 .add<Acts::SurfaceArrayNavigationPolicy>(
534 Acts::SurfaceArrayNavigationPolicy::Config{
535 .layerType = Cylinder,
537 .add<Acts::TryAllNavigationPolicy>(
538 Acts::TryAllNavigationPolicy::Config{.sensitives =
542 layer.setSurfaces(surfaces);
543 layer.setEnvelope(Acts::ExtentEnvelope{{
550 constexpr static auto addEndcapLayer = [](
auto& parent,
const auto& name,
551 const auto& surfaces) {
552 parent.addLayer(name, [&surfaces](
auto& layer) {
553 layer.setNavigationPolicyFactory(
554 Acts::NavigationPolicyFactory{}
555 .add<Acts::SurfaceArrayNavigationPolicy>(
556 Acts::SurfaceArrayNavigationPolicy::Config{
557 .layerType = Disc, .bins = {30, 30}})
558 .add<Acts::TryAllNavigationPolicy>(
559 Acts::TryAllNavigationPolicy::Config{.sensitives =
false})
562 layer.setSurfaces(surfaces);
567 for (
int bec : {-2, 2}) {
568 const std::string s = bec > 0 ?
"p" :
"n";
572 auto& ec_outer_geoId = outerPixelContainer.withGeometryIdentifier();
574 .setAllVolumeIdsTo(s_outerPixelVolumeId + std::floor(bec / 2))
575 .incrementLayerIds(1);
578 ec_outer_geoId.addCylinderContainer(
"OuterPixel_" + s +
"EC", AxisR);
581 std::array diskGroups{std::pair{3, 4}, std::pair{6, 5}, std::pair{7, 8}};
583 for (
size_t idx = 0; idx < diskGroups.size(); ++idx) {
584 auto [disk1, disk2] = diskGroups[idx];
589 Acts::Experimental::MaterialDesignatorBlueprintNode* material =
nullptr;
590 if (idx < (diskGroups.size() - 1)) {
591 material = &ec_outer.addMaterial(
592 "OuterPixel_" + s +
"EC_" + std::to_string(idx) +
"_Material",
594 mat.configureFace(OuterCylinder, {AxisRPhi, Closed, 20},
601 ? material->addCylinderContainer(
602 "OuterPixel_" + s +
"EC_" + std::to_string(idx), AxisZ)
603 : ec_outer.addCylinderContainer(
604 "OuterPixel_" + s +
"EC_" + std::to_string(idx), AxisZ);
606 ec_stack.setAttachmentStrategy(AttachmentStrategy::Gap);
607 ec_stack.setResizeStrategy(ResizeStrategy::Expand);
610 std::map<std::tuple<int, int>,
611 std::vector<std::shared_ptr<Acts::Surface>>>
614 for (
auto& element : elements) {
616 if (
id.bec() != bec ||
617 (
id.layer_disk() != disk1 &&
id.layer_disk() != disk2)) {
620 std::tuple<int, int> key{
id.layer_disk(),
id.eta_module()};
621 eta_rings[key].push_back(element->surface().getSharedPtr());
624 ATH_MSG_DEBUG(
"Found " << eta_rings.size() <<
" eta rings in group "
628 std::vector<std::vector<std::shared_ptr<Acts::Surface>>> sorted_rings;
629 sorted_rings.reserve(eta_rings.size());
630 for (
const auto& [key, surfaces] : eta_rings) {
631 sorted_rings.push_back(surfaces);
634 std::ranges::sort(sorted_rings, [&gctx](
const auto&
a,
const auto& b) {
635 Acts::ProtoLayer pl_a(gctx, makeConstPtrVector(
a));
636 Acts::ProtoLayer pl_b(gctx, makeConstPtrVector(b));
637 return std::abs(pl_a.min(AxisZ)) < std::abs(pl_b.min(AxisZ));
641 for (
size_t i = 0; i < sorted_rings.size(); ++i) {
642 const auto& surfaces = sorted_rings[i];
643 auto layerName =
"OuterPixel_" + s +
"EC_" + std::to_string(idx) +
644 "_" + std::to_string(i);
646 if (i < sorted_rings.size() - 1) {
647 ec_stack.addMaterial(layerName +
"_Material", [&](
auto& mat) {
648 mat.configureFace(bec > 0 ? PositiveDisc : NegativeDisc,
649 {AxisR, Bound, 20}, {AxisPhi, Closed, 40});
650 addEndcapLayer(mat, layerName, surfaces);
653 addEndcapLayer(ec_stack, layerName, surfaces);
662 const Acts::GeometryContext& gctx,
663 Acts::Experimental::BlueprintNode&
node) {
668 throw std::runtime_error(
"ITkStrip manager not available");
675 std::vector<std::shared_ptr<ActsDetectorElement>> elements;
678 for (
const auto* element : *
m_itkStripMgr->getDetectorElementCollection()) {
681 if (siDetElement ==
nullptr) {
683 throw std::runtime_error{
"Corrupt detector element collection"};
685 elements.push_back(std::make_shared<ActsDetectorElement>(*siDetElement));
691 elements.begin(), elements.end());
694 node.addMaterial(
"StripMaterial", [&](
auto& mat) {
695 mat.configureFace(OuterCylinder, {AxisRPhi, Closed, 20},
698 mat.addCylinderContainer(
"Strip", AxisZ, [&](
auto& strips) {
700 strips.withGeometryIdentifier([
this, &elements](
auto& geoId) {
701 geoId.setAllVolumeIdsTo(s_stripVolumeId).incrementLayerIds(1);
706 auto& brl_mat = geoId.addMaterial(
"Strip_Brl_Material", [&](
auto& mat) {
707 mat.configureFace(NegativeDisc, {AxisR, Bound, 10},
708 {AxisPhi, Closed, 10});
709 mat.configureFace(PositiveDisc, {AxisR, Bound, 10},
710 {AxisPhi, Closed, 10});
712 brl_mat.addCylinderContainer(
713 "Strip_Brl", AxisR, [
this, &elements](
auto&
barrel) {
714 barrel.setAttachmentStrategy(AttachmentStrategy::Gap);
715 barrel.setResizeStrategy(ResizeStrategy::Gap);
717 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>>
720 for (
auto& element : elements) {
727 layers[elementLayer].push_back(
728 element->surface().getSharedPtr());
732 <<
" layers to Strip barrel");
734 for (
const auto& [ilayer, surfaces] : layers) {
735 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
737 addStripBarrelLayer(
barrel, ilayer, surfaces);
743 for (
int bec : {-2, 2}) {
744 const std::string s = bec > 0 ?
"p" :
"n";
746 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
748 for (
auto& element : elements) {
750 if (
id.bec() * bec <= 0) {
754 layers[
id.layer_disk()].push_back(element->surface().getSharedPtr());
757 ATH_MSG_DEBUG(
"Found " << layers.size() <<
" layers in Strip " << s
761 std::vector<std::vector<std::shared_ptr<Acts::Surface>>> sorted_layers;
762 sorted_layers.reserve(layers.size());
763 for (
const auto& [key, surfaces] : layers) {
764 sorted_layers.push_back(surfaces);
767 std::sort(sorted_layers.begin(), sorted_layers.end(),
768 [&gctx](
const auto&
a,
const auto& b) {
769 Acts::ProtoLayer pl_a(gctx, makeConstPtrVector(a));
770 Acts::ProtoLayer pl_b(gctx, makeConstPtrVector(b));
771 return std::abs(pl_a.min(AxisZ)) <
772 std::abs(pl_b.min(AxisZ));
775 strips.withGeometryIdentifier([&sorted_layers, bec, &s](
auto& geoId) {
776 geoId.setAllVolumeIdsTo(s_stripVolumeId + std::floor(bec / 2))
777 .incrementLayerIds(1);
779 geoId.addCylinderContainer(
780 "Strip_" + s +
"EC", AxisZ, [&sorted_layers, bec, &s](
auto& ec) {
781 ec.setAttachmentStrategy(AttachmentStrategy::Gap);
782 ec.setResizeStrategy(ResizeStrategy::Gap);
785 for (
size_t i = 0; i < sorted_layers.size(); ++i) {
786 const auto& surfaces = sorted_layers[i];
787 auto layerName =
"Strip_" + s +
"EC_" + std::to_string(i);
789 addStripEndcapLayer(ec, bec, layerName, surfaces);