Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //----------------------------------*-C++-*----------------------------------//
0002 // Copyright 2021-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/OrangeTypes.hh
0007 //! \brief Type definitions for ORANGE geometry.
0008 //---------------------------------------------------------------------------//
0009 #pragma once
0010 
0011 #include <cstddef>
0012 #include <functional>
0013 #include <type_traits>
0014 #include <utility>
0015 
0016 #include "corecel/Macros.hh"
0017 #include "corecel/OpaqueId.hh"
0018 #include "corecel/Types.hh"
0019 #include "corecel/cont/Array.hh"
0020 #include "corecel/math/NumericLimits.hh"
0021 #include "geocel/Types.hh"  // IWYU pragma: export
0022 
0023 namespace celeritas
0024 {
0025 //---------------------------------------------------------------------------//
0026 template<class T>
0027 class BoundingBox;
0028 
0029 //---------------------------------------------------------------------------//
0030 // TYPE ALIASES
0031 //---------------------------------------------------------------------------//
0032 
0033 //! Real type used for acceleration
0034 using fast_real_type = float;
0035 
0036 //! Integer type for volume CSG tree representation
0037 using logic_int = size_type;
0038 
0039 //! Helper class for some template dispatch functions
0040 template<Axis T>
0041 using AxisTag = std::integral_constant<Axis, T>;
0042 
0043 //// ID TYPES ////
0044 
0045 //! Identifier for a BIHNode objects
0046 using BIHNodeId = OpaqueId<struct BIHNode_>;
0047 
0048 //! Identifier for a daughter universe
0049 using DaughterId = OpaqueId<struct Daughter>;
0050 
0051 //! Identifier for a face within a volume
0052 using FaceId = OpaqueId<struct Face_, logic_int>;
0053 
0054 //! Bounding box used for acceleration
0055 using FastBBox = BoundingBox<fast_real_type>;
0056 
0057 //! Identifier for a bounding box used for acceleration
0058 using FastBBoxId = OpaqueId<FastBBox>;
0059 
0060 //! Identifier for an array of length three of floating point values
0061 using FastReal3 = Array<float, 3>;
0062 
0063 //! Identifier for the current "level", i.e., depth of embedded universe
0064 using LevelId = OpaqueId<struct Level_>;
0065 
0066 //! Local identifier for a surface within a universe
0067 using LocalSurfaceId = OpaqueId<struct LocalSurface_>;
0068 
0069 //! Local identifier for a geometry volume within a universe
0070 using LocalVolumeId = OpaqueId<struct LocalVolume_>;
0071 
0072 //! Identifier for an OrientedBoundingZone
0073 using OrientedBoundingZoneId = OpaqueId<struct OrientedBoundingZoneRecord>;
0074 
0075 //! Opaque index for "simple unit" data
0076 using SimpleUnitId = OpaqueId<struct SimpleUnitRecord>;
0077 
0078 //! Opaque index for rectilinear array data
0079 using RectArrayId = OpaqueId<struct RectArrayRecord>;
0080 
0081 //! Identifier for a translation of a single embedded universe
0082 using TransformId = OpaqueId<struct TransformRecord>;
0083 
0084 //! Identifier for a relocatable set of volumes
0085 using UniverseId = OpaqueId<struct Universe_>;
0086 
0087 //---------------------------------------------------------------------------//
0088 // ENUMERATIONS
0089 //---------------------------------------------------------------------------//
0090 /*!
0091  * Whether a position is logically "inside" or "outside" a surface.
0092  *
0093  * For a plane, "outside" (true) is the "positive" sense and equivalent to
0094  * \f[
0095    \vec x \cdot \vec n >= 0
0096  * \f]
0097  * and "inside" is to the left of the plane's normal. Likewise, for a
0098  * sphere, "inside" is where the dot product of the position and outward normal
0099  * is negative.
0100  */
0101 enum class Sense : bool
0102 {
0103     inside,  //!< Quadric expression is less than zero
0104     outside,  //!< Expression is greater than zero
0105 };
0106 
0107 //---------------------------------------------------------------------------//
0108 /*!
0109  * Enumeration for mapping surface classes to integers.
0110  *
0111  * These are ordered roughly by complexity. The storage requirement for
0112  * corresponding surfaces are:
0113  * - 1 for `p.|sc|c.c`,
0114  * - 3 for `c.`,
0115  * - 4 for `[ps]|k.`,
0116  * - 7 for `sq`, and
0117  * - 10 for `gq`.
0118  *
0119  * See \c orange/surf/SurfaceTypeTraits.hh for how these map to classes.
0120  */
0121 enum class SurfaceType : unsigned char
0122 {
0123     px,  //!< Plane aligned with X axis
0124     py,  //!< Plane aligned with Y axis
0125     pz,  //!< Plane aligned with Z axis
0126     cxc,  //!< Cylinder centered on X axis
0127     cyc,  //!< Cylinder centered on Y axis
0128     czc,  //!< Cylinder centered on Z axis
0129     sc,  //!< Sphere centered at the origin
0130     cx,  //!< Cylinder parallel to X axis
0131     cy,  //!< Cylinder parallel to Y axis
0132     cz,  //!< Cylinder parallel to Z axis
0133     p,  //!< General plane
0134     s,  //!< Sphere
0135     kx,  //!< Cone parallel to X axis
0136     ky,  //!< Cone parallel to Y axis
0137     kz,  //!< Cone parallel to Z axis
0138     sq,  //!< Simple quadric
0139     gq,  //!< General quadric
0140     inv,  //!< Involute
0141     size_  //!< Sentinel value for number of surface types
0142 };
0143 
0144 //---------------------------------------------------------------------------//
0145 /*!
0146  * Enumeration for mapping transform implementations to integers.
0147  */
0148 enum class TransformType : unsigned char
0149 {
0150     no_transformation,  //!< Identity transform
0151     translation,  //!< Translation only
0152     transformation,  //!< Translation plus rotation
0153     size_
0154 };
0155 
0156 //---------------------------------------------------------------------------//
0157 /*!
0158  * Enumeration for type-deleted universe storage.
0159  *
0160  * See \c orange/univ/UniverseTypeTraits.hh for how these map to data and
0161  * classes.
0162  */
0163 enum class UniverseType : unsigned char
0164 {
0165     simple,
0166     rect_array,
0167 #if 0
0168     hex_array,
0169     dode_array,
0170     ...
0171 #endif
0172     size_  //!< Sentinel value for number of universe types
0173 };
0174 
0175 //---------------------------------------------------------------------------//
0176 /*!
0177  * Evaluated quadric expression allowing for distinct 'on surface' state.
0178  *
0179  * For a plane, "outside" is equivalent to
0180  * \f[
0181    \vec x \cdot \vec n > 0
0182  * \f]
0183  * and "inside" is to the left of the plane's normal (a negative dot product).
0184  * The exact equality to zero is literally an "edge case" but it can happen
0185  * with inter-universe coincident surfaces as well as carefully placed
0186  * particle sources and ray tracing.
0187  *
0188  * As an implementataion detail, the "on" case is currently *exact*, but future
0189  * changes might increase the width of "on" to a finite but small range
0190  * ("fuzziness").
0191  */
0192 enum class SignedSense
0193 {
0194     inside = -1,
0195     on = 0,
0196     outside = 1
0197 };
0198 
0199 //---------------------------------------------------------------------------//
0200 /*!
0201  * When evaluating an intersection, whether the point is on the surface.
0202  *
0203  * This helps eliminate roundoff errors and other arithmetic issues.
0204  */
0205 enum class SurfaceState : bool
0206 {
0207     off = false,
0208     on = true
0209 };
0210 
0211 //---------------------------------------------------------------------------//
0212 /*!
0213  * When crossing a boundary, whether the track exits the current volume.
0214  *
0215  * This is necessary due to changes in direction on the boundary due to
0216  * magnetic field and/or multiple scattering. We could extend this later to a
0217  * flag set of "volume changed" (internal non-reflective crossing), "direction
0218  * changed" (reflecting/periodic), "position changed" (bump/periodic).
0219  */
0220 enum class BoundaryResult : bool
0221 {
0222     reentrant = false,
0223     exiting = true
0224 };
0225 
0226 //---------------------------------------------------------------------------//
0227 /*!
0228  * Chirality of a twirly object (currently only Involute).
0229  */
0230 enum class Chirality : bool
0231 {
0232     left,  //!< Sinistral, spiraling counterclockwise
0233     right,  //!< Dextral, spiraling clockwise
0234 };
0235 
0236 //---------------------------------------------------------------------------//
0237 /*!
0238  * Volume logic encoding.
0239  *
0240  * This uses an *unscoped* enum inside a *namespace* so that its values can be
0241  * freely intermingled with other integers that represent face IDs.
0242  */
0243 namespace logic
0244 {
0245 //! Special logical Evaluator tokens.
0246 // The enum values are set to the highest 6 values of logic_int.
0247 enum OperatorToken : logic_int
0248 {
0249     lbegin = logic_int(~logic_int(6)),
0250     lopen = lbegin,  //!< Open parenthesis
0251     lclose,  //!< Close parenthesis
0252     ltrue,  //!< Push 'true'
0253     lor,  //!< Binary logical OR
0254     land,  //!< Binary logical AND
0255     lnot,  //!< Unary negation
0256     lend
0257 };
0258 }  // namespace logic
0259 
0260 //---------------------------------------------------------------------------//
0261 /*!
0262  * Masking priority.
0263  *
0264  * This is currently not implemented in GPU ORANGE except for the special
0265  * "background" cell and "exterior".
0266  */
0267 enum class ZOrder : size_type
0268 {
0269     invalid = 0,  //!< Invalid region
0270     background,  //!< Implicit fill
0271     media,  //!< Material-filled region or array
0272     array,  //!< Lattice array of nested arrangement
0273     hole,  //!< Another universe masking this one
0274     implicit_exterior = size_type(-2),  //!< Exterior in lower universe
0275     exterior = size_type(-1),  //!< The global problem boundary
0276 };
0277 
0278 //---------------------------------------------------------------------------//
0279 // STRUCTS
0280 //---------------------------------------------------------------------------//
0281 /*!
0282  * Data specifying a daughter universe embedded in a volume.
0283  */
0284 struct Daughter
0285 {
0286     UniverseId universe_id;
0287     TransformId transform_id;
0288 };
0289 
0290 //---------------------------------------------------------------------------//
0291 /*!
0292  * Tolerance for construction and runtime bumping.
0293  *
0294  * The relative error is used for comparisons of magnitudes of values, and the
0295  * absolute error provides a lower bound for the comparison tolerance. In most
0296  * cases (see \c SoftEqual, \c BoundingBoxBumper , \c detail::BumpCalculator)
0297  * the tolerance used is a maximum of the absolute error and the 1- or 2-norm
0298  * of some spatial coordinate. In other cases (\c SurfaceSimplifier, \c
0299  * SoftSurfaceEqual) the similarity between surfaces is determined by solving
0300  * for a change in surface coefficients that results in no more than a change
0301  * in \f$ \epsilon \f$ of a particle intercept. A final special case (the \c
0302  * sqrt_quadratic static variable) is used to approximate the degenerate
0303  * condition \f$ a\sim 0\f$ for a particle traveling nearly parallel to a
0304  * quadric surface: see \c CylAligned for a discussion.
0305  *
0306  * The absolute error should typically be constructed from the relative error
0307  * (since computers use floating point precision) and a characteristic length
0308  * scale for the problem being used. For detector/reactor problems the length
0309  * might be ~1 cm, for microbiology it might be ~1 um, and for astronomy might
0310  * be ~1e6 m.
0311  *
0312  * \note For historical reasons, the absolute tolerance used by \c SoftEqual
0313  * defaults to 1/100 of the relative tolerance, whereas with \c Tolerance the
0314  * equivalent behavior is setting a length scale of 0.01.
0315  *
0316  * \todo Move this to a separate file.
0317  */
0318 template<class T = ::celeritas::real_type>
0319 struct Tolerance
0320 {
0321     using real_type = T;
0322 
0323     real_type rel{};  //!< Relative error for differences
0324     real_type abs{};  //!< Absolute error [native length]
0325 
0326     //! Intercept tolerance for parallel-to-quadric cases
0327     static CELER_CONSTEXPR_FUNCTION real_type sqrt_quadratic()
0328     {
0329         if constexpr (std::is_same_v<real_type, double>)
0330             return 1e-5;
0331         else if constexpr (std::is_same_v<real_type, float>)
0332             return 5e-2f;
0333     }
0334 
0335     //! True if tolerances are valid
0336     CELER_CONSTEXPR_FUNCTION operator bool() const
0337     {
0338         return rel > 0 && rel < 1 && abs > 0;
0339     }
0340 
0341     // Construct from the default relative tolerance (sqrt(precision))
0342     static Tolerance from_default(real_type length = 1);
0343 
0344     // Construct from the default "soft equivalence" relative tolerance
0345     static Tolerance from_softequal();
0346 
0347     // Construct from a relative tolerance and a length scale
0348     static Tolerance from_relative(real_type rel, real_type length = 1);
0349 };
0350 
0351 extern template struct Tolerance<float>;
0352 extern template struct Tolerance<double>;
0353 
0354 //---------------------------------------------------------------------------//
0355 // HELPER FUNCTIONS (HOST/DEVICE)
0356 //---------------------------------------------------------------------------//
0357 /*!
0358  * Convert a boolean value to a Sense enum.
0359  */
0360 CELER_CONSTEXPR_FUNCTION Sense to_sense(bool s)
0361 {
0362     return static_cast<Sense>(s);
0363 }
0364 
0365 //---------------------------------------------------------------------------//
0366 /*!
0367  * Change the sense across a surface.
0368  */
0369 [[nodiscard]] CELER_CONSTEXPR_FUNCTION Sense flip_sense(Sense orig)
0370 {
0371     return static_cast<Sense>(!static_cast<bool>(orig));
0372 }
0373 
0374 //---------------------------------------------------------------------------//
0375 /*!
0376  * Change the sense across a surface.
0377  */
0378 [[nodiscard]] CELER_CONSTEXPR_FUNCTION SignedSense flip_sense(SignedSense orig)
0379 {
0380     using IntT = std::underlying_type_t<SignedSense>;
0381     return static_cast<SignedSense>(-static_cast<IntT>(orig));
0382 }
0383 
0384 //---------------------------------------------------------------------------//
0385 /*!
0386  * Change whether a boundary crossing is reentrant or exiting.
0387  */
0388 [[nodiscard]] CELER_CONSTEXPR_FUNCTION BoundaryResult
0389 flip_boundary(BoundaryResult orig)
0390 {
0391     return static_cast<BoundaryResult>(!static_cast<bool>(orig));
0392 }
0393 
0394 //---------------------------------------------------------------------------//
0395 /*!
0396  * Evaluate the sense based on the LHS expression of the quadric equation.
0397  *
0398  * This is an optimized jump-free version of:
0399  * \code
0400     return quadric == 0 ? SignedSense::on
0401         : quadric < 0 ? SignedSense::inside
0402         : SignedSense::outside;
0403  * \endcode
0404  * as
0405  * \code
0406     int gz = !(quadric <= 0) ? 1 : 0;
0407     int lz = quadric < 0 ? 1 : 0;
0408     return static_cast<SignedSense>(gz - lz);
0409  * \endcode
0410  * and compressed into a single line.
0411  *
0412  * NaN values are treated as "outside".
0413  */
0414 [[nodiscard]] CELER_CONSTEXPR_FUNCTION SignedSense
0415 real_to_sense(real_type quadric)
0416 {
0417     return static_cast<SignedSense>(!(quadric <= 0) - (quadric < 0));
0418 }
0419 
0420 //---------------------------------------------------------------------------//
0421 /*!
0422  * Convert a signed sense to a Sense enum.
0423  */
0424 CELER_CONSTEXPR_FUNCTION Sense to_sense(SignedSense s)
0425 {
0426     return Sense(static_cast<int>(s) >= 0);
0427 }
0428 
0429 //---------------------------------------------------------------------------//
0430 /*!
0431  * Convert a signed sense to a surface state.
0432  */
0433 CELER_CONSTEXPR_FUNCTION SurfaceState to_surface_state(SignedSense s)
0434 {
0435     return s == SignedSense::on ? SurfaceState::on : SurfaceState::off;
0436 }
0437 
0438 //---------------------------------------------------------------------------//
0439 /*!
0440  * Sentinel value indicating "no intersection".
0441  *
0442  * \todo There is probably a better place to put this since it's not a "type".
0443  * \todo A value of zero might also work since zero-length steps are
0444  * prohibited. But we'll need custom `min` and `min_element` in that case.
0445  */
0446 CELER_CONSTEXPR_FUNCTION real_type no_intersection()
0447 {
0448     return numeric_limits<real_type>::infinity();
0449 }
0450 
0451 //---------------------------------------------------------------------------//
0452 /*!
0453  * Return the UniverseId of the highest-level (i.e., root) universe.
0454  */
0455 CELER_CONSTEXPR_FUNCTION UniverseId top_universe_id()
0456 {
0457     return UniverseId{0};
0458 }
0459 
0460 //---------------------------------------------------------------------------//
0461 namespace logic
0462 {
0463 //! Whether an integer is a special logic token.
0464 CELER_CONSTEXPR_FUNCTION bool is_operator_token(logic_int lv)
0465 {
0466     return (lv >= lbegin);
0467 }
0468 }  // namespace logic
0469 
0470 //---------------------------------------------------------------------------//
0471 // HELPER FUNCTIONS (HOST)
0472 //---------------------------------------------------------------------------//
0473 //! Get a printable character corresponding to a sense.
0474 inline constexpr char to_char(Sense s)
0475 {
0476     return s == Sense::inside ? '-' : '+';
0477 }
0478 
0479 // Get a string corresponding to a surface type
0480 char const* to_cstring(SurfaceType);
0481 
0482 // Get a string corresponding to a transform type
0483 char const* to_cstring(TransformType);
0484 
0485 // Get a string corresponding to a signed sense
0486 char const* to_cstring(SignedSense);
0487 
0488 // Get a string corresponding to a surface state
0489 inline char const* to_cstring(SurfaceState s)
0490 {
0491     return s == SurfaceState::off ? "off" : "on";
0492 }
0493 
0494 //! Get a printable character corresponding to an operator.
0495 namespace logic
0496 {
0497 inline constexpr char to_char(OperatorToken tok)
0498 {
0499     return is_operator_token(tok) ? "()*|&~"[tok - lbegin] : '\a';
0500 }
0501 }  // namespace logic
0502 
0503 // Get a string corresponding to a z ordering
0504 char const* to_cstring(ZOrder);
0505 
0506 // Get a printable character corresponding to a z ordering
0507 char to_char(ZOrder z);
0508 
0509 // Convert a printable character to a z ordering
0510 ZOrder to_zorder(char c);
0511 
0512 //---------------------------------------------------------------------------//
0513 }  // namespace celeritas
0514 
0515 //---------------------------------------------------------------------------//
0516 // STD::HASH SPECIALIZATION FOR HOST CODE
0517 //---------------------------------------------------------------------------//
0518 //! \cond
0519 namespace std
0520 {
0521 //! Specialization for std::hash for unordered storage.
0522 template<>
0523 struct hash<celeritas::Sense>
0524 {
0525     using argument_type = celeritas::Sense;
0526     using result_type = std::size_t;
0527     result_type operator()(argument_type const& sense) const noexcept
0528     {
0529         return std::hash<bool>()(static_cast<bool>(sense));
0530     }
0531 };
0532 }  // namespace std
0533 //! \endcond