Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-04 07:57:56

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 = portalPtr(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   std::vector<OrientedSurface> orientedSurfaces =
0054       bounds.orientedSurfaces(m_volume->transform());
0055 
0056   auto handle = [&](Face face, std::size_t from) {
0057     const auto& source = orientedSurfaces.at(from);
0058     m_portals.at(toUnderlying(face)) =
0059         std::make_shared<Portal>(source.direction, source.surface, *m_volume);
0060   };
0061 
0062   handle(NegativeZFace, negativeFaceXY);
0063   handle(PositiveZFace, positiveFaceXY);
0064   handle(NegativeXFace, negativeFaceYZ);
0065   handle(PositiveXFace, positiveFaceYZ);
0066   handle(NegativeYFace, negativeFaceZX);
0067   handle(PositiveYFace, positiveFaceZX);
0068 }
0069 
0070 Portal* SingleCuboidPortalShell::portal(Face face) {
0071   return portalPtr(face).get();
0072 }
0073 
0074 std::shared_ptr<Portal> SingleCuboidPortalShell::portalPtr(Face face) {
0075   return m_portals.at(toUnderlying(face));
0076 }
0077 
0078 void SingleCuboidPortalShell::setPortal(std::shared_ptr<Portal> portal,
0079                                         Face face) {
0080   assert(portal != nullptr);
0081   assert(portal->isValid());
0082   m_portals.at(toUnderlying(face)) = std::move(portal);
0083 }
0084 
0085 std::size_t SingleCuboidPortalShell::size() const {
0086   std::size_t count = 0;
0087   std::ranges::for_each(
0088       m_portals, [&count](const auto& portal) { count += portal ? 1 : 0; });
0089   return count;
0090 }
0091 
0092 void SingleCuboidPortalShell::applyToVolume() {
0093   for (std::size_t i = 0; i < m_portals.size(); i++) {
0094     const auto& portal = m_portals.at(i);
0095     if (portal != nullptr) {
0096       if (!portal->isValid()) {
0097         std::stringstream ss;
0098         ss << static_cast<Face>(i);
0099         throw std::runtime_error{"Invalid portal found in shell at " +
0100                                  ss.str()};
0101       }
0102       m_volume->addPortal(portal);
0103     }
0104   }
0105 }
0106 
0107 bool SingleCuboidPortalShell::isValid() const {
0108   return std::ranges::all_of(m_portals, [](const auto& portal) {
0109     return portal == nullptr || portal->isValid();
0110   });
0111 };
0112 
0113 std::string SingleCuboidPortalShell::label() const {
0114   std::stringstream ss;
0115   ss << "CuboidShell(vol=" << m_volume->volumeName() << ")";
0116   return ss.str();
0117 }
0118 
0119 CuboidStackPortalShell::CuboidStackPortalShell(
0120     const GeometryContext& gctx, std::vector<CuboidPortalShell*> shells,
0121     AxisDirection direction, const Logger& logger)
0122     : m_direction(direction), m_shells{std::move(shells)} {
0123   using enum CuboidVolumeBounds::Face;
0124   using enum AxisDirection;
0125   std::tie(m_frontFace, m_backFace, m_sideFaces) =
0126       CuboidVolumeBounds::facesFromAxisDirection(m_direction);
0127 
0128   std::unordered_map<Face, AxisDirection> onSurfaceDirs;
0129   switch (m_direction) {
0130     case AxisX:
0131       onSurfaceDirs = {{NegativeZFace, AxisX},
0132                        {PositiveZFace, AxisX},
0133                        {NegativeYFace, AxisY},
0134                        {PositiveYFace, AxisY}};
0135       break;
0136     case AxisY:
0137       onSurfaceDirs = {{NegativeZFace, AxisY},
0138                        {PositiveZFace, AxisY},
0139                        {NegativeXFace, AxisX},
0140                        {PositiveXFace, AxisX}};
0141       break;
0142     case AxisZ:
0143       onSurfaceDirs = {{NegativeXFace, AxisY},
0144                        {PositiveXFace, AxisY},
0145                        {NegativeYFace, AxisX},
0146                        {PositiveYFace, AxisX}};
0147       break;
0148     default:
0149       throw std::invalid_argument("CuboidPortalShell: Invalid axis direction");
0150   }
0151 
0152   ACTS_VERBOSE("Making cuboid stack shell in " << m_direction << " direction");
0153   if (std::ranges::any_of(m_shells,
0154                           [](const auto* shell) { return shell == nullptr; })) {
0155     ACTS_ERROR("Invalid shell pointer");
0156     throw std::invalid_argument("Invalid shell pointer");
0157   }
0158 
0159   ACTS_VERBOSE(" ~> " << label());
0160 
0161   if (!std::ranges::all_of(
0162           m_shells, [](const auto* shell) { return shell->isValid(); })) {
0163     ACTS_ERROR("Invalid shell");
0164     throw std::invalid_argument("Invalid shell");
0165   }
0166 
0167   std::ranges::sort(m_shells, [*this](const auto& shellA, const auto& shellB) {
0168     switch (m_direction) {
0169       case AxisX:
0170         return (shellA->transform().translation().x() <
0171                 shellB->transform().translation().x());
0172       case AxisY:
0173         return (shellA->transform().translation().y() <
0174                 shellB->transform().translation().y());
0175       case AxisZ:
0176         return (shellA->transform().translation().z() <
0177                 shellB->transform().translation().z());
0178       default:
0179         throw std::invalid_argument(
0180             "CuboidPortalShell: Invalid axis direction");
0181     }
0182   });
0183 
0184   auto merge = [&](Face face) {
0185     std::vector<std::shared_ptr<Portal>> portals;
0186     std::ranges::transform(
0187         m_shells, std::back_inserter(portals),
0188         [face](auto* shell) { return shell->portalPtr(face); });
0189 
0190     auto merged = std::accumulate(
0191         std::next(portals.begin()), portals.end(), portals.front(),
0192         [&](const auto& aPortal,
0193             const auto& bPortal) -> std::shared_ptr<Portal> {
0194           assert(aPortal != nullptr);
0195           assert(bPortal != nullptr);
0196 
0197           AxisDirection onSurfaceAxis = onSurfaceDirs.at(face);
0198 
0199           return std::make_shared<Portal>(
0200               Portal::merge(gctx, *aPortal, *bPortal, onSurfaceAxis, logger));
0201         });
0202 
0203     assert(merged != nullptr);
0204     assert(merged->isValid());
0205 
0206     // reset merged portal on all shells
0207     for (auto& shell : m_shells) {
0208       shell->setPortal(merged, face);
0209     }
0210   };
0211 
0212   auto fuse = [&](Face faceA, Face faceB) {
0213     for (std::size_t i = 1; i < m_shells.size(); i++) {
0214       auto& shellA = m_shells.at(i - 1);
0215       auto& shellB = m_shells.at(i);
0216       ACTS_VERBOSE("Fusing " << shellA->label() << " and " << shellB->label());
0217 
0218       auto fused = std::make_shared<Portal>(Portal::fuse(
0219           gctx, *shellA->portalPtr(faceA), *shellB->portalPtr(faceB), logger));
0220 
0221       assert(fused != nullptr && "Invalid fused portal");
0222       assert(fused->isValid() && "Fused portal is invalid");
0223 
0224       shellA->setPortal(fused, faceA);
0225       shellB->setPortal(fused, faceB);
0226 
0227       assert(shellA->isValid() && "Shell A is not valid after fusing");
0228       assert(shellB->isValid() && "Shell B is not valid after fusing");
0229     }
0230   };
0231 
0232   for (const auto& face : m_sideFaces) {
0233     merge(face);
0234   }
0235   fuse(m_backFace, m_frontFace);
0236   assert(isValid() && "Shell is not valid after construction");
0237 }
0238 
0239 std::size_t CuboidStackPortalShell::size() const {
0240   return 6;
0241 }
0242 
0243 Portal* CuboidStackPortalShell::portal(Face face) {
0244   return portalPtr(face).get();
0245 }
0246 
0247 std::shared_ptr<Portal> CuboidStackPortalShell::portalPtr(Face face) {
0248   if (face == m_backFace) {
0249     return m_shells.back()->portalPtr(face);
0250   } else {
0251     return m_shells.front()->portalPtr(face);
0252   }
0253 }
0254 
0255 void CuboidStackPortalShell::setPortal(std::shared_ptr<Portal> portal,
0256                                        Face face) {
0257   assert(portal != nullptr);
0258 
0259   if (face == m_backFace) {
0260     m_shells.back()->setPortal(std::move(portal), face);
0261   } else if (face == m_frontFace) {
0262     m_shells.front()->setPortal(std::move(portal), face);
0263   } else {
0264     for (auto& shell : m_shells) {
0265       shell->setPortal(portal, face);
0266     }
0267   }
0268 }
0269 
0270 bool CuboidStackPortalShell::isValid() const {
0271   return std::ranges::all_of(m_shells, [](const auto* shell) {
0272     assert(shell != nullptr);
0273     return shell->isValid();
0274   });
0275 }
0276 
0277 const Transform3& CuboidStackPortalShell::transform() const {
0278   return m_shells.front()->transform();
0279 }
0280 
0281 std::string CuboidStackPortalShell::label() const {
0282   std::stringstream ss;
0283   ss << "CuboidStackShell(dir=" << m_direction << ", children=";
0284 
0285   std::vector<std::string> labels;
0286   std::ranges::transform(m_shells, std::back_inserter(labels),
0287                          [](const auto* shell) { return shell->label(); });
0288   ss << boost::algorithm::join(labels, "|");
0289   ss << ")";
0290   return ss.str();
0291 }
0292 
0293 std::ostream& operator<<(std::ostream& os, CuboidPortalShell::Face face) {
0294   switch (face) {
0295     using enum CuboidVolumeBounds::Face;
0296     case PositiveZFace:
0297       return os << "PositiveZFace";
0298     case NegativeZFace:
0299       return os << "NegativeZFace";
0300     case PositiveXFace:
0301       return os << "PositiveXFace";
0302     case NegativeXFace:
0303       return os << "NegativeXFace";
0304     case PositiveYFace:
0305       return os << "PositiveYFace";
0306     case NegativeYFace:
0307       return os << "NegativeYFace";
0308     default:
0309       return os << "Invalid face";
0310   }
0311 }
0312 
0313 }  // namespace Acts