Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-27 09:40:38

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/detail/BvhEnclosingVolFinder.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include "corecel/cont/IdStack.hh"
0010 #include "orange/OrangeTypes.hh"
0011 
0012 #include "BvhView.hh"
0013 
0014 namespace celeritas
0015 {
0016 namespace detail
0017 {
0018 //---------------------------------------------------------------------------//
0019 /*!
0020  * Traverse the BVH tree to find a volume that contains a point.
0021  *
0022  * Traversal is carried out using a depth-first search and terminated as soon
0023  * as a suitable volume is found. When visiting a leaf node, the bounding boxes
0024  * of leaf volumes are tested (inexpensive) before testing the leaf volumes
0025  * themselves (expensive). Determining if the point is enclosed by the volume
0026  * itself is done with a supplied predicate, which can also be used to exclude
0027  * volumes based on more stringent criteria. For example, for surface crossing
0028  * operations, a predicate that excludes the volume a particle is in prior to
0029  * the crossing may be used.
0030  *
0031  * \todo move to top-level orange directory out of detail namespace
0032  */
0033 class BvhEnclosingVolFinder
0034 {
0035   public:
0036     //!@{
0037     //! \name Type aliases
0038     using Storage = NativeCRef<BvhTreeData>;
0039     //!@}
0040 
0041     // Construct from vector of bounding boxes and storage for LocalVolumeIds
0042     inline CELER_FUNCTION BvhEnclosingVolFinder(BvhTreeRecord const& tree,
0043                                                 Storage const& storage);
0044 
0045     // Find a volume that satisfies is_inside
0046     template<class F>
0047     inline CELER_FUNCTION LocalVolumeId operator()(Real3 const& pos,
0048                                                    F&& is_inside) const;
0049 
0050   private:
0051     //// DATA ////
0052     BvhView view_;
0053 
0054     //// HELPER FUNCTIONS ////
0055 
0056     // Determine if any leaf node volumes contain the point
0057     template<class F>
0058     inline CELER_FUNCTION LocalVolumeId visit_leaf(BvhNodeId leaf_id,
0059                                                    F&& is_inside) const;
0060 
0061     // Determine if any inf_vols contain the point
0062     template<class F>
0063     inline CELER_FUNCTION LocalVolumeId visit_inf_vols(F&& is_inside) const;
0064 
0065     // Determine if a single bbox contains the point
0066     inline CELER_FUNCTION bool visit_bbox(LocalVolumeId const& id,
0067                                           Real3 const& pos) const;
0068 };
0069 
0070 //---------------------------------------------------------------------------//
0071 // INLINE DEFINITIONS
0072 //---------------------------------------------------------------------------//
0073 /*!
0074  * Construct from vector of bounding boxes and storage.
0075  */
0076 CELER_FUNCTION BvhEnclosingVolFinder::BvhEnclosingVolFinder(
0077     BvhTreeRecord const& tree, Storage const& storage)
0078     : view_(tree, storage)
0079 {
0080 }
0081 
0082 //---------------------------------------------------------------------------//
0083 /*!
0084  * Find a volume that satisfies is_inside_vol.
0085  */
0086 template<class F>
0087 CELER_FUNCTION LocalVolumeId BvhEnclosingVolFinder::operator()(
0088     Real3 const& pos, F&& is_inside_vol) const
0089 {
0090     using Side = BvhInternalNode::Side;
0091 
0092     // Stack of deferred nodes
0093     using StackT = IdStack<BvhNodeId, max_bvh_depth - 1>;
0094     BvhNodeId stack_spill_[StackT::spill_extent];
0095     StackT stack{stack_spill_};
0096     stack.push(BvhNodeId{0});
0097 
0098     while (!stack.empty())
0099     {
0100         if (!view_.is_internal(stack.top()))
0101         {
0102             auto id = this->visit_leaf(stack.top(), is_inside_vol);
0103             stack.pop();
0104 
0105             if (id)
0106             {
0107                 return id;
0108             }
0109         }
0110         else
0111         {
0112             auto const& node = view_.inner_node(stack.top());
0113             stack.pop();
0114             for (auto s : {Side::right, Side::left})
0115             {
0116                 if (is_inside(node.bbox(s), pos))
0117                 {
0118                     stack.push(node.child(s));
0119                 }
0120             }
0121         }
0122     }
0123 
0124     return this->visit_inf_vols(is_inside_vol);
0125 }
0126 
0127 //---------------------------------------------------------------------------//
0128 // HELPER FUNCTIONS
0129 //---------------------------------------------------------------------------//
0130 /*!
0131  * Determine if any leaf node volumes contain the point.
0132  */
0133 template<class F>
0134 CELER_FUNCTION LocalVolumeId BvhEnclosingVolFinder::visit_leaf(
0135     BvhNodeId leaf_id, F&& is_inside) const
0136 {
0137     for (auto id : view_.leaf_vol_ids(leaf_id))
0138     {
0139         if (is_inside(id))
0140         {
0141             return id;
0142         }
0143     }
0144     return LocalVolumeId{};
0145 }
0146 
0147 //---------------------------------------------------------------------------//
0148 /*!
0149  * Determine if any volumes in inf_vols contain the point.
0150  */
0151 template<class F>
0152 CELER_FUNCTION LocalVolumeId BvhEnclosingVolFinder::visit_inf_vols(
0153     F&& is_inside) const
0154 {
0155     for (auto id : view_.inf_vol_ids())
0156     {
0157         if (is_inside(id))
0158         {
0159             return id;
0160         }
0161     }
0162     return LocalVolumeId{};
0163 }
0164 
0165 //---------------------------------------------------------------------------//
0166 /*!
0167  * Determinate if a single bbox contains the point.
0168  */
0169 CELER_FUNCTION bool BvhEnclosingVolFinder::visit_bbox(LocalVolumeId const& id,
0170                                                       Real3 const& point) const
0171 {
0172     return is_inside(view_.bbox(id), point);
0173 }
0174 
0175 //---------------------------------------------------------------------------//
0176 }  // namespace detail
0177 }  // namespace celeritas