Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-13 10:48:06

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