Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2026-07-16 08:07:47

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include "Acts/Geometry/CuboidPortalShell.hpp"
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Geometry/BoundarySurfaceFace.hpp"
0013 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0014 #include "Acts/Geometry/Portal.hpp"
0015 #include "Acts/Geometry/PortalLinkBase.hpp"
0016 #include "Acts/Geometry/TrackingVolume.hpp"
0017 #include "Acts/Utilities/AxisDefinitions.hpp"
0018 
0019 #include <algorithm>
0020 #include <array>
0021 #include <cstddef>
0022 #include <numeric>
0023 #include <stdexcept>
0024 #include <unordered_map>
0025 
0026 #include <boost/algorithm/string/join.hpp>
0027 
0028 namespace Acts {
0029 
0030 void CuboidPortalShell::fill(TrackingVolume& volume) {
0031   using enum CuboidVolumeBounds::Face;
0032   for (Face face : {NegativeZFace, PositiveZFace, NegativeXFace, PositiveXFace,
0033                     NegativeYFace, PositiveYFace}) {
0034     const auto& portalAtFace = portal(face);
0035     if (portalAtFace != nullptr) {
0036       portalAtFace->fill(volume);
0037       volume.addPortal(portalAtFace);
0038     }
0039   }
0040 }
0041 
0042 SingleCuboidPortalShell::SingleCuboidPortalShell(TrackingVolume& volume)
0043     : m_volume{&volume} {
0044   using enum CuboidVolumeBounds::Face;
0045   if (m_volume->volumeBounds().type() != VolumeBounds::BoundsType::eCuboid) {
0046     throw std::invalid_argument(
0047         "CuboidPortalShell: Invalid volume bounds type");
0048   }
0049 
0050   const auto& bounds =
0051       dynamic_cast<const CuboidVolumeBounds&>(m_volume->volumeBounds());
0052 
0053   ACTS_PUSH_IGNORE_DEPRECATED()
0054   std::vector<OrientedSurface> orientedSurfaces =
0055       bounds.orientedSurfaces(m_volume->transform());
0056   ACTS_POP_IGNORE_DEPRECATED()
0057 
0058   auto handle = [&](Face face, std::size_t from) {
0059     const auto& source = orientedSurfaces.at(from);
0060     m_portals.at(toUnderlying(face)) =
0061         std::make_shared<Portal>(source.direction, source.surface, *m_volume);
0062   };
0063 
0064   handle(NegativeZFace, negativeFaceXY);
0065   handle(PositiveZFace, positiveFaceXY);
0066   handle(NegativeXFace, negativeFaceYZ);
0067   handle(PositiveXFace, positiveFaceYZ);
0068   handle(NegativeYFace, negativeFaceZX);
0069   handle(PositiveYFace, positiveFaceZX);
0070 }
0071 
0072 std::shared_ptr<Portal> SingleCuboidPortalShell::portal(Face face) {
0073   return m_portals.at(toUnderlying(face));
0074 }
0075 
0076 void SingleCuboidPortalShell::setPortal(std::shared_ptr<Portal> portal,
0077                                         Face face) {
0078   assert(portal != nullptr);
0079   assert(portal->isValid());
0080   m_portals.at(toUnderlying(face)) = std::move(portal);
0081 }
0082 
0083 std::size_t SingleCuboidPortalShell::size() const {
0084   std::size_t count = 0;
0085   std::ranges::for_each(
0086       m_portals, [&count](const auto& portal) { count += portal ? 1 : 0; });
0087   return count;
0088 }
0089 
0090 void SingleCuboidPortalShell::applyToVolume() {
0091   for (std::size_t i = 0; i < m_portals.size(); i++) {
0092     const auto& portal = m_portals.at(i);
0093     if (portal != nullptr) {
0094       if (!portal->isValid()) {
0095         std::stringstream ss;
0096         ss << static_cast<Face>(i);
0097         throw std::runtime_error{"Invalid portal found in shell at " +
0098                                  ss.str()};
0099       }
0100       m_volume->addPortal(portal);
0101     }
0102   }
0103 }
0104 
0105 bool SingleCuboidPortalShell::isValid() const {
0106   return std::ranges::all_of(m_portals, [](const auto& portal) {
0107     return portal == nullptr || portal->isValid();
0108   });
0109 };
0110 
0111 std::string SingleCuboidPortalShell::label() const {
0112   std::stringstream ss;
0113   ss << "CuboidShell(vol=" << m_volume->volumeName() << ")";
0114   return ss.str();
0115 }
0116 
0117 CuboidStackPortalShell::CuboidStackPortalShell(
0118     const GeometryContext& gctx, std::vector<CuboidPortalShell*> shells,
0119     AxisDirection direction, const Logger& logger)
0120     : m_direction(direction), m_shells{std::move(shells)} {
0121   using enum CuboidVolumeBounds::Face;
0122   using enum AxisDirection;
0123   std::tie(m_frontFace, m_backFace, m_sideFaces) =
0124       CuboidVolumeBounds::facesFromAxisDirection(m_direction);
0125 
0126   std::unordered_map<Face, AxisDirection> onSurfaceDirs;
0127   switch (m_direction) {
0128     case AxisX:
0129       onSurfaceDirs = {{NegativeZFace, AxisX},
0130                        {PositiveZFace, AxisX},
0131                        {NegativeYFace, AxisY},
0132                        {PositiveYFace, AxisY}};
0133       break;
0134     case AxisY:
0135       onSurfaceDirs = {{NegativeZFace, AxisY},
0136                        {PositiveZFace, AxisY},
0137                        {NegativeXFace, AxisX},
0138                        {PositiveXFace, AxisX}};
0139       break;
0140     case AxisZ:
0141       onSurfaceDirs = {{NegativeXFace, AxisY},
0142                        {PositiveXFace, AxisY},
0143                        {NegativeYFace, AxisX},
0144                        {PositiveYFace, AxisX}};
0145       break;
0146     default:
0147       throw std::invalid_argument("CuboidPortalShell: Invalid axis direction");
0148   }
0149 
0150   ACTS_VERBOSE("Making cuboid stack shell in " << m_direction << " direction");
0151   if (std::ranges::any_of(m_shells,
0152                           [](const auto* shell) { return shell == nullptr; })) {
0153     ACTS_ERROR("Invalid shell pointer");
0154     throw std::invalid_argument("Invalid shell pointer");
0155   }
0156 
0157   ACTS_VERBOSE(" ~> " << label());
0158 
0159   if (!std::ranges::all_of(
0160           m_shells, [](const auto* shell) { return shell->isValid(); })) {
0161     ACTS_ERROR("Invalid shell");
0162     throw std::invalid_argument("Invalid shell");
0163   }
0164 
0165   std::ranges::sort(
0166       m_shells, [*this, &gctx](const auto& shellA, const auto& shellB) {
0167         switch (m_direction) {
0168           case AxisX:
0169             return (shellA->localToGlobalTransform(gctx).translation().x() <
0170                     shellB->localToGlobalTransform(gctx).translation().x());
0171           case AxisY:
0172             return (shellA->localToGlobalTransform(gctx).translation().y() <
0173                     shellB->localToGlobalTransform(gctx).translation().y());
0174           case AxisZ:
0175             return (shellA->localToGlobalTransform(gctx).translation().z() <
0176                     shellB->localToGlobalTransform(gctx).translation().z());
0177           default:
0178             throw std::invalid_argument(
0179                 "CuboidPortalShell: Invalid axis direction");
0180         }
0181       });
0182 
0183   auto merge = [&](Face face) {
0184     std::vector<std::shared_ptr<Portal>> portals;
0185     std::ranges::transform(m_shells, std::back_inserter(portals),
0186                            [face](auto* shell) { return shell->portal(face); });
0187 
0188     auto merged = std::accumulate(
0189         std::next(portals.begin()), portals.end(), portals.front(),
0190         [&](const auto& aPortal,
0191             const auto& bPortal) -> std::shared_ptr<Portal> {
0192           assert(aPortal != nullptr);
0193           assert(bPortal != nullptr);
0194 
0195           AxisDirection onSurfaceAxis = onSurfaceDirs.at(face);
0196 
0197           return std::make_shared<Portal>(
0198               Portal::merge(gctx, *aPortal, *bPortal, onSurfaceAxis, logger));
0199         });
0200 
0201     assert(merged != nullptr);
0202     assert(merged->isValid());
0203 
0204     // reset merged portal on all shells
0205     for (auto& shell : m_shells) {
0206       shell->setPortal(merged, face);
0207     }
0208   };
0209 
0210   auto fuse = [&](Face faceA, Face faceB) {
0211     for (std::size_t i = 1; i < m_shells.size(); i++) {
0212       auto& shellA = m_shells.at(i - 1);
0213       auto& shellB = m_shells.at(i);
0214       ACTS_VERBOSE("Fusing " << shellA->label() << " and " << shellB->label());
0215 
0216       auto fused = std::make_shared<Portal>(Portal::fuse(
0217           gctx, *shellA->portal(faceA), *shellB->portal(faceB), logger));
0218 
0219       assert(fused != nullptr && "Invalid fused portal");
0220       assert(fused->isValid() && "Fused portal is invalid");
0221 
0222       shellA->setPortal(fused, faceA);
0223       shellB->setPortal(fused, faceB);
0224 
0225       assert(shellA->isValid() && "Shell A is not valid after fusing");
0226       assert(shellB->isValid() && "Shell B is not valid after fusing");
0227     }
0228   };
0229 
0230   for (const auto& face : m_sideFaces) {
0231     merge(face);
0232   }
0233   fuse(m_backFace, m_frontFace);
0234   assert(isValid() && "Shell is not valid after construction");
0235 }
0236 
0237 std::size_t CuboidStackPortalShell::size() const {
0238   return 6;
0239 }
0240 
0241 std::shared_ptr<Portal> CuboidStackPortalShell::portal(Face face) {
0242   if (face == m_backFace) {
0243     return m_shells.back()->portal(face);
0244   } else {
0245     return m_shells.front()->portal(face);
0246   }
0247 }
0248 
0249 void CuboidStackPortalShell::setPortal(std::shared_ptr<Portal> portal,
0250                                        Face face) {
0251   assert(portal != nullptr);
0252 
0253   if (face == m_backFace) {
0254     m_shells.back()->setPortal(std::move(portal), face);
0255   } else if (face == m_frontFace) {
0256     m_shells.front()->setPortal(std::move(portal), face);
0257   } else {
0258     for (auto& shell : m_shells) {
0259       shell->setPortal(portal, face);
0260     }
0261   }
0262 }
0263 
0264 bool CuboidStackPortalShell::isValid() const {
0265   return std::ranges::all_of(m_shells, [](const auto* shell) {
0266     assert(shell != nullptr);
0267     return shell->isValid();
0268   });
0269 }
0270 
0271 const Transform3& CuboidStackPortalShell::localToGlobalTransform(
0272     const GeometryContext& gctx) const {
0273   return m_shells.front()->localToGlobalTransform(gctx);
0274 }
0275 
0276 std::string CuboidStackPortalShell::label() const {
0277   std::stringstream ss;
0278   ss << "CuboidStackShell(dir=" << m_direction << ", children=";
0279 
0280   std::vector<std::string> labels;
0281   std::ranges::transform(m_shells, std::back_inserter(labels),
0282                          [](const auto* shell) { return shell->label(); });
0283   ss << boost::algorithm::join(labels, "|");
0284   ss << ")";
0285   return ss.str();
0286 }
0287 
0288 std::ostream& operator<<(std::ostream& os, CuboidPortalShell::Face face) {
0289   switch (face) {
0290     using enum CuboidVolumeBounds::Face;
0291     case PositiveZFace:
0292       return os << "PositiveZFace";
0293     case NegativeZFace:
0294       return os << "NegativeZFace";
0295     case PositiveXFace:
0296       return os << "PositiveXFace";
0297     case NegativeXFace:
0298       return os << "NegativeXFace";
0299     case PositiveYFace:
0300       return os << "PositiveYFace";
0301     case NegativeYFace:
0302       return os << "NegativeYFace";
0303     default:
0304       return os << "Invalid face";
0305   }
0306 }
0307 
0308 }  // namespace Acts