Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-06-21 08:08:55

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/Material/HomogeneousSurfaceMaterial.hpp"
0016 #include "Acts/Material/ProtoSurfaceMaterial.hpp"
0017 
0018 #include <boost/core/demangle.hpp>
0019 
0020 namespace Acts::Experimental::detail {
0021 
0022 class CylinderProtoDesignator;
0023 class CuboidProtoDesignator;
0024 class NullDesignator;
0025 template <typename face_enum_t, typename shell_type_t>
0026 class HomogeneousMaterialDesignator;
0027 
0028 using CylinderHomogeneousMaterialDesignator =
0029     HomogeneousMaterialDesignator<CylinderVolumeBounds::Face,
0030                                   CylinderPortalShell>;
0031 
0032 using CuboidHomogeneousMaterialDesignator =
0033     HomogeneousMaterialDesignator<CuboidVolumeBounds::Face, CuboidPortalShell>;
0034 
0035 class DesignatorBase {
0036  public:
0037   virtual ~DesignatorBase() = default;
0038 
0039   virtual void apply(PortalShellBase& shell, const Logger& logger,
0040                      const std::string& prefix) = 0;
0041 
0042   virtual std::string label() const = 0;
0043 
0044   using FaceVariant =
0045       std::variant<CylinderVolumeBounds::Face, CuboidVolumeBounds::Face>;
0046 
0047   virtual std::unique_ptr<DesignatorBase> merged(
0048       const DesignatorBase& other) const = 0;
0049 
0050   virtual std::unique_ptr<DesignatorBase> merged(
0051       const CylinderProtoDesignator& other) const;
0052 
0053   virtual std::unique_ptr<DesignatorBase> merged(
0054       const CuboidProtoDesignator& other) const;
0055 
0056   virtual std::unique_ptr<DesignatorBase> merged(
0057       const NullDesignator& other) const;
0058 
0059   virtual std::unique_ptr<DesignatorBase> merged(
0060       const CylinderHomogeneousMaterialDesignator& other) const;
0061 
0062   virtual std::unique_ptr<DesignatorBase> merged(
0063       const CuboidHomogeneousMaterialDesignator& other) const;
0064 
0065   virtual void graphvizLabel(std::ostream& os) const = 0;
0066 };
0067 
0068 class CylinderProtoDesignator : public DesignatorBase {
0069  public:
0070   using Face = CylinderVolumeBounds::Face;
0071 
0072   CylinderProtoDesignator(Face face, const DirectedProtoAxis& loc0,
0073                           const DirectedProtoAxis& loc1,
0074                           const std::string& prefix) {
0075     validate(face, loc0, loc1, prefix);
0076 
0077     m_binning.emplace_back(face, loc0, loc1);
0078   }
0079 
0080   std::string label() const override { return "CylinderProtoDesignator"; }
0081 
0082   void apply(PortalShellBase& shell, const Logger& logger,
0083              const std::string& prefix) override {
0084     auto* cylShell = dynamic_cast<CylinderPortalShell*>(&shell);
0085     if (cylShell == nullptr) {
0086       throw std::invalid_argument(prefix +
0087                                   "Cylinder faces must use a valid face");
0088     }
0089 
0090     ACTS_DEBUG(prefix << "Binning is set to compatible type");
0091     using enum CylinderVolumeBounds::Face;
0092 
0093     for (const auto& [face, loc0, loc1] : m_binning) {
0094       auto* portal = cylShell->portal(face);
0095       if (portal == nullptr) {
0096         ACTS_ERROR(prefix << "Portal is nullptr");
0097         throw std::runtime_error("Portal is nullptr");
0098       }
0099 
0100       ACTS_DEBUG(prefix << "Assigning material with binning: " << loc0 << ", "
0101                         << loc1 << " to face " << face);
0102 
0103       portal->surface().assignSurfaceMaterial(
0104           std::make_shared<ProtoGridSurfaceMaterial>(std::vector{loc0, loc1}));
0105     }
0106   }
0107 
0108   void graphvizLabel(std::ostream& os) const override {
0109     os << "<br/><i>Cylinder Binning</i>";
0110     for (const auto& [face, loc0, loc1] : m_binning) {
0111       os << "<br/> at: " << face;
0112       os << ": " << loc0.getAxisDirection() << "=" << loc0.getAxis().getNBins();
0113       os << ", " << loc1.getAxisDirection() << "=" << loc1.getAxis().getNBins();
0114     }
0115   }
0116 
0117   std::unique_ptr<DesignatorBase> merged(
0118       const DesignatorBase& other) const override {
0119     return other.merged(*this);
0120   }
0121 
0122   std::unique_ptr<DesignatorBase> merged(
0123       const CylinderProtoDesignator& other) const override {
0124     auto merged = std::make_unique<CylinderProtoDesignator>(*this);
0125     std::ranges::copy(other.m_binning, std::back_inserter(merged->m_binning));
0126     return merged;
0127   }
0128 
0129   std::unique_ptr<DesignatorBase> merged(
0130       const NullDesignator& /*other*/) const override {
0131     return std::make_unique<CylinderProtoDesignator>(*this);
0132   }
0133 
0134  private:
0135   void validate(Face face, const DirectedProtoAxis& loc0,
0136                 const DirectedProtoAxis& loc1, const std::string& prefix) {
0137     using enum CylinderVolumeBounds::Face;
0138     using enum AxisDirection;
0139 
0140     // Validate axis directions based on face type
0141     switch (face) {
0142       case NegativeDisc:
0143       case PositiveDisc:
0144         if (loc0.getAxisDirection() != AxisR ||
0145             loc1.getAxisDirection() != AxisPhi) {
0146           throw std::invalid_argument(prefix +
0147                                       "Disc faces must use (r, phi) binning");
0148         }
0149         break;
0150       case OuterCylinder:
0151       case InnerCylinder:
0152         if (loc0.getAxisDirection() != AxisRPhi ||
0153             loc1.getAxisDirection() != AxisZ) {
0154           throw std::invalid_argument(
0155               prefix + "Cylinder faces must use (rphi, z) binning");
0156         }
0157         break;
0158       case NegativePhiPlane:
0159       case PositivePhiPlane:
0160         throw std::invalid_argument(prefix +
0161                                     "Phi plane faces are not supported");
0162         break;
0163     }
0164 
0165     if (std::ranges::find_if(m_binning, [&](const auto& bin) {
0166           return std::get<0>(bin) == face;
0167         }) != m_binning.end()) {
0168       throw std::invalid_argument(prefix + "Cylinder face already configured");
0169     }
0170   }
0171 
0172   std::vector<std::tuple<Face, DirectedProtoAxis, DirectedProtoAxis>> m_binning;
0173 };
0174 
0175 class CuboidProtoDesignator : public DesignatorBase {
0176  public:
0177   using Face = CuboidVolumeBounds::Face;
0178 
0179   CuboidProtoDesignator(Face face, const DirectedProtoAxis& loc0,
0180                         const DirectedProtoAxis& loc1,
0181                         const std::string& prefix) {
0182     validate(face, loc0, loc1, prefix);
0183 
0184     m_binning.emplace_back(face, loc0, loc1);
0185   }
0186 
0187   std::string label() const override { return "CuboidProtoDesignator"; }
0188 
0189   void apply(PortalShellBase& shell, const Logger& logger,
0190              const std::string& prefix) override {
0191     auto* cuboidShell = dynamic_cast<CuboidPortalShell*>(&shell);
0192     if (cuboidShell == nullptr) {
0193       throw std::invalid_argument(prefix +
0194                                   "Cuboid faces must use a valid face");
0195     }
0196 
0197     ACTS_DEBUG(prefix << "Binning is set to compatible type");
0198     using enum CuboidVolumeBounds::Face;
0199 
0200     for (const auto& [face, loc0, loc1] : m_binning) {
0201       auto* portal = cuboidShell->portal(face);
0202       if (portal == nullptr) {
0203         ACTS_ERROR(prefix << "Portal is nullptr");
0204         throw std::runtime_error("Portal is nullptr");
0205       }
0206 
0207       ACTS_DEBUG(prefix << "Assigning material with binning: " << loc0 << ", "
0208                         << loc1 << " to face " << face);
0209 
0210       portal->surface().assignSurfaceMaterial(
0211           std::make_shared<ProtoGridSurfaceMaterial>(std::vector{loc0, loc1}));
0212     }
0213   }
0214 
0215   void graphvizLabel(std::ostream& os) const override {
0216     os << "<br/><i>Cuboid Binning</i>";
0217     for (const auto& [face, loc0, loc1] : m_binning) {
0218       os << "<br/> at: " << face;
0219       os << ": " << loc0.getAxisDirection() << "=" << loc0.getAxis().getNBins();
0220       os << ", " << loc1.getAxisDirection() << "=" << loc1.getAxis().getNBins();
0221     }
0222   }
0223 
0224   std::unique_ptr<DesignatorBase> merged(
0225       const DesignatorBase& other) const override {
0226     return other.merged(*this);
0227   }
0228 
0229   std::unique_ptr<DesignatorBase> merged(
0230       const CuboidProtoDesignator& other) const override {
0231     auto merged = std::make_unique<CuboidProtoDesignator>(*this);
0232     std::ranges::copy(other.m_binning, std::back_inserter(merged->m_binning));
0233     return merged;
0234   }
0235 
0236   std::unique_ptr<DesignatorBase> merged(
0237       const NullDesignator& /*other*/) const override {
0238     return std::make_unique<CuboidProtoDesignator>(*this);
0239   }
0240 
0241  private:
0242   void validate(Face face, const DirectedProtoAxis& loc0,
0243                 const DirectedProtoAxis& loc1, const std::string& prefix) {
0244     using enum CuboidVolumeBounds::Face;
0245     using enum AxisDirection;
0246 
0247     // For cuboid faces, the valid axes are always X and Y
0248     if (loc0.getAxisDirection() != AxisX || loc1.getAxisDirection() != AxisY) {
0249       throw std::invalid_argument(prefix +
0250                                   "Cuboid faces must use (x, y) binning");
0251     }
0252 
0253     if (std::ranges::find_if(m_binning, [&](const auto& bin) {
0254           return std::get<0>(bin) == face;
0255         }) != m_binning.end()) {
0256       throw std::invalid_argument(prefix + "Cuboid face already configured");
0257     }
0258   }
0259 
0260   std::vector<std::tuple<Face, DirectedProtoAxis, DirectedProtoAxis>> m_binning;
0261 };
0262 
0263 template <typename face_enum_t, typename shell_type_t>
0264 class HomogeneousMaterialDesignator : public DesignatorBase {
0265  public:
0266   using FaceType = face_enum_t;
0267   using ShellType = shell_type_t;
0268 
0269   HomogeneousMaterialDesignator(
0270       FaceType face,
0271       std::shared_ptr<const HomogeneousSurfaceMaterial> material) {
0272     m_materials.emplace_back(face, std::move(material));
0273   }
0274 
0275   std::string label() const override {
0276     return std::string{shellTypeName()} + " HomogeneousMaterialDesignator";
0277   }
0278 
0279   void apply(PortalShellBase& shell, const Logger& logger,
0280              const std::string& prefix) override {
0281     auto* concreteShell = dynamic_cast<ShellType*>(&shell);
0282     if (concreteShell == nullptr) {
0283       ACTS_ERROR(prefix << "Concrete shell type mismatch: configured for "
0284                         << boost::core::demangle(typeid(ShellType).name())
0285                         << " but received "
0286                         << boost::core::demangle(typeid(shell).name()));
0287 
0288       throw std::invalid_argument(prefix + "Concrete shell type mismatch");
0289     }
0290 
0291     for (const auto& [face, material] : m_materials) {
0292       auto* portal = concreteShell->portal(face);
0293       if (portal == nullptr) {
0294         ACTS_ERROR(prefix << "Portal is nullptr");
0295         throw std::runtime_error("Portal is nullptr");
0296       }
0297 
0298       portal->surface().assignSurfaceMaterial(material);
0299     }
0300   }
0301 
0302   constexpr std::string_view shellTypeName() const {
0303     if constexpr (std::is_same_v<ShellType, CylinderPortalShell>) {
0304       return "Cylinder";
0305     } else if constexpr (std::is_same_v<ShellType, CuboidPortalShell>) {
0306       return "Cuboid";
0307     } else {
0308       throw std::runtime_error("Unknown shell type");
0309     }
0310   }
0311 
0312   void graphvizLabel(std::ostream& os) const override {
0313     os << "<br/><i>Homog. " << shellTypeName() << " material</i>";
0314     for (const auto& [face, material] : m_materials) {
0315       os << "<br/> at: " << face;
0316     }
0317   }
0318 
0319   std::unique_ptr<DesignatorBase> merged(
0320       const DesignatorBase& other) const override {
0321     return other.merged(*this);
0322   }
0323 
0324   std::unique_ptr<DesignatorBase> merged(
0325       const HomogeneousMaterialDesignator& other) const override {
0326     auto merged = std::make_unique<HomogeneousMaterialDesignator>(*this);
0327     std::ranges::copy(other.m_materials,
0328                       std::back_inserter(merged->m_materials));
0329     return merged;
0330   }
0331 
0332   std::unique_ptr<DesignatorBase> merged(
0333       const NullDesignator& /*other*/) const override {
0334     return std::make_unique<HomogeneousMaterialDesignator>(*this);
0335   }
0336 
0337  private:
0338   std::vector<
0339       std::pair<FaceType, std::shared_ptr<const HomogeneousSurfaceMaterial>>>
0340       m_materials;
0341 };
0342 
0343 class NullDesignator : public DesignatorBase {
0344  public:
0345   void apply(PortalShellBase& /*shell*/, const Logger& logger,
0346              const std::string& prefix) override {
0347     ACTS_WARNING(prefix << "MaterialDesignator was not configured with any "
0348                         << "material designation! Check your configuration.");
0349   }
0350 
0351   std::string label() const override { return "NullDesignator"; }
0352 
0353   std::unique_ptr<DesignatorBase> merged(
0354       const DesignatorBase& other) const override {
0355     return other.merged(*this);
0356   }
0357 
0358   std::unique_ptr<DesignatorBase> merged(
0359       const CylinderProtoDesignator& other) const override {
0360     return std::make_unique<CylinderProtoDesignator>(other);
0361   }
0362 
0363   std::unique_ptr<DesignatorBase> merged(
0364       const CuboidProtoDesignator& other) const override {
0365     return std::make_unique<CuboidProtoDesignator>(other);
0366   }
0367 
0368   std::unique_ptr<DesignatorBase> merged(
0369       const NullDesignator& /*other*/) const override {
0370     return std::make_unique<NullDesignator>();
0371   }
0372 
0373   std::unique_ptr<DesignatorBase> merged(
0374       const CylinderHomogeneousMaterialDesignator& other) const override {
0375     return other.merged(*this);
0376   }
0377 
0378   std::unique_ptr<DesignatorBase> merged(
0379       const CuboidHomogeneousMaterialDesignator& other) const override {
0380     return other.merged(*this);
0381   }
0382 
0383   void graphvizLabel(std::ostream& os) const override {
0384     os << "<br/><i>NullDesignator</i>";
0385   }
0386 };
0387 
0388 inline std::string mergingError(const DesignatorBase& lhs,
0389                                 const DesignatorBase& rhs) {
0390   return "MaterialDesignator: Merging of " + lhs.label() + " with " +
0391          rhs.label() +
0392          " is not supported. This means you are trying to "
0393          "configure the same face with different binning or "
0394          "materials. Please check your configuration.";
0395 }
0396 
0397 inline std::unique_ptr<DesignatorBase> DesignatorBase::merged(
0398     const CylinderProtoDesignator& other) const {
0399   throw std::runtime_error(mergingError(*this, other));
0400 }
0401 
0402 inline std::unique_ptr<DesignatorBase> DesignatorBase::merged(
0403     const CuboidProtoDesignator& other) const {
0404   throw std::runtime_error(mergingError(*this, other));
0405 }
0406 
0407 inline std::unique_ptr<DesignatorBase> DesignatorBase::merged(
0408     const NullDesignator& other) const {
0409   throw std::runtime_error(mergingError(*this, other));
0410 }
0411 
0412 inline std::unique_ptr<DesignatorBase> DesignatorBase::merged(
0413     const CylinderHomogeneousMaterialDesignator& other) const {
0414   throw std::runtime_error(mergingError(*this, other));
0415 }
0416 
0417 inline std::unique_ptr<DesignatorBase> DesignatorBase::merged(
0418     const CuboidHomogeneousMaterialDesignator& other) const {
0419   throw std::runtime_error(mergingError(*this, other));
0420 }
0421 
0422 }  // namespace Acts::Experimental::detail