Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-17 07:46:40

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 #pragma once
0010 
0011 #include "Acts/Geometry/CuboidPortalShell.hpp"
0012 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0013 #include "Acts/Geometry/CylinderPortalShell.hpp"
0014 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0015 #include "Acts/Geometry/DiamondPortalShell.hpp"
0016 #include "Acts/Geometry/DiamondVolumeBounds.hpp"
0017 #include "Acts/Geometry/TrapezoidPortalShell.hpp"
0018 #include "Acts/Geometry/TrapezoidVolumeBounds.hpp"
0019 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
0020 #include "Acts/Material/ProtoSurfaceMaterial.hpp"
0021 
0022 #include <format>
0023 #include <regex>
0024 #include <string>
0025 #include <variant>
0026 
0027 #include <boost/core/demangle.hpp>
0028 
0029 namespace Acts::Experimental::detail {
0030 
0031 const std::regex kPortalShellRegex{R"((\w+)PortalShell$)"};
0032 
0033 /// Extract the shape name from a portal shell type name, e.g.
0034 /// "Acts::CuboidPortalShell" -> "Cuboid". Falls back to full demangled name if
0035 /// the "PortalShell" suffix is not found.
0036 inline std::string portalShellShapeName(const std::type_info& type) {
0037   std::string full = boost::core::demangle(type.name());
0038 
0039   if (std::smatch match; std::regex_search(full, match, kPortalShellRegex)) {
0040     return match[1].str();
0041   }
0042   return full;
0043 }
0044 
0045 template <typename face_enum_t, typename shell_type_t>
0046 class ProtoDesignator {
0047  public:
0048   using Face = face_enum_t;
0049   using ShellType = shell_type_t;
0050 
0051   ProtoDesignator(Face face, const DirectedProtoAxis& loc0,
0052                   const DirectedProtoAxis& loc1, const std::string& prefix) {
0053     validateAxes(face, loc0, loc1, prefix);
0054     validateDuplicate(face, prefix);
0055     m_binning.emplace_back(face, loc0, loc1);
0056   }
0057 
0058   std::string label() const {
0059     return std::format("{}ProtoDesignator",
0060                        portalShellShapeName(typeid(ShellType)));
0061   }
0062 
0063   void apply(PortalShellBase& shell, const Logger& logger,
0064              const std::string& prefix) const {
0065     auto* concreteShell = dynamic_cast<ShellType*>(&shell);
0066     if (concreteShell == nullptr) {
0067       throw std::invalid_argument(prefix +
0068                                   portalShellShapeName(typeid(ShellType)) +
0069                                   " faces must use a valid face");
0070     }
0071 
0072     ACTS_DEBUG(prefix << "Binning is set to compatible type");
0073 
0074     for (const auto& [face, loc0, loc1] : m_binning) {
0075       auto* portal = concreteShell->portal(face).get();
0076       if (portal == nullptr) {
0077         ACTS_ERROR(prefix << "Portal is nullptr");
0078         throw std::runtime_error("Portal is nullptr");
0079       }
0080 
0081       ACTS_DEBUG(prefix << "Assigning material with binning: " << loc0 << ", "
0082                         << loc1 << " to face " << face);
0083 
0084       portal->surface().assignSurfaceMaterial(
0085           std::make_shared<ProtoGridSurfaceMaterial>(std::vector{loc0, loc1}));
0086     }
0087   }
0088 
0089   void graphvizLabel(std::ostream& os) const {
0090     os << "<br/><i>" << portalShellShapeName(typeid(ShellType))
0091        << " Binning</i>";
0092     for (const auto& [face, loc0, loc1] : m_binning) {
0093       os << "<br/> at: " << face;
0094       os << ": " << loc0.getAxisDirection() << "=" << loc0.getAxis().getNBins();
0095       os << ", " << loc1.getAxisDirection() << "=" << loc1.getAxis().getNBins();
0096     }
0097   }
0098 
0099   ProtoDesignator merged(const ProtoDesignator& other) const {
0100     ProtoDesignator result = *this;
0101     std::ranges::copy(other.m_binning, std::back_inserter(result.m_binning));
0102     return result;
0103   }
0104 
0105  private:
0106   void validateAxes(Face face, const DirectedProtoAxis& loc0,
0107                     const DirectedProtoAxis& loc1,
0108                     const std::string& prefix) const {
0109     using enum AxisDirection;
0110 
0111     if constexpr (std::is_same_v<ShellType, CylinderPortalShell>) {
0112       using enum CylinderVolumeBounds::Face;
0113       switch (face) {
0114         case NegativeDisc:
0115         case PositiveDisc:
0116           if (loc0.getAxisDirection() != AxisR ||
0117               loc1.getAxisDirection() != AxisPhi) {
0118             throw std::invalid_argument(prefix +
0119                                         "Disc faces must use (r, phi) binning");
0120           }
0121           break;
0122         case OuterCylinder:
0123         case InnerCylinder:
0124           if (loc0.getAxisDirection() != AxisRPhi ||
0125               loc1.getAxisDirection() != AxisZ) {
0126             throw std::invalid_argument(
0127                 prefix + "Cylinder faces must use (rphi, z) binning");
0128           }
0129           break;
0130         case NegativePhiPlane:
0131         case PositivePhiPlane:
0132           throw std::invalid_argument(prefix +
0133                                       "Phi plane faces are not supported");
0134         default:
0135           throw std::invalid_argument(prefix + "Unknown face type");
0136       }
0137     } else if constexpr (std::is_same_v<ShellType, CuboidPortalShell>) {
0138       if (loc0.getAxisDirection() != AxisX ||
0139           loc1.getAxisDirection() != AxisY) {
0140         throw std::invalid_argument(prefix +
0141                                     "Cuboid faces must use (x, y) binning");
0142       }
0143     } else {
0144       static_assert(std::is_same_v<ShellType, void>, "Unknown shell type");
0145     }
0146   }
0147 
0148   void validateDuplicate(Face face, const std::string& prefix) {
0149     if (std::ranges::find_if(m_binning, [&](const auto& bin) {
0150           return std::get<0>(bin) == face;
0151         }) != m_binning.end()) {
0152       throw std::invalid_argument(prefix +
0153                                   portalShellShapeName(typeid(ShellType)) +
0154                                   " face already configured");
0155     }
0156   }
0157 
0158   std::vector<std::tuple<Face, DirectedProtoAxis, DirectedProtoAxis>> m_binning;
0159 };
0160 
0161 using CylinderProtoDesignator =
0162     ProtoDesignator<CylinderVolumeBounds::Face, CylinderPortalShell>;
0163 using CuboidProtoDesignator =
0164     ProtoDesignator<CuboidVolumeBounds::Face, CuboidPortalShell>;
0165 
0166 template <typename face_enum_t, typename shell_type_t>
0167 class ISurfaceMaterialDesignator {
0168  public:
0169   using FaceType = face_enum_t;
0170   using ShellType = shell_type_t;
0171 
0172   ISurfaceMaterialDesignator(FaceType face,
0173                              std::shared_ptr<const ISurfaceMaterial> material) {
0174     m_materials.emplace_back(face, std::move(material));
0175   }
0176 
0177   std::string label() const {
0178     return std::format("{} ISurfaceMaterialDesignator",
0179                        portalShellShapeName(typeid(ShellType)));
0180   }
0181 
0182   void apply(PortalShellBase& shell, const Logger& logger,
0183              const std::string& prefix) const {
0184     auto* concreteShell = dynamic_cast<ShellType*>(&shell);
0185     if (concreteShell == nullptr) {
0186       ACTS_ERROR(prefix << "Concrete shell type mismatch: configured for "
0187                         << portalShellShapeName(typeid(ShellType))
0188                         << " but received "
0189                         << portalShellShapeName(typeid(shell)));
0190 
0191       throw std::invalid_argument(prefix + "Concrete shell type mismatch");
0192     }
0193 
0194     for (const auto& [face, material] : m_materials) {
0195       auto* portal = concreteShell->portal(face).get();
0196       if (portal == nullptr) {
0197         ACTS_ERROR(prefix << "Portal is nullptr");
0198         throw std::runtime_error("Portal is nullptr");
0199       }
0200 
0201       portal->surface().assignSurfaceMaterial(material);
0202     }
0203   }
0204 
0205   void graphvizLabel(std::ostream& os) const {
0206     os << "<br/><i>Homog. " << portalShellShapeName(typeid(ShellType))
0207        << " material</i>";
0208     for (const auto& [face, material] : m_materials) {
0209       os << "<br/> at: " << face;
0210     }
0211   }
0212 
0213   ISurfaceMaterialDesignator merged(
0214       const ISurfaceMaterialDesignator& other) const {
0215     ISurfaceMaterialDesignator result = *this;
0216     std::ranges::copy(other.m_materials,
0217                       std::back_inserter(result.m_materials));
0218     return result;
0219   }
0220 
0221  private:
0222   std::vector<std::pair<FaceType, std::shared_ptr<const ISurfaceMaterial>>>
0223       m_materials;
0224 };
0225 
0226 using CylinderHomogeneousMaterialDesignator =
0227     ISurfaceMaterialDesignator<CylinderVolumeBounds::Face, CylinderPortalShell>;
0228 
0229 using CuboidHomogeneousMaterialDesignator =
0230     ISurfaceMaterialDesignator<CuboidVolumeBounds::Face, CuboidPortalShell>;
0231 
0232 using TrapezoidHomogeneousMaterialDesignator =
0233     ISurfaceMaterialDesignator<TrapezoidVolumeBounds::Face,
0234                                TrapezoidPortalShell>;
0235 
0236 using DiamondHomogeneousMaterialDesignator =
0237     ISurfaceMaterialDesignator<DiamondVolumeBounds::Face, DiamondPortalShell>;
0238 
0239 /// Type-erased material designator. std::monostate represents the unconfigured
0240 /// (null) state.
0241 using Designator =
0242     std::variant<std::monostate, CylinderProtoDesignator, CuboidProtoDesignator,
0243                  CylinderHomogeneousMaterialDesignator,
0244                  CuboidHomogeneousMaterialDesignator,
0245                  TrapezoidHomogeneousMaterialDesignator,
0246                  DiamondHomogeneousMaterialDesignator>;
0247 
0248 /// Merge two designators. std::monostate acts as the identity element.
0249 /// Throws if the two active designator types are incompatible (e.g. cylinder
0250 /// proto vs cuboid proto, or proto vs homogeneous).
0251 inline Designator merge(const Designator& a, const Designator& b) {
0252   return std::visit(
0253       []<typename X, typename Y>(const X& x, const Y& y) -> Designator {
0254         if constexpr (std::is_same_v<X, std::monostate>) {
0255           return y;
0256         } else if constexpr (std::is_same_v<Y, std::monostate>) {
0257           return x;
0258         } else if constexpr (std::is_same_v<X, Y>) {
0259           return x.merged(y);
0260         } else {
0261           throw std::runtime_error(
0262               std::format("MaterialDesignator: Merging of {} with {} is not "
0263                           "supported. This means you are trying to configure "
0264                           "the same face with different binning or materials. "
0265                           "Please check your configuration.",
0266                           x.label(), y.label()));
0267         }
0268       },
0269       a, b);
0270 }
0271 
0272 /// Apply a designator to a portal shell.
0273 inline void apply(const Designator& d, PortalShellBase& shell,
0274                   const Logger& logger, const std::string& prefix) {
0275   std::visit(
0276       [&]<typename T>(const T& des) {
0277         if constexpr (std::is_same_v<T, std::monostate>) {
0278           ACTS_WARNING(prefix << "MaterialDesignator was not configured with "
0279                               << "any material designation! Check your "
0280                               << "configuration.");
0281         } else {
0282           des.apply(shell, logger, prefix);
0283         }
0284       },
0285       d);
0286 }
0287 
0288 /// Write a Graphviz label for a designator to an output stream.
0289 inline void graphvizLabel(const Designator& d, std::ostream& os) {
0290   std::visit(
0291       [&]<typename T>(const T& des) {
0292         if constexpr (std::is_same_v<T, std::monostate>) {
0293           os << "<br/><i>NullDesignator</i>";
0294         } else {
0295           des.graphvizLabel(os);
0296         }
0297       },
0298       d);
0299 }
0300 
0301 }  // namespace Acts::Experimental::detail