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/VolumePathAccumulator.hh
0006 //! \sa test/geocel/Volume.test.cc
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include "corecel/Assert.hh"
0011 #include "corecel/Macros.hh"
0012 
0013 #include "VolumeData.hh"
0014 
0015 namespace celeritas
0016 {
0017 //---------------------------------------------------------------------------//
0018 /*!
0019  * Incrementally compute the unique ID of a path in the volume hierarchy.
0020  *
0021  * Each \c VolumeUniqueInstanceId uniquely identifies a root-to-node path
0022  * (i.e., a Geant4 "touchable") in the volume DAG.  This class computes the ID
0023  * on the fly without allocating a path buffer: call \c operator() once for
0024  * each \c VolumeInstanceId encountered while descending from the world volume,
0025  * passing the current accumulated ID and receiving the updated one.
0026  *
0027  * For a volume instance \c vi at position \c k in its
0028  * parent volume's children list, the offset is the sum of
0029  * \c num_desc(volume(vj)) for all preceding siblings \c vj (positions
0030  * 0..k-1), where \c num_desc(V) counts the total number of unique paths
0031  * ending at any node in V's subtree (including V itself).
0032  * For a path \f$[vi_0, vi_1, \ldots, vi_k]\f$ the unique instance ID is
0033  * \f[
0034  *   \text{uid} = \sum_{i=0}^{k} \bigl(\text{offset}[vi_i] + 1\bigr).
0035  * \f]
0036  * The empty path (the world volume itself, with no enclosing instance) maps
0037  * to ID 0 (see \c world_unique_instance ).
0038  *
0039  * \par Example:
0040  * \code
0041    VolumePathAccumulator accum{params.host_ref()};
0042    VolumeUniqueInstanceId uid = world_unique_instance;
0043    for (VolumeInstanceId vi : path_below_world)
0044    {
0045        uid = accum(uid, vi);  // unique ID for the node reached via this step
0046    }
0047  * \endcode
0048  *
0049  * or, if it's easier to include the world as part of the path (using unsigned
0050  * integer overflow that's part of the OpaqueId implementation), or if the path
0051  * might be "empty" to indicate being outside:
0052  * \code
0053    VolumePathAccumulator accum{params.host_ref()};
0054    VolumeUniqueInstanceId uid;
0055    for (VolumeInstanceId vi : path_including_world)
0056    {
0057        uid = accum(uid, vi);  // unique ID for the node reached via this step
0058    }
0059  * \endcode
0060 
0061  *
0062  * \internal The mapping relies on \c unique_instance_offsets precomputed in
0063  * \c VolumeParamsData.
0064  */
0065 class VolumePathAccumulator
0066 {
0067   public:
0068     //!@{
0069     //! \name Type aliases
0070     using ParamsRef = NativeCRef<VolumeParamsData>;
0071     //!@}
0072 
0073   public:
0074     //! Construct from volume hierarchy data
0075     explicit CELER_FUNCTION VolumePathAccumulator(ParamsRef const& params)
0076         : params_(params)
0077     {
0078     }
0079 
0080     // Descend one level: add offset[vi]+1 to uid and return the result
0081     inline CELER_FUNCTION VolumeUniqueInstanceId operator()(
0082         VolumeUniqueInstanceId uid, VolumeInstanceId vi) const;
0083 
0084   private:
0085     ParamsRef const& params_;
0086 };
0087 
0088 //---------------------------------------------------------------------------//
0089 // INLINE DEFINITIONS
0090 //---------------------------------------------------------------------------//
0091 /*!
0092  * Accumulate the contribution of one path step and return the updated ID.
0093  *
0094  * The result after \f$k\f$ calls equals the \c VolumeUniqueInstanceId of the
0095  * node reached via the first \f$k\f$ instances in the path.
0096  */
0097 CELER_FUNCTION VolumeUniqueInstanceId VolumePathAccumulator::operator()(
0098     VolumeUniqueInstanceId uid, VolumeInstanceId vi) const
0099 {
0100     CELER_EXPECT(vi < params_.unique_instance_offsets.size());
0101     auto const offset = params_.unique_instance_offsets[vi];
0102     return VolumeUniqueInstanceId(*uid + offset.get() + 1);
0103 }
0104 
0105 //---------------------------------------------------------------------------//
0106 }  // namespace celeritas