82 const std::vector<Acts::ActsScalar>& rBoundaries,
83 const std::vector<Acts::ActsScalar>& phiBoundaries,
unsigned int index,
94 std::make_unique<Acts::RadialBounds>(
minR,
maxR, 0.5 * sectorPhi, avgPhi);
96 auto surface = Acts::Surface::makeShared<Acts::DiscSurface>(
99 const auto& stitchBoundaries =
100 (stitchValue ==
Acts::binR) ? rBoundaries : phiBoundaries;
103 stitchBoundaries, stitchValue);
118 const std::vector<Acts::ActsScalar>& zBoundaries,
119 const std::vector<Acts::ActsScalar>& phiBoundaries,
unsigned int index,
128 auto bounds = std::make_unique<Acts::CylinderBounds>(
r, 0.5 * lengthZ,
129 0.5 * sectorPhi, avgPhi);
131 auto surface = Acts::Surface::makeShared<Acts::CylinderSurface>(
135 const auto& stitchBoundaries =
136 (stitchValue ==
Acts::binZ) ? zBoundaries : phiBoundaries;
139 stitchBoundaries, stitchValue);
158 const auto& refTransform = refSurface.
transform(gctx);
159 auto refRotation = refTransform.rotation();
162 std::unique_ptr<Acts::PlanarBounds>
bounds =
nullptr;
172 Acts::Vector3 pCenter = volumeCenter + medium * refRotation.col(1
u);
173 transform.pretranslate(pCenter);
176 0.5 * (boundValues[Acts::RectangleBounds::BoundValues::eMaxX] -
177 boundValues[Acts::RectangleBounds::BoundValues::eMinX]);
179 bounds = std::make_unique<Acts::RectangleBounds>(
halfX, 0.5 * range);
184 const auto& surfaceCenter = refSurface.
center(gctx);
188 Acts::Vector3 pCenter = volumeCenter + centerR * refRotation.col(2);
189 transform.pretranslate(pCenter);
192 0.5 * (boundValues[Acts::RectangleBounds::BoundValues::eMaxY] -
193 boundValues[Acts::RectangleBounds::BoundValues::eMinY]);
194 bounds = std::make_unique<Acts::RectangleBounds>(0.5 * range,
halfY);
197 transform.prerotate(refRotation);
199 auto surface = Acts::Surface::makeShared<Acts::PlaneSurface>(
215 std::map<
unsigned int,
216 std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>>>
218 const std::vector<Acts::Experimental::DetectorComponent::PortalContainer>&
220 const std::vector<unsigned int>& sides,
221 const std::vector<unsigned int>& selectedOnly = {},
226 std::map<
unsigned int,
227 std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>>>
231 std::vector<unsigned int> selectedSides;
232 if (not selectedOnly.empty()) {
233 std::set_intersection(sides.begin(), sides.end(), selectedOnly.begin(),
235 std::back_inserter(selectedSides));
237 selectedSides = sides;
241 for (
const auto& pc : containers) {
243 for (
const auto&
s : selectedSides) {
244 auto cSide = pc.find(
s);
245 if (cSide != pc.end()) {
246 auto p = cSide->second;
247 auto& sVolumes = sideVolumes[
s];
251 sVolumes.insert(sVolumes.end(), aVolumes.begin(), aVolumes.end());
271 const std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>>&
274 auto refRotation =
volumes[0
u]->transform(gctx).rotation();
278 auto curRotation =
v->transform(gctx).rotation();
279 if (not curRotation.isApprox(refRotation)) {
282 message +=
std::string(
" is not aligned with previous volume");
283 throw std::invalid_argument(message.c_str());
297 const std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>>&
303 message +=
std::string(
"not enough volume given (") +
306 throw std::invalid_argument(message.c_str());
312 message +=
std::string(
"nullptr detector instead of volume " +
314 throw std::invalid_argument(message.c_str());
317 if (
v->volumeBounds().type() != Acts::VolumeBounds::BoundsType::eCylinder) {
319 std::string(
"non-cylindrical volume bounds detected for volume " +
321 throw std::invalid_argument(message.c_str());
337 const std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>>&
339 const std::vector<std::array<unsigned int, 2u>>& refCur) {
341 auto refValues =
volumes[0
u]->volumeBounds().values();
344 auto curValues =
v->volumeBounds().values();
345 for (
auto [r,
c] : refCur) {
346 if (std::abs(refValues[r] - curValues[
c]) >
348 std::string message =
"CylindricalDetectorHelper: '";
349 message +=
volumes[iv - 1]->name();
351 message +=
"' does not attach to '";
353 message +=
"' does not match with '";
355 message +=
volumes[iv]->name();
357 message +=
" - at bound values ";
360 throw std::runtime_error(message.c_str());
363 refValues = curValues;
373 std::vector<std::shared_ptr<Experimental::DetectorVolume>>&
volumes,
374 const std::vector<unsigned int>& selectedOnly,
382 std::vector<std::array<unsigned int, 2u>> checks = {
383 {1
u, 0
u}, {3
u, 3
u}, {4
u, 4
u}};
385 if (selectedOnly.empty()) {
386 checks.push_back({2
u, 2
u});
388 checkBounds(gctx,
volumes, checks);
396 DetectorComponent::PortalContainer dShell;
399 std::vector<ActsScalar> rBoundaries = {};
400 auto refValues =
volumes[0
u]->volumeBounds().values();
403 rBoundaries.push_back(refValues[CylinderVolumeBounds::BoundValues::eMinR]);
404 rBoundaries.push_back(refValues[CylinderVolumeBounds::BoundValues::eMaxR]);
407 bool connectR = selectedOnly.empty() or
408 std::find(selectedOnly.begin(), selectedOnly.end(), 2
u) !=
413 refValues[CylinderVolumeBounds::BoundValues::eHalfPhiSector];
414 ActsScalar avgPhi = refValues[CylinderVolumeBounds::BoundValues::eAveragePhi];
417 for (
unsigned int iv = 1; iv <
volumes.size(); ++iv) {
418 refValues =
volumes[iv]->volumeBounds().values();
420 rBoundaries.push_back(refValues[CylinderVolumeBounds::BoundValues::eMaxR]);
431 auto& keepCylinder =
volumes[iv - 1]->portalPtrs()[2
u];
432 auto& wasteCylinder =
volumes[iv]->portalPtrs()[3
u];
433 keepCylinder->fuse(wasteCylinder);
434 volumes[iv]->updatePortal(keepCylinder, 3
u);
455 std::vector<PortalReplacement> pReplacements = {};
460 for (
const auto [iu, idir] :
enumerate(discDirs)) {
461 if (selectedOnly.empty() or
462 std::find(selectedOnly.begin(), selectedOnly.end(), iu) !=
463 selectedOnly.end()) {
465 const Transform3& refTransform = refSurface.transform(gctx);
466 pReplacements.push_back(createDiscReplacement(
467 refTransform, rBoundaries, {avgPhi - phiSector, avgPhi + phiSector},
473 if (sectorsPresent) {
474 ACTS_VERBOSE(
"Sector planes are present, they need replacement.");
479 for (
const auto [iu, idir] :
enumerate(sectorDirs)) {
482 if (selectedOnly.empty() or
483 std::find(selectedOnly.begin(), selectedOnly.end(), iu + 4
u) !=
484 selectedOnly.end()) {
488 pReplacements.push_back(createSectorReplacement(
489 gctx, vCenter, refSurface, rBoundaries,
Acts::binR, iu + 4
u, idir));
494 "No sector planes present, full 2 * M_PI cylindrical geometry.");
504 ACTS_VERBOSE(
"- update portals of volume '" << iv->name() <<
"'.");
505 for (
auto& [
p,
i, dir, boundaries, binning] : pReplacements) {
513 size_t nPortals = iv->portals().size();
514 bool innerPresent = (nPortals == 3
u or nPortals == 5
u);
515 int iOffset = (innerPresent and
i > 2
u) ? -1 : 0;
517 <<
i + iOffset <<
" (including offset " << iOffset <<
")");
518 iv->updatePortal(
p, static_cast<unsigned int>(
i + iOffset));
528 std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>>& volumes,
529 const std::vector<unsigned int>& selectedOnly,
532 checkVolumes(gctx, volumes);
535 std::vector<std::array<unsigned int, 2u>> checks = {{3
u, 3
u}, {4
u, 4
u}};
538 if (selectedOnly.empty()) {
539 checks.push_back({0
u, 0
u});
540 checks.push_back({1
u, 1
u});
542 checkBounds(gctx, volumes, checks);
547 ACTS_DEBUG(
"Connect " << volumes.size() <<
" detector volumes in Z.");
550 DetectorComponent::PortalContainer dShell;
555 bool connectZ = selectedOnly.empty() or
556 std::find(selectedOnly.begin(), selectedOnly.end(), 1
u) !=
559 const auto rotation = volumes[0
u]->transform(gctx).rotation();
561 std::vector<Vector3> zBoundaries3D = {};
567 auto addZboundary3D = [&](
const Experimental::DetectorVolume& volume,
569 const auto boundValues = volume.volumeBounds().values();
571 boundValues[CylinderVolumeBounds::BoundValues::eHalfLengthZ];
572 zBoundaries3D.push_back(volume.transform(gctx).translation() +
573 side * halflengthZ * rotation.col(2));
577 addZboundary3D(*volumes[0
u].
get(), -1);
578 addZboundary3D(*volumes[0
u].
get(), 1);
579 for (
unsigned int iv = 1; iv < volumes.size(); ++iv) {
581 addZboundary3D(*volumes[iv].
get(), 1
u);
585 << volumes[iv]->
name() <<
"'.");
592 auto& keepDisc = volumes[iv - 1]->portalPtrs()[1
u];
593 auto& wasteDisc = volumes[iv]->portalPtrs()[0
u];
595 Vector3 keepPosition = keepDisc->surface().center(gctx);
596 Vector3 wastePosition = wasteDisc->surface().center(gctx);
597 if (not keepPosition.isApprox(wastePosition)) {
598 std::string message =
"CylindricalDetectorHelper: '";
599 message += volumes[iv - 1]->name();
600 message +=
"' does not attach to '";
601 message += volumes[iv]->name();
603 message +=
" - along z with values ";
606 throw std::runtime_error(message.c_str());
608 keepDisc->fuse(wasteDisc);
609 volumes[iv]->updatePortal(keepDisc, 0
u);
615 dShell[0
u] = volumes[0
u]->portalPtrs()[0
u];
616 dShell[1
u] = volumes[volumes.size() - 1
u]->portalPtrs()[1
u];
621 0.5 * (zBoundaries3D[zBoundaries3D.size() - 1
u] + zBoundaries3D[0
u]);
627 std::vector<ActsScalar> zBoundaries = {};
628 for (
const auto& zb3D : zBoundaries3D) {
629 auto proj3D = (zb3D - combinedCenter).dot(rotation.col(2));
632 zBoundaries.push_back(zBoundary);
635 Transform3 combinedTransform = Transform3::Identity();
636 combinedTransform.pretranslate(combinedCenter);
637 combinedTransform.rotate(rotation);
640 const auto& refVolume = volumes[0
u];
641 const auto refValues = refVolume->volumeBounds().values();
644 ActsScalar minR = refValues[CylinderVolumeBounds::BoundValues::eMinR];
645 ActsScalar maxR = refValues[CylinderVolumeBounds::BoundValues::eMaxR];
647 refValues[CylinderVolumeBounds::BoundValues::eHalfPhiSector];
648 ActsScalar avgPhi = refValues[CylinderVolumeBounds::BoundValues::eAveragePhi];
651 size_t nPortals = volumes[volumes.size() - 1
u]->portals().size();
652 bool innerPresent = (nPortals != 3
u and nPortals != 5
u);
653 bool sectorsPresent = nPortals > 4
u;
657 std::vector<PortalReplacement> pReplacements = {};
662 std::vector<Acts::ActsScalar> cylinderR = {maxR};
664 ACTS_VERBOSE(
"Inner surface present, tube geometry detected.");
665 cylinderDirs.push_back(Direction::Forward);
666 cylinderR.push_back(minR);
668 ACTS_VERBOSE(
"No inner surface present, solid cylinder geometry detected.");
671 unsigned int iSecOffset = innerPresent ? 4u : 3
u;
673 for (
const auto [iu, idir] :
enumerate(cylinderDirs)) {
674 if (selectedOnly.empty() or
675 std::find(selectedOnly.begin(), selectedOnly.end(), iu + 2
u) !=
676 selectedOnly.end()) {
677 pReplacements.push_back(createCylinderReplacement(
678 combinedTransform, cylinderR[iu], zBoundaries,
679 {avgPhi - phiSector, avgPhi + phiSector}, iu + 2
u, idir));
684 if (sectorsPresent) {
685 ACTS_VERBOSE(
"Sector planes are present, they need replacement.");
689 for (
const auto [iu, idir] :
enumerate(sectorDirs)) {
691 if (selectedOnly.empty() or
692 std::find(selectedOnly.begin(), selectedOnly.end(), iu + 4
u) !=
693 selectedOnly.end()) {
695 volumes[0
u]->portals()[iu + iSecOffset]->surface();
696 pReplacements.push_back(
697 createSectorReplacement(gctx, combinedCenter, refSurface,
703 "No sector planes present, full 2 * M_PI cylindrical geometry.");
710 ACTS_VERBOSE(
"Portals of " << volumes.size() <<
" volumes need updating.");
711 for (
auto& iv : volumes) {
712 ACTS_VERBOSE(
"- update portals of volume '" << iv->name() <<
"'.");
713 for (
auto& [
p,
i, dir, boundaries, binning] : pReplacements) {
717 int iOffset = (
i > 2u and not innerPresent) ? -1 : 0;
719 iv->updatePortal(
p, static_cast<unsigned int>(
i + iOffset));
731 std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>>& volumes,
732 const std::vector<unsigned int>& ,
735 checkVolumes(gctx, volumes);
740 ACTS_DEBUG(
"Connect " << volumes.size() <<
" detector volumes in phi.");
743 DetectorComponent::PortalContainer dShell;
746 size_t nPortals = volumes[volumes.size() - 1
u]->portals().size();
747 bool innerPresent = (nPortals != 3u and nPortals != 5
u);
749 Transform3 refTransform = volumes[0
u]->transform(gctx);
752 unsigned int iSecOffset = innerPresent ? 4u : 3
u;
753 std::vector<ActsScalar> phiBoundaries = {};
754 auto refValues = volumes[0
u]->volumeBounds().values();
755 phiBoundaries.push_back(
756 refValues[CylinderVolumeBounds::BoundValues::eAveragePhi] -
757 refValues[CylinderVolumeBounds::BoundValues::eHalfPhiSector]);
758 phiBoundaries.push_back(
759 refValues[CylinderVolumeBounds::BoundValues::eAveragePhi] +
760 refValues[CylinderVolumeBounds::BoundValues::eHalfPhiSector]);
762 for (
unsigned int iv = 1; iv < volumes.size(); ++iv) {
764 << volumes[iv]->
name() <<
"'.");
767 auto& keepSector = volumes[iv - 1]->portalPtrs()[iSecOffset + 1
u];
768 auto& wasteSector = volumes[iv]->portalPtrs()[iSecOffset];
769 keepSector->fuse(wasteSector);
770 volumes[iv]->updatePortal(keepSector, iSecOffset);
772 auto curValues = volumes[iv]->volumeBounds().values();
775 curValues[CylinderVolumeBounds::BoundValues::eAveragePhi] -
776 curValues[CylinderVolumeBounds::BoundValues::eHalfPhiSector];
778 curValues[CylinderVolumeBounds::BoundValues::eAveragePhi] +
779 curValues[CylinderVolumeBounds::BoundValues::eHalfPhiSector];
781 if (std::abs(phiBoundaries[phiBoundaries.size() - 1
u] - lowPhi) >
783 std::string message =
"CylindricalDetectorHelper: '";
784 message += volumes[iv - 1]->name();
785 message +=
"' does not attach to '";
786 message += volumes[iv]->name();
788 message +=
" - within phi sectors ";
792 throw std::runtime_error(message.c_str());
795 phiBoundaries.push_back(highPhi);
797 refValues = curValues;
802 std::vector<PortalReplacement> pReplacements = {};
804 pReplacements.push_back(createDiscReplacement(
806 {refValues[CylinderVolumeBounds::BoundValues::eMinR],
807 refValues[CylinderVolumeBounds::BoundValues::eMaxR]},
811 pReplacements.push_back(createDiscReplacement(
813 {refValues[CylinderVolumeBounds::BoundValues::eMinR],
814 refValues[CylinderVolumeBounds::BoundValues::eMaxR]},
818 pReplacements.push_back(createCylinderReplacement(
819 refTransform, refValues[CylinderVolumeBounds::BoundValues::eMaxR],
820 {-refValues[CylinderVolumeBounds::BoundValues::eHalfLengthZ],
821 refValues[CylinderVolumeBounds::BoundValues::eHalfLengthZ]},
826 if (refValues[CylinderVolumeBounds::BoundValues::eMinR] > 0.) {
828 pReplacements.push_back(createCylinderReplacement(
829 refTransform, refValues[CylinderVolumeBounds::BoundValues::eMinR],
830 {-refValues[CylinderVolumeBounds::BoundValues::eHalfLengthZ],
831 refValues[CylinderVolumeBounds::BoundValues::eHalfLengthZ]},
838 ACTS_VERBOSE(
"Portals of " << volumes.size() <<
" volumes need updating.");
839 for (
auto& iv : volumes) {
840 ACTS_VERBOSE(
"- update portals of volume '" << iv->name() <<
"'.");
841 for (
auto& [
p,
i, dir, boundaries, binning] : pReplacements) {
843 iv->updatePortal(
p, static_cast<unsigned int>(
i));
856 std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>>& volumes,
864 if (volumes.size() != 2
u) {
865 throw std::invalid_argument(
866 "Wrapping the detector volume requires exactly 2 volumes.");
870 DetectorComponent::PortalContainer dShell;
873 dShell[0
u] = volumes[1
u]->portalPtrs()[0
u];
874 dShell[1
u] = volumes[1
u]->portalPtrs()[1
u];
875 dShell[2
u] = volumes[1
u]->portalPtrs()[2
u];
878 auto& keepCover = volumes[0
u]->portalPtrs()[2
u];
879 auto& wasteCover = volumes[1
u]->portalPtrs()[3
u];
880 keepCover->fuse(wasteCover);
881 volumes[1
u]->updatePortal(keepCover, 3u);
884 auto& keepDiscN = volumes[1
u]->portalPtrs()[4
u];
885 auto& wasteDiscN = volumes[0
u]->portalPtrs()[0
u];
886 keepDiscN->fuse(wasteDiscN);
887 volumes[0
u]->updatePortal(keepDiscN, 0u);
890 auto& keepDiscP = volumes[0
u]->portalPtrs()[1
u];
891 auto& wasteDiscP = volumes[1
u]->portalPtrs()[5
u];
892 keepDiscP->fuse(wasteDiscP);
893 volumes[1
u]->updatePortal(keepDiscP, 5u);
896 if (volumes[0u]->portalPtrs().
size() == 4u and
897 volumes[1u]->portalPtrs().
size() == 8u) {
902 .values()[Acts::CylinderVolumeBounds::BoundValues::eHalfLengthZ];
904 volumes[1
u]->volumeBounds().values()
905 [Acts::CutoutCylinderVolumeBounds::BoundValues::eHalfLengthZ];
909 .values()[Acts::CylinderVolumeBounds::BoundValues::eMinR];
911 std::vector<PortalReplacement> pReplacements;
912 pReplacements.push_back(createCylinderReplacement(
913 volumes[0u]->
transform(gctx), innerR, {-HlZ, -hlZ, hlZ, HlZ},
914 {-M_PI, M_PI}, 3
u, Direction::Forward));
915 std::vector<std::shared_ptr<DetectorVolume>> zVolumes = {
916 volumes[1
u], volumes[0
u], volumes[1
u]};
919 auto& [
p,
i, dir, boundaries, binning] = pReplacements[0
u];
921 volumes[1
u]->updatePortal(
p, 6u);
922 volumes[0
u]->updatePortal(
p, 3u);
923 volumes[1
u]->updatePortal(
p, 7u);
934 const std::vector<DetectorComponent::PortalContainer>& containers,
935 const std::vector<unsigned int>& selectedOnly,
940 ACTS_DEBUG(
"Connect " << containers.size() <<
" proto containers in R.");
946 for (
unsigned int ic = 1; ic < containers.size(); ++ic) {
947 auto& formerContainer = containers[ic - 1];
948 auto& currentContainer = containers[ic];
950 if (formerContainer.find(2u) == formerContainer.end()) {
951 throw std::invalid_argument(
952 "CylindricalDetectorHelper: proto container has no outer cover, "
954 "not be connected in R");
956 if (currentContainer.find(3u) == currentContainer.end()) {
957 throw std::invalid_argument(
958 "CylindricalDetectorHelper: proto container has no inner cover, "
960 "not be connected in R");
964 std::shared_ptr<Portal> keepCylinder = containers[ic - 1].find(2u)->second;
965 std::shared_ptr<Portal> wasteCylinder = containers[ic].find(3u)->second;
966 keepCylinder->fuse(wasteCylinder);
967 for (
auto& av : wasteCylinder->attachedDetectorVolumes()[1
u]) {
968 av->updatePortal(keepCylinder, 3u);
973 if (containers[0u].find(3u) != containers[0u].
end()) {
974 dShell[3
u] = containers[0
u].find(3u)->second;
976 dShell[2
u] = containers[containers.size() - 1
u].find(2u)->second;
979 stripSideVolumes(containers, {0
u, 1
u, 4
u, 5u}, selectedOnly,
logLevel);
981 for (
auto [
s, volumes] : sideVolumes) {
983 if (pR.find(
s) != pR.end()) {
984 dShell[
s] = pR.find(
s)->second;
995 const std::vector<DetectorComponent::PortalContainer>& containers,
996 const std::vector<unsigned int>& selectedOnly,
1001 ACTS_DEBUG(
"Connect " << containers.size() <<
" proto containers in Z.");
1006 for (
unsigned int ic = 1; ic < containers.size(); ++ic) {
1007 auto& formerContainer = containers[ic - 1];
1008 auto& currentContainer = containers[ic];
1010 if (formerContainer.find(1u) == formerContainer.end()) {
1011 throw std::invalid_argument(
1012 "CylindricalDetectorHelper: proto container has no negative disc, "
1013 "can not be connected in Z");
1015 if (currentContainer.find(0u) == currentContainer.end()) {
1016 throw std::invalid_argument(
1017 "CylindricalDetectorHelper: proto container has no positive disc, "
1018 "can not be connected in Z");
1020 std::shared_ptr<Portal> keepDisc = formerContainer.find(1u)->second;
1021 std::shared_ptr<Portal> wasteDisc = currentContainer.find(0u)->second;
1022 keepDisc->fuse(wasteDisc);
1023 for (
auto& av : wasteDisc->attachedDetectorVolumes()[1
u]) {
1024 ACTS_VERBOSE(
"Update portal of detector volume '" << av->name() <<
"'.");
1025 av->updatePortal(keepDisc, 0u);
1030 dShell[0
u] = containers[0
u].find(0u)->second;
1031 dShell[1
u] = containers[containers.size() - 1
u].find(1u)->second;
1034 std::vector<unsigned int> nominalSides = {2
u, 4
u, 5u};
1035 if (containers[0u].find(3u) != containers[0u].
end()) {
1036 nominalSides.push_back(3u);
1041 stripSideVolumes(containers, nominalSides, selectedOnly, logLevel);
1044 <<
" side volume packs to be connected");
1045 for (
auto [
s, volumes] : sideVolumes) {
1046 ACTS_VERBOSE(
" - connect " << volumes.size() <<
" at selected side " <<
s);
1048 if (pR.find(
s) != pR.end()) {
1049 dShell[
s] = pR.find(
s)->second;
1060 [[maybe_unused]]
const std::vector<DetectorComponent::PortalContainer>&
1062 [[maybe_unused]]
const std::vector<unsigned int>& selectedOnly,
1064 throw std::invalid_argument(
1065 "CylindricalDetectorHelper: container connection in phi not implemented "
1075 const std::vector<DetectorComponent::PortalContainer>& containers,
1077 if (containers.size() != 2
u) {
1078 throw std::invalid_argument(
1079 "CylindricalDetectorHelper: wrapping must take exactly two "
1084 auto innerContainer = containers.front();
1086 auto outerContainer = containers.back();
1087 std::shared_ptr<DetectorVolume> wrappingVolume =
nullptr;
1088 for (
auto [key,
value] : outerContainer) {
1089 auto attachedVolumes =
value->attachedDetectorVolumes();
1090 for (
const auto& ava : attachedVolumes) {
1091 for (
const auto& av : ava) {
1092 if (wrappingVolume ==
nullptr and av !=
nullptr) {
1093 wrappingVolume = av;
1094 }
else if (wrappingVolume !=
nullptr and av != wrappingVolume) {
1095 throw std::invalid_argument(
1096 "CylindricalDetectorHelper: wrapping container must represent a "
1102 if (wrappingVolume ==
nullptr) {
1103 throw std::invalid_argument(
1104 "CylindricalDetectorHelper: wrapping volume could not be "
1111 ACTS_DEBUG(
"Wrapping a container with volume `" << wrappingVolume->name()
1114 DetectorComponent::PortalContainer dShell;
1117 dShell[0
u] = wrappingVolume->portalPtrs()[0
u];
1118 dShell[1
u] = wrappingVolume->portalPtrs()[1
u];
1119 dShell[2
u] = wrappingVolume->portalPtrs()[2
u];
1122 auto& keepCover = innerContainer[2
u];
1123 auto& wasteCover = wrappingVolume->portalPtrs()[3
u];
1124 keepCover->fuse(wasteCover);
1125 wrappingVolume->updatePortal(keepCover, 3u);
1128 auto& keepDiscN = innerContainer[0
u];
1129 auto& wasteDiscN = wrappingVolume->portalPtrs()[4
u];
1130 keepDiscN->fuse(wasteDiscN);
1131 wrappingVolume->updatePortal(keepDiscN, 4u);
1134 auto& keepDiscP = innerContainer[1
u];
1135 auto& wasteDiscP = wrappingVolume->portalPtrs()[5
u];
1136 keepDiscP->fuse(wasteDiscP);
1137 wrappingVolume->updatePortal(keepDiscP, 5u);
1140 if (innerContainer.size() == 4u and
1141 wrappingVolume->portalPtrs().size() == 8
u) {
1143 auto& centralSegment = innerContainer[3
u];
1144 auto centralValues = centralSegment->surface().bounds().values();
1146 centralValues[CylinderBounds::BoundValues::eHalfLengthZ];
1148 auto& nSegment = wrappingVolume->portalPtrs()[6
u];
1149 auto nValues = nSegment->surface().bounds().values();
1151 nValues[CylinderBounds::BoundValues::eHalfLengthZ];
1152 auto& pSegment = wrappingVolume->portalPtrs()[7
u];
1153 auto pValues = pSegment->surface().bounds().values();
1155 pValues[CylinderBounds::BoundValues::eHalfLengthZ];
1157 auto sideVolumes = stripSideVolumes({innerContainer}, {3u}, {3u},
logLevel);
1160 std::vector<std::shared_ptr<DetectorVolume>> innerVolumes = {
1161 wrappingVolume->getSharedPtr()};
1163 std::vector<ActsScalar> zBoundaries = {
1164 -centralHalfLengthZ - 2 * nHalfLengthZ, centralHalfLengthZ};
1166 for (
auto& svs : sideVolumes) {
1167 for (
auto&
v : svs.second) {
1169 zBoundaries.push_back(zBoundaries.back() + 2 * hlZ);
1170 innerVolumes.push_back(
v);
1174 zBoundaries.push_back(zBoundaries.back() + 2 * pHalfLengthZ);
1175 innerVolumes.push_back(wrappingVolume);