Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:23:04

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