File indexing completed on 2025-06-21 08:08:55
0001
0002
0003
0004
0005
0006
0007
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& ) 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
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& ) 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
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& ) 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& , 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& ) 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 }