242 const Acts::GeometryContext& gctx,
243 Acts::Experimental::BlueprintNode&
node) {
248 throw std::runtime_error(
"ITkPixel manager not available");
255 std::vector<std::shared_ptr<ActsDetectorElement>> elements;
258 for (
const auto* element : *
m_itkPixelMgr->getDetectorElementCollection()) {
261 if (siDetElement ==
nullptr) {
263 throw std::runtime_error{
"Corrupt detector element collection"};
265 elements.push_back(std::make_shared<ActsDetectorElement>(*siDetElement));
271 elements.begin(), elements.end());
274 auto& innerPixel =
node.addCylinderContainer(
"InnerPixel", AxisR);
275 innerPixel.setAttachmentStrategy(AttachmentStrategy::Gap);
276 innerPixel.setResizeStrategy(ResizeStrategy::Gap);
278 innerPixel.addMaterial(
"InnerPixelMaterial", [&](
auto& mat) {
279 mat.configureFace(OuterCylinder, {AxisRPhi, Closed, 20},
281 mat.configureFace(InnerCylinder, {AxisRPhi, Closed, 20},
284 auto& innerPixelContainer = mat.addCylinderContainer(
"InnerPixel", AxisZ);
287 auto& barrelGeoId = innerPixelContainer.withGeometryIdentifier();
289 .incrementLayerIds(1)
290 .sortBy([](
auto&
a,
auto& b) {
292 dynamic_cast<const Acts::CylinderVolumeBounds&
>(
a.volumeBounds());
294 dynamic_cast<const Acts::CylinderVolumeBounds&
>(b.volumeBounds());
296 using enum Acts::CylinderVolumeBounds::BoundValues;
297 double aMidR = (boundsA.get(eMinR) + boundsA.get(eMaxR)) / 2.0;
298 double bMidR = (boundsB.get(eMinR) + boundsB.get(eMaxR)) / 2.0;
300 return aMidR < bMidR;
304 barrelGeoId.addMaterial(
"InnerPixel_Material", [&](
auto& mat) {
305 mat.configureFace(NegativeDisc, {AxisR, Bound, 10},
306 {AxisPhi, Closed, 10});
307 mat.configureFace(PositiveDisc, {AxisR, Bound, 10},
308 {AxisPhi, Closed, 10});
310 auto&
barrel = brl_mat.addCylinderContainer(
"InnerPixel_Brl", AxisR);
312 barrel.setAttachmentStrategy(AttachmentStrategy::Gap);
313 barrel.setResizeStrategy(ResizeStrategy::Gap);
315 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
317 for (
auto& element : elements) {
323 if (
id.layer_disk() >= 2) {
328 layers[elementLayer].push_back(element->surface().getSharedPtr());
331 ATH_MSG_DEBUG(
"Adding " << layers.size() <<
" layers to InnerPixel barrel");
333 for (
const auto& [ilayer, surfaces] : layers) {
334 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
338 std::format(
"InnerPixel_Brl_{}_Material", ilayer), [&](
auto& lmat) {
339 lmat.configureFace(OuterCylinder, {AxisRPhi, Closed, 40},
343 lmat.addLayer(std::format(
"InnerPixel_Brl_{}", ilayer));
345 layer.setNavigationPolicyFactory(
346 Acts::NavigationPolicyFactory{}
347 .add<Acts::SurfaceArrayNavigationPolicy>(
348 Acts::SurfaceArrayNavigationPolicy::Config{
349 .layerType = Cylinder,
351 .add<Acts::TryAllNavigationPolicy>(
352 Acts::TryAllNavigationPolicy::Config{.sensitives =
356 layer.setSurfaces(surfaces);
357 layer.setEnvelope(Acts::ExtentEnvelope{{
365 for (
int bec : {-2, 2}) {
366 std::string s = bec > 0 ?
"p" :
"n";
367 auto& ecGeoId = innerPixelContainer.withGeometryIdentifier();
369 .incrementLayerIds(1);
370 auto& ec = ecGeoId.addCylinderContainer(
"InnerPixel_" + s +
"EC", AxisZ);
371 ec.setAttachmentStrategy(AttachmentStrategy::Gap);
372 ec.setResizeStrategy(ResizeStrategy::Gap);
374 std::map<std::tuple<int, int, int>,
375 std::vector<std::shared_ptr<Acts::Surface>>>
378 for (
auto& element : elements) {
380 if (
id.bec() * bec <= 0) {
384 if (
id.layer_disk() >= 3) {
388 std::tuple<int, int, int> key{
id.bec(),
id.layer_disk(),
390 initialLayers[key].push_back(element->surface().getSharedPtr());
394 <<
" initial layers to InnerPixel " << s <<
"EC");
396 std::vector<LayerData> protoLayers;
397 protoLayers.reserve(initialLayers.size());
399 for (
const auto& [key, surfaces] : initialLayers) {
400 auto& layer = protoLayers.emplace_back(gctx, surfaces);
401 layer.protoLayer.envelope[AxisR] = {2_mm, 2_mm};
402 layer.protoLayer.envelope[AxisZ] = {1_mm, 1_mm};
405 std::ranges::sort(protoLayers,
406 [](
const LayerData&
a,
const LayerData& b) {
407 return std::abs(
a.protoLayer.medium(AxisZ)) <
408 std::abs(b.protoLayer.medium(AxisZ));
411 ATH_MSG_DEBUG(
"Found " << protoLayers.size() <<
" initial layers");
413 std::vector<LayerData> mergedLayers;
415 mergedLayers = mergeLayers(gctx, std::move(protoLayers));
417 mergedLayers = std::move(protoLayers);
420 ATH_MSG_DEBUG(
"After merging: " << mergedLayers.size() <<
" layers");
422 for (
const auto [key, pl] : Acts::enumerate(mergedLayers)) {
423 ATH_MSG_DEBUG(
"- Layer " << key <<
" has " << pl.surfaces.size()
426 pl.protoLayer.medium(AxisZ);
427 auto layerName = std::format(
"InnerPixel_{}EC_{}", key, s);
429 auto addLayer = [&layerName, &pl](
auto& parent) {
430 auto& layer = parent.addLayer(layerName);
432 layer.setNavigationPolicyFactory(
433 Acts::NavigationPolicyFactory{}
434 .add<Acts::SurfaceArrayNavigationPolicy>(
435 Acts::SurfaceArrayNavigationPolicy::Config{
438 .add<Acts::TryAllNavigationPolicy>(
439 Acts::TryAllNavigationPolicy::Config{.sensitives =
false})
442 layer.setSurfaces(pl.surfaces);
443 layer.setEnvelope(Acts::ExtentEnvelope{{
450 << key <<
" / " << mergedLayers.size()
451 <<
" at z = " << pl.protoLayer.medium(AxisZ));
453 ec.addMaterial(layerName +
"_Material", [&](
auto& lmat) {
454 lmat.configureFace(NegativeDisc, {AxisR, Bound, 10},
455 {AxisPhi, Closed, 40});
456 lmat.configureFace(PositiveDisc, {AxisR, Bound, 10},
457 {AxisPhi, Closed, 40});
465 auto& outerPixel =
node.addCylinderContainer(
"OuterPixel", AxisR);
466 outerPixel.setAttachmentStrategy(AttachmentStrategy::Gap);
467 outerPixel.setResizeStrategy(ResizeStrategy::Gap);
469 outerPixel.addMaterial(
"OuterPixelMaterial", [&](
auto& opmat) {
470 opmat.configureFace(OuterCylinder, {AxisRPhi, Bound, 20}, {AxisZ, Bound, 20});
471 opmat.configureFace(InnerCylinder, {AxisRPhi, Bound, 20}, {AxisZ, Bound, 20});
473 auto& outerPixelContainer = opmat.addCylinderContainer(
"OuterPixel", AxisZ);
475 auto& barrelGeoId = outerPixelContainer.withGeometryIdentifier();
479 barrelGeoId.addMaterial(
"OuterPixel_Material", [&](
auto& bmat) {
480 bmat.configureFace(NegativeDisc, {AxisR, Bound, 10},
481 {AxisPhi, Closed, 10});
482 bmat.configureFace(PositiveDisc, {AxisR, Bound, 10},
483 {AxisPhi, Closed, 10});
485 auto&
barrel = brl_mat.addCylinderContainer(
"OuterPixel_Brl", AxisR);
487 barrel.setAttachmentStrategy(AttachmentStrategy::Gap);
488 barrel.setResizeStrategy(ResizeStrategy::Gap);
490 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
492 for (
auto& element : elements) {
498 if (
id.layer_disk() <= 1) {
503 layers[elementLayer].push_back(element->surface().getSharedPtr());
506 ATH_MSG_DEBUG(
"Adding " << layers.size() <<
" layers to OuterPixel barrel");
508 for (
const auto& [ilayer, surfaces] : layers) {
509 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
513 std::format(
"OuterPixel_Brl_{}_Material", ilayer), [&](
auto& lmat) {
514 lmat.configureFace(OuterCylinder, {AxisRPhi, Closed, 40},
518 lmat.addLayer(
"OuterPixel_Brl_" + std::to_string(ilayer));
520 layer.setNavigationPolicyFactory(
521 Acts::NavigationPolicyFactory{}
522 .add<Acts::SurfaceArrayNavigationPolicy>(
523 Acts::SurfaceArrayNavigationPolicy::Config{
524 .layerType = Cylinder,
526 .add<Acts::TryAllNavigationPolicy>(
527 Acts::TryAllNavigationPolicy::Config{.sensitives =
531 layer.setSurfaces(surfaces);
532 layer.setEnvelope(Acts::ExtentEnvelope{{
539 constexpr static auto addEndcapLayer = [](
auto& parent,
const auto& name,
540 const auto& surfaces) {
541 parent.addLayer(name, [&surfaces](
auto& layer) {
542 layer.setNavigationPolicyFactory(
543 Acts::NavigationPolicyFactory{}
544 .add<Acts::SurfaceArrayNavigationPolicy>(
545 Acts::SurfaceArrayNavigationPolicy::Config{
546 .layerType = Disc, .bins = {30, 30}})
547 .add<Acts::TryAllNavigationPolicy>(
548 Acts::TryAllNavigationPolicy::Config{.sensitives =
false})
551 layer.setSurfaces(surfaces);
555 for (
int bec : {-2, 2}) {
556 const std::string s = bec > 0 ?
"p" :
"n";
558 auto& ec_outer_geoId = outerPixelContainer.withGeometryIdentifier();
561 .incrementLayerIds(1);
564 ec_outer_geoId.addCylinderContainer(
"OuterPixel_" + s +
"EC", AxisR);
567 std::array diskGroups{std::pair{3, 4}, std::pair{6, 5}, std::pair{7, 8}};
569 for (
size_t idx = 0; idx < diskGroups.size(); ++idx) {
570 auto [disk1, disk2] = diskGroups[idx];
572 Acts::Experimental::MaterialDesignatorBlueprintNode* material =
nullptr;
573 if (idx < (diskGroups.size() - 1)) {
574 material = &ec_outer.addMaterial(
575 "OuterPixel_" + s +
"EC_" + std::to_string(idx) +
"_Material",
577 mat.configureFace(OuterCylinder, {AxisRPhi, Closed, 20},
584 ? material->addCylinderContainer(
585 "OuterPixel_" + s +
"EC_" + std::to_string(idx), AxisZ)
586 : ec_outer.addCylinderContainer(
587 "OuterPixel_" + s +
"EC_" + std::to_string(idx), AxisZ);
589 ec_stack.setAttachmentStrategy(AttachmentStrategy::Gap);
590 ec_stack.setResizeStrategy(ResizeStrategy::Gap);
592 std::map<std::tuple<int, int>,
593 std::vector<std::shared_ptr<Acts::Surface>>>
596 for (
auto& element : elements) {
598 if (
id.bec() != bec ||
599 (
id.layer_disk() != disk1 &&
id.layer_disk() != disk2)) {
602 std::tuple<int, int> key{
id.layer_disk(),
id.eta_module()};
603 eta_rings[key].push_back(element->surface().getSharedPtr());
606 ATH_MSG_DEBUG(
"Found " << eta_rings.size() <<
" eta rings in group "
609 std::vector<std::vector<std::shared_ptr<Acts::Surface>>> sorted_rings;
610 sorted_rings.reserve(eta_rings.size());
611 for (
const auto& [key, surfaces] : eta_rings) {
612 sorted_rings.push_back(surfaces);
615 std::ranges::sort(sorted_rings, [&gctx](
const auto&
a,
const auto& b) {
616 Acts::ProtoLayer pl_a(gctx, makeConstPtrVector(
a));
617 Acts::ProtoLayer pl_b(gctx, makeConstPtrVector(b));
618 return std::abs(pl_a.min(AxisZ)) < std::abs(pl_b.min(AxisZ));
621 for (
size_t i = 0; i < sorted_rings.size(); ++i) {
622 const auto& surfaces = sorted_rings[i];
623 auto layerName =
"OuterPixel_" + s +
"EC_" + std::to_string(idx) +
624 "_" + std::to_string(i);
626 ec_stack.addMaterial(layerName +
"_Material", [&](
auto& mat) {
627 mat.configureFace(PositiveDisc, {AxisR, Bound, 10},
628 {AxisPhi, Closed, 40});
629 mat.configureFace(NegativeDisc, {AxisR, Bound, 10},
630 {AxisPhi, Closed, 40});
631 addEndcapLayer(mat, layerName, surfaces);
640 const Acts::GeometryContext& gctx,
641 Acts::Experimental::BlueprintNode&
node) {
646 throw std::runtime_error(
"ITkStrip manager not available");
653 std::vector<std::shared_ptr<ActsDetectorElement>> elements;
656 for (
const auto* element : *
m_itkStripMgr->getDetectorElementCollection()) {
659 if (siDetElement ==
nullptr) {
661 throw std::runtime_error{
"Corrupt detector element collection"};
663 elements.push_back(std::make_shared<ActsDetectorElement>(*siDetElement));
669 elements.begin(), elements.end());
671 auto&
strip =
node.addCylinderContainer(
"Strip", AxisR);
672 strip.setAttachmentStrategy(AttachmentStrategy::Gap);
673 strip.setResizeStrategy(ResizeStrategy::Gap);
675 strip.addMaterial(
"StripMaterial", [&](
auto& mat) {
676 mat.configureFace(OuterCylinder, {AxisRPhi, Closed, 20},
678 mat.configureFace(InnerCylinder, {AxisRPhi, Closed, 20},
681 auto& stripContainer = mat.addCylinderContainer(
"Strip", AxisZ);
684 stripContainer.withGeometryIdentifier([
this, &elements](
auto& geoId) {
687 auto& brl_mat = geoId.addMaterial(
"Strip_Brl_Material", [&](
auto& mat) {
688 mat.configureFace(NegativeDisc, {AxisR, Bound, 10},
689 {AxisPhi, Closed, 10});
690 mat.configureFace(PositiveDisc, {AxisR, Bound, 10},
691 {AxisPhi, Closed, 10});
693 brl_mat.addCylinderContainer(
694 "Strip_Brl", AxisR, [
this, &elements](
auto&
barrel) {
695 barrel.setAttachmentStrategy(AttachmentStrategy::Gap);
696 barrel.setResizeStrategy(ResizeStrategy::Gap);
698 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
700 for (
auto& element : elements) {
707 layers[elementLayer].push_back(element->surface().getSharedPtr());
711 <<
" layers to Strip barrel");
713 for (
const auto& [ilayer, surfaces] : layers) {
714 ATH_MSG_DEBUG(
"- Layer " << ilayer <<
" has " << surfaces.size()
716 addStripBarrelLayer(
barrel, ilayer, surfaces);
722 for (
int bec : {-2, 2}) {
723 const std::string s = bec > 0 ?
"p" :
"n";
725 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
727 for (
auto& element : elements) {
729 if (
id.bec() * bec <= 0) {
733 layers[
id.layer_disk()].push_back(element->surface().getSharedPtr());
736 ATH_MSG_DEBUG(
"Found " << layers.size() <<
" layers in Strip " << s
739 std::vector<std::vector<std::shared_ptr<Acts::Surface>>> sorted_layers;
740 sorted_layers.reserve(layers.size());
741 for (
const auto& [key, surfaces] : layers) {
742 sorted_layers.push_back(surfaces);
745 std::sort(sorted_layers.begin(), sorted_layers.end(),
746 [&gctx](
const auto&
a,
const auto& b) {
747 Acts::ProtoLayer pl_a(gctx, makeConstPtrVector(a));
748 Acts::ProtoLayer pl_b(gctx, makeConstPtrVector(b));
749 return std::abs(pl_a.min(AxisZ)) < std::abs(pl_b.min(AxisZ));
752 stripContainer.withGeometryIdentifier([&sorted_layers, bec,
755 .incrementLayerIds(1);
757 geoId.addCylinderContainer(
758 "Strip_" + s +
"EC", AxisZ, [&sorted_layers, &s](
auto& ec) {
759 ec.setAttachmentStrategy(AttachmentStrategy::Gap);
760 ec.setResizeStrategy(ResizeStrategy::Gap);
762 for (
size_t i = 0; i < sorted_layers.size(); ++i) {
763 const auto& surfaces = sorted_layers[i];
764 auto layerName =
"Strip_" + s +
"EC_" + std::to_string(i);
765 addStripEndcapLayer(ec, layerName, surfaces);
775 std::vector<std::shared_ptr<Acts::Surface>> allStripSurfaces;
776 allStripSurfaces.reserve(elements.size());
777 for (
auto& element : elements) {
778 allStripSurfaces.push_back(element->surface().getSharedPtr());
780 Acts::ProtoLayer stripExtent(gctx, makeConstPtrVector(allStripSurfaces));
782 constexpr double spacerClearance = 5_mm;
783 constexpr double spacerThickness = 5_mm;
784 double spacerRmin = stripExtent.max(AxisR) + spacerClearance;
785 double spacerHalfZ = std::max(std::abs(stripExtent.min(AxisZ)),
786 std::abs(stripExtent.max(AxisZ))) +
789 strip.addStaticVolume(
790 Acts::Transform3::Identity(),
791 std::make_shared<Acts::CylinderVolumeBounds>(
792 spacerRmin, spacerRmin + spacerThickness, spacerHalfZ),
793 "Strip_OuterSpacer");