Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-17 08:18:59

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file orange/orangeinp/Solid.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include <optional>
0010 #include <type_traits>
0011 #include <utility>
0012 #include <vector>
0013 
0014 #include "corecel/math/Turn.hh"
0015 
0016 #include "IntersectRegion.hh"
0017 #include "ObjectInterface.hh"
0018 
0019 namespace celeritas
0020 {
0021 namespace orangeinp
0022 {
0023 //---------------------------------------------------------------------------//
0024 /*!
0025  * Define the azimuthal truncation of a solid.
0026  *
0027  * This is a pie slice infinite along the z axis and outward from it. Its cross
0028  * section is in the \em x-y plane, and a start
0029  * angle of zero corresponding to the \em +x axis. An interior angle of one
0030  * results in no radial exclusion from the resulting solid. A interior angle of
0031  * more than 0.5 turns (180 degrees) results in a wedge being subtracted from
0032  * the solid, and an angle of less than or equal to 0.5 turns results in the
0033  * intersection of the solid with a wedge.
0034  *
0035  * \code
0036   // Truncates a solid to the east-facing quadrant:
0037   EnclosedAzi{Turn{-0.125}, Turn{0.125}};
0038   // Removes the second quadrant (northwest) from a solid:
0039   EnclosedAzi{Turn{0.50}, Turn{1.25}};
0040   \endcode
0041  */
0042 class EnclosedAzi
0043 {
0044   public:
0045     //!@{
0046     //! \name Type aliases
0047     using SenseWedge = std::pair<Sense, InfAziWedge>;
0048     //!@}
0049 
0050   public:
0051     //! Default to "all angles"
0052     EnclosedAzi() = default;
0053 
0054     // Construct from a starting angle and stop angle
0055     EnclosedAzi(Turn start, Turn stop);
0056 
0057     // Construct a wedge shape to intersect (inside) or subtract (outside)
0058     SenseWedge make_sense_region() const;
0059 
0060     // Whether the enclosed angle is not a full circle
0061     constexpr explicit inline operator bool() const;
0062 
0063     //! Starting angle
0064     Turn start() const { return start_; }
0065 
0066     //! stop angle
0067     Turn stop() const { return stop_; }
0068 
0069   private:
0070     Turn start_{0};
0071     Turn stop_{1};
0072 };
0073 
0074 //---------------------------------------------------------------------------//
0075 /*!
0076  * Define the polar truncation of a solid.
0077  *
0078  * This subtracts up to two infinite cones centered along the z axis from the
0079  * origin.
0080  *
0081  * A start angle of zero corresponding to the \em +z axis. An interior angle of
0082  * 0.5 results in no exclusion from the resulting solid.
0083  * \code
0084   // Truncates a solid to the top hemisphere (no cones, just equatorial plane)
0085   EnclosedPolar{Turn{0}, Turn{0.25}};
0086   // Truncates a solid to northern latitudes (intersect two cones and a plane)
0087   EnclosedPolar{Turn{0.15}, Turn{0.2}};
0088   // Truncates a solid to an equatorial region (18 degrees N to 36 S: the union
0089   // of two polar wedge cones)
0090   EnclosedPolar{Turn{0.2}, Turn{0.35}};
0091   \endcode
0092  */
0093 class EnclosedPolar
0094 {
0095   public:
0096     //!@{
0097     //! \name Type aliases
0098     using VecPolarWedge = std::vector<InfPolarWedge>;
0099     //!@}
0100 
0101   public:
0102     //! Default to "all angles"
0103     EnclosedPolar() = default;
0104 
0105     // Construct from a starting angle and stop angle
0106     EnclosedPolar(Turn start, Turn stop);
0107 
0108     // Construct one or two wedges to union then intersect with the solid
0109     VecPolarWedge make_regions() const;
0110 
0111     // Whether the enclosed angle is not a full circle
0112     constexpr explicit inline operator bool() const;
0113 
0114     //! Starting angle
0115     Turn start() const { return start_; }
0116 
0117     //! stop angle
0118     Turn stop() const { return stop_; }
0119 
0120   private:
0121     Turn start_{0};
0122     Turn stop_{0.5};
0123 };
0124 
0125 //---------------------------------------------------------------------------//
0126 /*!
0127  * A hollow shape with an optional start and end angle.
0128  *
0129  * Solids are a shape with (optionally) the same *kind* of shape subtracted
0130  * from it, and (optionally) an azimuthal section removed from it.
0131  */
0132 class SolidBase : public ObjectInterface
0133 {
0134   public:
0135     // Construct a volume from this object
0136     NodeId build(VolumeBuilder&) const final;
0137 
0138     // Write the shape to JSON
0139     void output(JsonPimpl*) const final;
0140 
0141     //! Interior intersect region interface for construction and access
0142     virtual IntersectRegionInterface const& interior() const = 0;
0143 
0144     //! Optional excluded region
0145     virtual IntersectRegionInterface const* excluded() const = 0;
0146 
0147     //! Optional azimuthal angular restriction
0148     virtual EnclosedAzi const& enclosed_azi() const = 0;
0149 
0150     //! Optional polar angular restriction
0151     virtual EnclosedPolar const& enclosed_polar() const = 0;
0152 
0153     ~SolidBase() override = default;
0154 
0155   protected:
0156     //!@{
0157     //! Allow construction and assignment only through daughter classes
0158     SolidBase() = default;
0159     CELER_DEFAULT_COPY_MOVE(SolidBase);
0160     //!@}
0161 };
0162 
0163 //---------------------------------------------------------------------------//
0164 /*!
0165  * A shape that has undergone an intersection or combination of intersections.
0166  *
0167  * This shape may be:
0168  * A) hollow (excluded interior),
0169  * B) truncated azimuthally (enclosed angle),
0170  * C) truncated in z (intersected with z-slab),
0171  * D) both A and B.
0172  *
0173  * Examples: \code
0174    // A cone with a thickness of 0.1
0175    Solid s{"cone", Cone{{1, 2}, 10.0}, Cone{{0.9, 1.9}, 10.0}};
0176    // A cylinder segment in z={-2.5, 2.5}, r={0.5, 0.75}, theta={-45, 45} deg
0177    Solid s{"cyl", Cylinder{0.75, 5.0}, Cylinder{0.5, 5.0},
0178            {Turn{0}, Turn{0.25}};
0179    // The east-facing quarter of a cone shape
0180    Solid s{"cone", Cone{{1, 2}, 10.0}, {Turn{-0.125}, Turn{0.25}};
0181  * \endcode
0182  */
0183 template<class T>
0184 class Solid final : public SolidBase
0185 {
0186     static_assert(std::is_base_of_v<IntersectRegionInterface, T>);
0187 
0188   public:
0189     //!@{
0190     //! \name Type aliases
0191     using OptionalRegion = std::optional<T>;
0192     //!@}
0193 
0194   public:
0195     // Return a solid *or* shape given an optional interior or enclosed angle
0196     static SPConstObject or_shape(std::string&& label,
0197                                   T&& interior,
0198                                   OptionalRegion&& excluded = {},
0199                                   EnclosedAzi&& enclosed = {},
0200                                   EnclosedPolar&& polar = {});
0201 
0202     // Construct with everything
0203     Solid(std::string&& label,
0204           T&& interior,
0205           OptionalRegion&& excluded,
0206           EnclosedAzi&& enclosed,
0207           EnclosedPolar&& polar);
0208 
0209     //! Get the user-provided label
0210     std::string_view label() const final { return label_; }
0211 
0212     //! Interior intersect region interface for construction and access
0213     IntersectRegionInterface const& interior() const final
0214     {
0215         return interior_;
0216     }
0217 
0218     // Optional excluded
0219     IntersectRegionInterface const* excluded() const final;
0220 
0221     //! Optional azimuthal restriction
0222     EnclosedAzi const& enclosed_azi() const final { return azi_; }
0223 
0224     //! Optional polar restriction
0225     EnclosedPolar const& enclosed_polar() const final { return polar_; }
0226 
0227   private:
0228     std::string label_;
0229     T interior_;
0230     OptionalRegion exclusion_;
0231     EnclosedAzi azi_;
0232     EnclosedPolar polar_;
0233 };
0234 
0235 //---------------------------------------------------------------------------//
0236 // DEDUCTION GUIDES
0237 //---------------------------------------------------------------------------//
0238 
0239 template<class T, class... Us>
0240 Solid(std::string&&, T&&, Us...) -> Solid<T>;
0241 
0242 //---------------------------------------------------------------------------//
0243 // TYPE ALIASES
0244 //---------------------------------------------------------------------------//
0245 
0246 using ConeSolid = Solid<Cone>;
0247 using CylinderSolid = Solid<Cylinder>;
0248 using PrismSolid = Solid<Prism>;
0249 using SphereSolid = Solid<Sphere>;
0250 using EllipsoidSolid = Solid<Ellipsoid>;
0251 
0252 //---------------------------------------------------------------------------//
0253 // EXPLICIT INSTANTIATION
0254 //---------------------------------------------------------------------------//
0255 
0256 extern template class Solid<Cone>;
0257 extern template class Solid<Cylinder>;
0258 // TODO: hyperboloid
0259 extern template class Solid<Prism>;
0260 extern template class Solid<Sphere>;
0261 
0262 //---------------------------------------------------------------------------//
0263 // INLINE DEFINITIONS
0264 //---------------------------------------------------------------------------//
0265 /*!
0266  * Whether the enclosed angle is not a full circle.
0267  *
0268  * Note that the constructor does not allow a full circle, so only the default
0269  * constructor can set values of zero and 1.
0270  */
0271 constexpr EnclosedAzi::operator bool() const
0272 {
0273     return !(start_ == Turn{0} && stop_ == Turn{1});
0274 }
0275 
0276 //---------------------------------------------------------------------------//
0277 /*!
0278  * Whether the enclosed angle is less than the whole polar range.
0279  */
0280 constexpr EnclosedPolar::operator bool() const
0281 {
0282     return !(start_ == Turn{0} && stop_ == Turn{0.5});
0283 }
0284 
0285 //---------------------------------------------------------------------------//
0286 /*!
0287  * Access the optional excluded.
0288  */
0289 template<class T>
0290 IntersectRegionInterface const* Solid<T>::excluded() const
0291 {
0292     return exclusion_ ? &(*exclusion_) : nullptr;
0293 }
0294 
0295 //---------------------------------------------------------------------------//
0296 }  // namespace orangeinp
0297 }  // namespace celeritas