Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:05:56

0001 //----------------------------------*-C++-*----------------------------------//
0002 // Copyright 2024 UT-Battelle, LLC, and other Celeritas developers.
0003 // See the top-level COPYRIGHT file for details.
0004 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0005 //---------------------------------------------------------------------------//
0006 //! \file orange/orangeinp/IntersectRegion.hh
0007 //! \brief Contains IntersectRegionInterface and concrete daughters
0008 //---------------------------------------------------------------------------//
0009 #pragma once
0010 
0011 #include "corecel/Macros.hh"
0012 #include "corecel/cont/Array.hh"
0013 #include "corecel/math/Turn.hh"
0014 #include "orange/OrangeTypes.hh"
0015 
0016 namespace celeritas
0017 {
0018 struct JsonPimpl;
0019 
0020 namespace orangeinp
0021 {
0022 class IntersectSurfaceBuilder;
0023 
0024 //---------------------------------------------------------------------------//
0025 /*!
0026  * Interface class for building non-reentrant spatial regions.
0027  *
0028  * This is a building block for constructing more complex objects out of
0029  * smaller spatial regions. A \c shape object will have a single intersect
0030  * region, and a \c solid object region may have multiple adjacent intersect
0031  * regions.
0032  *
0033  * Convex regions should be as minimal as possible and rely on transformations
0034  * to change axes, displacement, etc. As a general rule, the exterior bounding
0035  * box of a intersect region should be <em>centered on the origin</em>, and
0036  * objects should be aligned along the \em z axis.
0037  *
0038  * When implementing this class, prefer to build simpler surfaces (planes)
0039  * before complex ones (cones) in case we implement short-circuiting logic,
0040  * since expressions are currently sorted.
0041  *
0042  * \note Additional methods such as volume calculation may be added here later.
0043  */
0044 class IntersectRegionInterface
0045 {
0046   public:
0047     //! Construct surfaces that are AND-ed into this region
0048     virtual void build(IntersectSurfaceBuilder&) const = 0;
0049 
0050     //! Write the region to a JSON object
0051     virtual void output(JsonPimpl*) const = 0;
0052 
0053   protected:
0054     //!@{
0055     //! Allow construction and assignment only through daughter classes
0056     IntersectRegionInterface() = default;
0057     virtual ~IntersectRegionInterface() = default;
0058     CELER_DEFAULT_COPY_MOVE(IntersectRegionInterface);
0059     //!@}
0060 };
0061 
0062 //---------------------------------------------------------------------------//
0063 /*!
0064  * A rectangular parallelepiped/cuboid centered on the origin.
0065  */
0066 class Box final : public IntersectRegionInterface
0067 {
0068   public:
0069     // Construct with half-widths
0070     explicit Box(Real3 const& halfwidths);
0071 
0072     // Build surfaces
0073     void build(IntersectSurfaceBuilder&) const final;
0074 
0075     // Output to JSON
0076     void output(JsonPimpl*) const final;
0077 
0078     //// ACCESSORS ////
0079 
0080     //! Half-width for each axis
0081     Real3 const& halfwidths() const { return hw_; }
0082 
0083   private:
0084     Real3 hw_;
0085 };
0086 
0087 //---------------------------------------------------------------------------//
0088 /*!
0089  * A closed cone along the Z axis centered on the origin.
0090  *
0091  * A quadric cone technically defines two opposing cones that touch at a single
0092  * vanishing point, but this cone is required to be truncated so that the
0093  * vanishing point is on our outside the cone.
0094  *
0095  * The midpoint along the Z axis of the cone is the origin. A cone is \em not
0096  * allowed to have equal radii: for that, use a cylinder. However, it \em may
0097  * have a single radius of zero, which puts the vanishing point on one end of
0098  * the cone.
0099  *
0100  * This intersect region, along with the Cylinder, is a base component of the
0101  * G4Polycone (PCON).
0102  */
0103 class Cone final : public IntersectRegionInterface
0104 {
0105   public:
0106     // Construct with Z half-height and lo, hi radii
0107     Cone(Real2 const& radii, real_type halfheight);
0108 
0109     //// INTERFACE ////
0110 
0111     // Build surfaces
0112     void build(IntersectSurfaceBuilder&) const final;
0113 
0114     // Output to JSON
0115     void output(JsonPimpl*) const final;
0116 
0117     //// TEMPLATE INTERFACE ////
0118 
0119     // Whether this encloses another cone
0120     bool encloses(Cone const& other) const;
0121 
0122     //// ACCESSORS ////
0123 
0124     //! Lower and upper radii
0125     Real2 const& radii() const { return radii_; }
0126 
0127     //! Half-height along Z
0128     real_type halfheight() const { return hh_; }
0129 
0130   private:
0131     Real2 radii_;
0132     real_type hh_;
0133 };
0134 
0135 //---------------------------------------------------------------------------//
0136 /*!
0137  * A Z-aligned cylinder centered on the origin.
0138  */
0139 class Cylinder final : public IntersectRegionInterface
0140 {
0141   public:
0142     // Construct with radius
0143     Cylinder(real_type radius, real_type halfheight);
0144 
0145     // Build surfaces
0146     void build(IntersectSurfaceBuilder&) const final;
0147 
0148     // Output to JSON
0149     void output(JsonPimpl*) const final;
0150 
0151     //// TEMPLATE INTERFACE ////
0152 
0153     // Whether this encloses another cylinder
0154     bool encloses(Cylinder const& other) const;
0155 
0156     //// ACCESSORS ////
0157 
0158     //! Radius
0159     real_type radius() const { return radius_; }
0160 
0161     //! Half-height along Z
0162     real_type halfheight() const { return hh_; }
0163 
0164   private:
0165     real_type radius_;
0166     real_type hh_;
0167 };
0168 
0169 //---------------------------------------------------------------------------//
0170 /*!
0171  * An axis-alligned ellipsoid centered at the origin.
0172  */
0173 class Ellipsoid final : public IntersectRegionInterface
0174 {
0175   public:
0176     // Construct with radius
0177     explicit Ellipsoid(Real3 const& radii);
0178 
0179     // Build surfaces
0180     void build(IntersectSurfaceBuilder&) const final;
0181 
0182     // Output to JSON
0183     void output(JsonPimpl*) const final;
0184 
0185     //// ACCESSORS ////
0186 
0187     //! Radius along each axis
0188     Real3 const& radii() const { return radii_; }
0189 
0190   private:
0191     Real3 radii_;
0192 };
0193 
0194 //---------------------------------------------------------------------------//
0195 /*!
0196  * A generalized polygon with parallel flat faces along the z axis.
0197  *
0198  * A GenPrism, like VecGeom's GenTrap, ROOT's Arb8, and Geant4's
0199  * G4GenericTrap, represents a generalized volume with polyhedral faces on two
0200  * parallel planes perpendicular to the Z axis. Unlike those other codes, the
0201  * number of faces can be arbitrary in number.
0202  *
0203  * The faces have an orientation and ordering so that \em twisted faces can be
0204  * constructed by joining corresponding points using straight-line "vertical"
0205  * edges, directly matching the G4GenericTrap definition, but using a generic
0206  * quadric expression for each twisted face.
0207  *
0208  * Trapezoids constructed from the helper functions will have sides that are
0209  * same ordering as a prism: the rightward face is first (normal is along the
0210  * +x axis), then the others follow counterclockwise.
0211  */
0212 class GenPrism final : public IntersectRegionInterface
0213 {
0214   public:
0215     //!@{
0216     //! \name Type aliases
0217     using VecReal2 = std::vector<Real2>;
0218     //!@}
0219 
0220     //! Regular trapezoidal top/bottom face
0221     struct TrapFace
0222     {
0223         //! Half the vertical distance between horizontal edges
0224         real_type hy{};
0225         //! Top horizontal edge half-length
0226         real_type hx_lo{};
0227         //! Bottom horizontal edge half-length
0228         real_type hx_hi{};
0229         //! Shear angle, between horizontal line centers and Y axis
0230         Turn alpha;
0231     };
0232 
0233   public:
0234     // Helper function to construct a Trd shape from hz and two rectangles,
0235     // one for each z-face
0236     static GenPrism from_trd(real_type halfz, Real2 const& lo, Real2 const& hi);
0237 
0238     // Helper function to construct a general trap from its half-height and
0239     // the two trapezoids defining its lower and upper faces
0240     static GenPrism from_trap(real_type hz,
0241                               Turn theta,
0242                               Turn phi,
0243                               TrapFace const& lo,
0244                               TrapFace const& hi);
0245 
0246     // Construct from half Z height and 4 vertices for top and bottom planes
0247     GenPrism(real_type halfz, VecReal2 const& lo, VecReal2 const& hi);
0248 
0249     // Build surfaces
0250     void build(IntersectSurfaceBuilder&) const final;
0251 
0252     // Output to JSON
0253     void output(JsonPimpl*) const final;
0254 
0255     //// ACCESSORS ////
0256 
0257     //! Half-height along Z
0258     real_type halfheight() const { return hz_; }
0259 
0260     //! Polygon on -z face
0261     VecReal2 const& lower() const { return lo_; }
0262 
0263     //! Polygon on +z face
0264     VecReal2 const& upper() const { return hi_; }
0265 
0266     //! Number of sides (points on the Z face)
0267     size_type num_sides() const { return lo_.size(); }
0268 
0269     // Calculate the cosine of the twist angle for a given side
0270     real_type calc_twist_cosine(size_type size_idx) const;
0271 
0272   private:
0273     enum class Degenerate
0274     {
0275         none,
0276         lo,
0277         hi
0278     };
0279 
0280     real_type hz_;  //!< half-height
0281     VecReal2 lo_;  //!< corners of the -z face
0282     VecReal2 hi_;  //!< corners of the +z face
0283     Degenerate degen_{Degenerate::none};  //!< no plane on this z axis
0284 };
0285 
0286 //---------------------------------------------------------------------------//
0287 /*!
0288  * An open wedge shape from the Z axis.
0289  *
0290  * The wedge is defined by an interior angle that *must* be less than or equal
0291  * to 180 degrees (half a turn) and *must* be more than zero. It can be
0292  * subtracted, or its negation can be subtracted. The start angle is mapped
0293  * onto [0, 1) on construction.
0294  */
0295 class InfWedge final : public IntersectRegionInterface
0296 {
0297   public:
0298     // Construct from a starting angle and interior angle
0299     InfWedge(Turn start, Turn interior);
0300 
0301     // Build surfaces
0302     void build(IntersectSurfaceBuilder&) const final;
0303 
0304     // Output to JSON
0305     void output(JsonPimpl*) const final;
0306 
0307     //// ACCESSORS ////
0308 
0309     //! Starting angle
0310     Turn start() const { return start_; }
0311 
0312     //! Interior angle
0313     Turn interior() const { return interior_; }
0314 
0315   private:
0316     Turn start_;
0317     Turn interior_;
0318 };
0319 
0320 //---------------------------------------------------------------------------//
0321 /*!
0322  * An involute "blade" centered on the origin.
0323  *
0324  * This is the intersection of two parallel involutes with a cylindrical shell.
0325  * The three radii, which must be in ascending order, are that of the involute,
0326  * the inner cylinder, and the outer cylinder.
0327  *
0328  * The "chirality" of the involute is viewed from the \em +z axis looking down:
0329  * whether it spirals to the right or left.
0330  */
0331 class Involute final : public IntersectRegionInterface
0332 {
0333   public:
0334     // Construct with radius
0335     explicit Involute(Real3 const& radii,
0336                       Real2 const& displacement,
0337                       Chirality chirality,
0338                       real_type halfheight);
0339 
0340     // Build surfaces
0341     void build(IntersectSurfaceBuilder&) const final;
0342 
0343     // Output to JSON
0344     void output(JsonPimpl*) const final;
0345 
0346     //// ACCESSORS ////
0347 
0348     //! Radii: Rdius of involute, minimum radius, maximum radius
0349     Real3 const& radii() const { return radii_; }
0350     //! Displacement angle
0351     Real2 const& displacement_angle() const { return a_; }
0352     //!  Angular bounds of involute
0353     Real2 const& t_bounds() const { return t_bounds_; }
0354     //! Chirality of involute: turning left or right
0355     Chirality chirality() const { return sign_; }
0356     //! Halfheight
0357     real_type halfheight() const { return hh_; }
0358 
0359   private:
0360     Real3 radii_;
0361     Real2 a_;
0362     Real2 t_bounds_;
0363     Chirality sign_;
0364     real_type hh_;
0365 };
0366 
0367 //---------------------------------------------------------------------------//
0368 /*!
0369  * A general parallelepiped centered on the origin.
0370  *
0371  * A parallelepiped is a shape having 3 pairs of parallel faces out of
0372  * which one is parallel with the XY plane (Z faces). All faces are
0373  * parallelograms in the general case. The Z faces have 2 edges parallel
0374  * with the X-axis. Note that all angle parameters are expressed in terms
0375  * of fractions of a 360deg turn.
0376  *
0377  * The shape has the center in the origin and it is defined by:
0378  *
0379  *   - `halfedges:` a 3-vector (dY, dY, dZ) with half-lengths of the
0380  *     projections of the edges on X, Y, Z. The lower Z face is positioned at
0381  *     `-dZ`, and the upper one at `+dZ`.
0382  *   - `alpha:` angle between the segment defined by the centers of the
0383  *     X-parallel edges and Y axis. Validity range is `(-1/4, 1/4)`;
0384  *   - `theta:` polar angle of the shape's main axis, e.g. the segment defined
0385  *     by the centers of the Z faces. Validity range is `[0, 1/4)`;
0386  *   - `phi:` azimuthal angle of the shape's main axis (as explained above).
0387  *     Validity range is `[0, 1)`.
0388  */
0389 class Parallelepiped final : public IntersectRegionInterface
0390 {
0391   public:
0392     // Construct with half widths and 3 angles
0393     Parallelepiped(Real3 const& halfedges, Turn alpha, Turn theta, Turn phi);
0394 
0395     // Build surfaces
0396     void build(IntersectSurfaceBuilder&) const final;
0397 
0398     // Output to JSON
0399     void output(JsonPimpl*) const final;
0400 
0401     //// ACCESSORS ////
0402 
0403     //! Half-lengths of edge projections along each axis
0404     Real3 const& halfedges() const { return hpr_; }
0405     //! Angle between slanted y-edges and the y-axis (in turns)
0406     Turn alpha() const { return alpha_; }
0407     //! Polar angle of main axis (in turns)
0408     Turn theta() const { return theta_; }
0409     //! Azimuthal angle of main axis (in turns)
0410     Turn phi() const { return phi_; }
0411 
0412   private:
0413     // half-lengths
0414     Real3 hpr_;
0415     // angle between slanted y-edges and the y-axis
0416     Turn alpha_;
0417     // polar angle of main axis
0418     Turn theta_;
0419     // azimuthal angle of main axis
0420     Turn phi_;
0421 };
0422 
0423 //---------------------------------------------------------------------------//
0424 /*!
0425  * A regular, z-extruded polygon centered on the origin.
0426  *
0427  * This is the base component of a G4Polyhedra (PGON). The default rotation is
0428  * to put a y-aligned plane on the bottom of the shape, so looking at an x-y
0429  * slice given an apothem \em a, every shape has a surface at \f$ y = -a \f$:
0430  * - n=3 is a triangle with a flat bottom, point up
0431  * - n=4 is a square with axis-aligned sides
0432  * - n=6 is a flat-top hexagon
0433  *
0434  * The "orientation" parameter is a scaled counterclockwise rotation on
0435  * \f$[0, 1)\f$, where zero preserves the orientation described above, and
0436  * unity replicates the original shape but with the "p0" face being where the
0437  * "p1" originally was. With a value of 0.5:
0438  * - n=3 is a downward-pointing triangle
0439  * - n=4 is a diamond
0440  * - n=6 is a pointy-top hexagon
0441  */
0442 class Prism final : public IntersectRegionInterface
0443 {
0444   public:
0445     // Construct with inner radius (apothem), half height, and orientation
0446     Prism(int num_sides,
0447           real_type apothem,
0448           real_type halfheight,
0449           real_type orientation);
0450 
0451     // Build surfaces
0452     void build(IntersectSurfaceBuilder&) const final;
0453 
0454     // Output to JSON
0455     void output(JsonPimpl*) const final;
0456 
0457     //// TEMPLATE INTERFACE ////
0458 
0459     // Whether this encloses another cylinder
0460     bool encloses(Prism const& other) const;
0461 
0462     //// ACCESSORS ////
0463 
0464     //! Number of sides
0465     int num_sides() const { return num_sides_; }
0466     //! Inner radius
0467     real_type apothem() const { return apothem_; }
0468     //! Half the Z height
0469     real_type halfheight() const { return hh_; }
0470     //! Rotation factor
0471     real_type orientation() const { return orientation_; }
0472 
0473   private:
0474     // Number of sides
0475     int num_sides_;
0476 
0477     // Distance from center to midpoint of its side
0478     real_type apothem_;
0479 
0480     // Half the z height
0481     real_type hh_;
0482 
0483     // Rotational offset (0 has bottom face at -Y, 1 is congruent)
0484     real_type orientation_;
0485 };
0486 
0487 //---------------------------------------------------------------------------//
0488 /*!
0489  * A sphere centered on the origin.
0490  *
0491  * \note Be aware there's also a sphere *surface* at orange/surf/Sphere.hh in a
0492  * different namespace.
0493  */
0494 class Sphere final : public IntersectRegionInterface
0495 {
0496   public:
0497     // Construct with radius
0498     explicit Sphere(real_type radius);
0499 
0500     // Build surfaces
0501     void build(IntersectSurfaceBuilder&) const final;
0502 
0503     // Output to JSON
0504     void output(JsonPimpl*) const final;
0505 
0506     //// TEMPLATE INTERFACE ////
0507 
0508     // Whether this encloses another sphere
0509     bool encloses(Sphere const& other) const;
0510 
0511     //// ACCESSORS ////
0512 
0513     //! Radius
0514     real_type radius() const { return radius_; }
0515 
0516   private:
0517     real_type radius_;
0518 };
0519 
0520 //---------------------------------------------------------------------------//
0521 }  // namespace orangeinp
0522 }  // namespace celeritas