Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-29 09:13:54

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 geocel/GeoTrackInterface.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include <functional>
0010 
0011 #include "corecel/Config.hh"
0012 
0013 #include "corecel/Macros.hh"
0014 #include "corecel/cont/Array.hh"
0015 #include "corecel/cont/Span.hh"
0016 #include "corecel/math/ArrayUtils.hh"
0017 
0018 #include "Types.hh"
0019 
0020 namespace celeritas
0021 {
0022 //---------------------------------------------------------------------------//
0023 /*!
0024  * Standard interface to geometry navigation for a track for testing on CPU.
0025  * \tparam RealType Floating point precision
0026  *
0027  * \note This class is for illustrative and testing purposes \b only
0028  *   (see celeritas::test::WrappedGeoTrackView) and is
0029  *   \b not used during the main Celeritas execution. The geometry there is
0030  *   determined by the \c CELERITAS_CORE_GEO configuration variable and defined
0031  *   as a type alias \c celeritas::CoreGeoTrackView .
0032  *
0033  * Initialization is performed via the assignment operator using a \c
0034  * GeoTrackInitializer.
0035  *
0036  * - Initialization may fail, leaving the track with an "error" status.
0037  * - Some implementations allow initialization on a boundary, leaving the track
0038  *   in an "outgoing from boundary" state (i.e., the next step is into the
0039  *   volume the track initializes inside).
0040  * - Some implementations allow initialization to succeed but be in an
0041  *   unphysical part of the geometry (e.g., ORANGE exterior volume). In this
0042  *   case, the canonical volume ID will be null, indicating no
0043  *   corresponding user-defined geometry region.
0044  *
0045  * Tracking to and across volumes along a straight line requires a specific
0046  * sequence of calls.
0047  *
0048  * - Locate the boundary crossing along the current direction with \c
0049  *   find_next_step.
0050  * - Move within the current volume, not crossing a boundary, via \c
0051  *   move_internal or \c move_to_boundary.
0052  * - If on a boundary, \c normal can be used to calculate the current surface
0053  *   normal, but its dot product with the track direction may not be
0054  *   meaningful. Use \c geo_status to determine whether the track is incident
0055  *   to or outgoing from the boundary.
0056  * - If incident into the boundary, change volumes ("relocate") with \c
0057  *   cross_boundary.  The post-crossing status can be \c error, \c
0058  *   boundary_out, or \c invalid. Some geometries represent the exterior as a
0059  *   null canonical VolumeId, and some as an invalid state.
0060  *
0061  * \note The free function \c is_on_boundary will be true of the geo status
0062  * both before \em and after the call to \c cross_boundary, and the surface
0063  * normal can be calculated in both cases.
0064  *
0065  * Movement to a nearby but arbitrary point can be done inside a
0066  * "safety" distance:
0067  *
0068  * - Locate the closest point on the boundary in any direction with \c
0069  *   find_safety.
0070  * - Change the direction with \c set_dir. (Note that this will always
0071  *   invalidate the linear "next step".)
0072  * - Move to a point with \c move_internal.
0073  *
0074  * Neither accessors nor mutators should be called in an \c invalid state.
0075  * It is allowable but potentially dangerous to call accessors in an \c error
0076  * state.
0077  */
0078 template<class RealType = ::celeritas::real_type>
0079 class GeoTrackInterface
0080 {
0081   public:
0082     //!@{
0083     //! \name Type aliases
0084     using Initializer_t = GeoTrackInitializer;
0085     using real_type = RealType;
0086     using Real3 = Array<real_type, 3>;
0087     using VolPathVisitor = std::function<void(VolumeLevelId, VolumeInstanceId)>;
0088     //!@}
0089 
0090   public:
0091     // Anchor virtual destructor in GeoInterface.cc
0092     virtual ~GeoTrackInterface() = 0;
0093 
0094     /*!
0095      * Initialize the state.
0096      *
0097      * Takes a \c GeoTrackInitializer object to locate the point in the
0098      * geometry hierarchy.
0099      *
0100      * \post \c geo_status() is never \c GeoStatus::boundary_inc : the
0101      *   result is \c interior (placed inside a volume), \c boundary_out
0102      *   (placed on a boundary with direction heading away from it), or \c
0103      *   error (volume not found).
0104      */
0105     virtual GeoTrackInterface& operator=(Initializer_t const& init) = 0;
0106 
0107     //!@{
0108     //! \name Physical state
0109 
0110     //! Return the physical position in the global coordinate system
0111     virtual Real3 const& pos() const = 0;
0112     //! Return the direction in the global coordinate system
0113     virtual Real3 const& dir() const = 0;
0114 
0115     //!@}
0116     //!@{
0117     //! \name Canonical volume state
0118     //! \pre The geo status cannot be \c GeoStatus::invalid
0119 
0120     //! Get the canonical volume ID in the current impl volume
0121     virtual VolumeId volume_id() const = 0;
0122     //! Get the physical volume ID in the current cell
0123     virtual VolumeInstanceId volume_instance_id() const = 0;
0124     //! Get the distance from root volume in the geometry hierarchy
0125     virtual VolumeLevelId volume_level() const = 0;
0126     //! Get the volume instance ID for all levels
0127     virtual void volume_instance_id(Span<VolumeInstanceId> levels) const = 0;
0128     //! Visit each volume level in the path
0129     virtual void foreach_volume_path(VolPathVisitor visit) const = 0;
0130 
0131     /*!
0132      * Whether the track is outside the valid geometry region.
0133      *
0134      * Returns true if the track has left the world (or started outside the
0135      * outermost known volume).
0136      *
0137      * \deprecated Check \c geo.geo_status() is not \c invalid and evaluate \c
0138      * is_outside(geo.volume_id())
0139      */
0140     virtual bool is_outside() const = 0;
0141     //!@}
0142 
0143     //! Get the implementation volume ID
0144     virtual ImplVolumeId impl_volume_id() const = 0;
0145 
0146     /*!
0147      * Whether the last operation resulted in an error.
0148      *
0149      * \deprecated check \c geo_status for \c GeoStatus::error instead.
0150      */
0151     virtual bool failed() const = 0;
0152 
0153     //!@{
0154     //! \name Surface state
0155 
0156     /*!
0157      * Whether the track is exactly on a surface.
0158      *
0159      * Returns true if a track is exactly on the boundary of a volume, capable
0160      * of changing to another volume without altering the physical position.
0161      *
0162      * \deprecated use \c is_on_boundary(geo.geo_status())
0163      */
0164     virtual bool is_on_boundary() const = 0;
0165 
0166     /*!
0167      * Calculate the normal vector on the current surface.
0168      *
0169      * Returns a global-coordinate direction perpendicular to the volume at
0170      * the local point when on a boundary. The sign of the surface normal is
0171      * implementation-dependent; it may change based on the track state
0172      * (previous volume, direction, surface sign) or geometry construction.
0173      *
0174      * \pre \c is_on_boundary(geo.geo_status()) must be true
0175      */
0176     virtual Real3 normal() const = 0;
0177 
0178     /*!
0179      * Derive the geometry state from the existing state flags.
0180      *
0181      * This is a shim for geometry implementations that do not natively track
0182      * the full \c GeoStatus. When on a boundary, it \b assumes the normal
0183      * vector is oriented "outward" from the current volume.
0184      * The dot product of the track direction and the surface normal determines
0185      * whether the track is incident to the boundary (positive: headed outward
0186      * from the volume) or incident (negative: headed into the volume).
0187      */
0188     virtual GeoStatus geo_status() const
0189     {
0190         if (this->failed())
0191             return GeoStatus::error;
0192         if (this->is_on_boundary())
0193         {
0194             return dot_product(this->dir(), this->normal()) >= 0
0195                        ? GeoStatus::boundary_inc
0196                        : GeoStatus::boundary_out;
0197         }
0198         return GeoStatus::interior;
0199     }
0200 
0201     //!@}
0202     //!@{
0203     //! \name Straight-line movement and boundary crossing
0204 
0205     /*!
0206      * Find the distance to the next boundary, up to and including a step.
0207      *
0208      * Determines the distance to the next boundary along the track's current
0209      * direction, up to a given distance. Queries may be more efficient for
0210      * small distances.
0211      *
0212      * \todo Revisit whether to allow \c geo_status() to be
0213      * \c GeoStatus::boundary_inc , or to reconsider \c geo_status entirely
0214      *
0215      * \post The returned distance is in the range \c [0, max_step] .
0216      * A zero distance must indicate a boundary hit, e.g. within the geometry's
0217      * surface tolerance. Call move_to_boundary followed by cross_boundary to
0218      * resolve the hit even when no physical displacement is needed.
0219      */
0220     virtual Propagation find_next_step(real_type max_step) = 0;
0221 
0222     /*!
0223      * Move within the volume along a straight line.
0224      *
0225      * Changes the physical position of the geometry state without altering
0226      * the logical state (i.e., it must remain within the current volume).
0227      *
0228      * \pre The given \c step must be less than or equal to the previous \c
0229      * find_next_step result and can only be equal if the endpoint is not on a
0230      * boundary.
0231      */
0232     virtual void move_internal(real_type step) = 0;
0233 
0234     /*!
0235      * Move to the boundary in preparation for crossing it.
0236      *
0237      * Moves the track to the boundary of the current volume along the current
0238      * direction, updating its logical state to indicate that it is on the
0239      * boundary of the current volume.
0240      *
0241      * \pre \c geo_status() is not \c GeoStatus::boundary_inc .
0242      * \post \c geo_status() is \c GeoStatus::boundary_inc .
0243      */
0244     virtual void move_to_boundary() = 0;
0245 
0246     /*!
0247      * Cross from one side of the current surface to the other.
0248      *
0249      * Changes the logical state when on the boundary, updating to the next
0250      * volume.
0251      *
0252      * \pre \c geo_status() is \c GeoStatus::boundary_inc .
0253      * \post \c geo_status() is \c GeoStatus::boundary_out , or \c
0254      *   GeoStatus::error if the new volume could not be found.
0255      */
0256     virtual void cross_boundary() = 0;
0257     //!@}
0258     //!@{
0259     //! \name Locally bounded movement
0260 
0261     /*!
0262      * Find the safety distance at the current position.
0263      *
0264      * Determines the distance to the nearest boundary in any direction (i.e.,
0265      * the radius of the maximally inscribed sphere).
0266      *
0267      * \c deprecated: use \c find_safety(inf) (REMOVE in v0.8)
0268      */
0269     virtual real_type find_safety() = 0;
0270 
0271     /*!
0272      * Find the safety at the current position, up to a maximum step distance.
0273      *
0274      * The resulting safety should be no larger than the maximum step.
0275      *
0276      * \pre \c is_on_boundary(geo.geo_status()) must be false
0277      */
0278     virtual real_type find_safety(real_type max_step) = 0;
0279 
0280     /*!
0281      * Change direction.
0282      *
0283      * Changes the direction of the track (in global coordinate system).
0284      */
0285     virtual void set_dir(Real3 const& newdir) = 0;
0286 
0287     /*!
0288      * Move within the volume to a specific point.
0289      *
0290      * Changes the physical position of the geometry state without altering
0291      * the logical state (i.e., it must remain within the current volume).
0292      * The original and updated points \em must be path-connected: a line can
0293      * be drawn between them entirely within the current volume.
0294      */
0295     virtual void move_internal(Real3 const& pos) = 0;
0296     //!@}
0297 
0298   protected:
0299     GeoTrackInterface() = default;
0300     CELER_DEFAULT_COPY_MOVE(GeoTrackInterface);
0301 };
0302 
0303 //---------------------------------------------------------------------------//
0304 #if CELERITAS_REAL_TYPE == CELERITAS_REAL_TYPE_FLOAT
0305 extern template class GeoTrackInterface<float>;
0306 #endif
0307 extern template class GeoTrackInterface<double>;
0308 
0309 //---------------------------------------------------------------------------//
0310 }  // namespace celeritas