Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 09:06:12

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/BIHIntersectingVolFinder.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include "corecel/math/Algorithms.hh"
0010 
0011 #include "BIHView.hh"
0012 #include "../BoundingBoxUtils.hh"
0013 #include "../OrangeData.hh"
0014 #include "../univ/detail/Types.hh"
0015 
0016 namespace celeritas
0017 {
0018 namespace detail
0019 {
0020 //---------------------------------------------------------------------------//
0021 /*!
0022  * Traverse the BIH to the find the volume that the ray intersects with first.
0023  *
0024  * Traversal is carried out using a depth first search. During traversal, the
0025  * minimum intersection is stored.  The decision to traverse an edge is done by
0026  * calculating the distance to intersection with the precomputed edge bounding
0027  * box. The edge bounding box is the bounding box created by clipping an
0028  * infinite bounding box with all bounding planes between the root node and the
0029  * current edge (inclusive). If a ray's intersection with the edge bbox is
0030  * found to be nearer than the current minimum intersection, traversal procedes
0031  * down that edge. Likewise, when a root node is reacted, intersections with
0032  * volume bboxes are first tested against the minimum intersection prior to
0033  * testing the the volume itself. The minimum intersection is only modified
0034  * when a nearer minimumium intersection with a actual volume if found, NOT a
0035  * nearer intersection with an edge bbox or volume bbox. This is because is is
0036  * possible to have a ray that interects with a volume's bbox, but not the
0037  * volume itself.
0038  *
0039  * \todo move to top-level orange directory out of detail namespace
0040  */
0041 class BIHIntersectingVolFinder
0042 {
0043   public:
0044     //!@{
0045     //! \name Type aliases
0046     using Storage = NativeCRef<BIHTreeData>;
0047 
0048     struct Ray
0049     {
0050         Real3 const& pos;
0051         Real3 const& dir;
0052     };
0053     //!@}
0054 
0055     // Construct from a vector of bounding boxes and storage for LocalVolumeIds
0056     inline CELER_FUNCTION
0057     BIHIntersectingVolFinder(BIHTree const& tree, Storage const& storage);
0058 
0059     // Calculate the minimum intersection, with supplied maximum search
0060     // distance
0061     template<class F>
0062     inline CELER_FUNCTION Intersection
0063     operator()(Ray ray, F&& visit_vol, real_type max_search_dist) const;
0064 
0065     // Calculate the minimum intersection, without supplied maximum search
0066     // distance
0067     template<class F>
0068     inline CELER_FUNCTION Intersection operator()(Ray ray, F&& visit_vol) const;
0069 
0070   private:
0071     //// DATA ////
0072     BIHView view_;
0073 
0074     //// HELPER FUNCTIONS ////
0075 
0076     // Get the ID of the next node in the traversal sequence
0077     inline CELER_FUNCTION BIHNodeId next_node(BIHNodeId current_id,
0078                                               BIHNodeId previous_id,
0079                                               Ray ray,
0080                                               real_type min_dist) const;
0081 
0082     // Determine if the intersection with an edge/vol bbox is less than
0083     // min_dist
0084     inline CELER_FUNCTION bool
0085     visit_bbox(FastBBox const& bbox, Ray ray, real_type min_dist) const;
0086 
0087     // Calculate the current min intersection, which may/may not be on this
0088     // leaf
0089     template<class F>
0090     inline CELER_FUNCTION Intersection visit_leaf(BIHLeafNode const& leaf_node,
0091                                                   Ray ray,
0092                                                   Intersection intersection,
0093                                                   F&& visit_vol) const;
0094 
0095     // Calculate the current min intersection, which may/may not be in inf_vols
0096     template<class F>
0097     inline CELER_FUNCTION Intersection visit_inf_vols(Intersection intersection,
0098                                                       F&& visit_vol) const;
0099 };
0100 
0101 //---------------------------------------------------------------------------//
0102 // INLINE DEFINITIONS
0103 //---------------------------------------------------------------------------//
0104 /*!
0105  * Construct from vector a of bounding boxes and storage.
0106  */
0107 CELER_FUNCTION
0108 BIHIntersectingVolFinder::BIHIntersectingVolFinder(
0109     BIHTree const& tree, BIHIntersectingVolFinder::Storage const& storage)
0110     : view_(tree, storage)
0111 {
0112     CELER_EXPECT(tree);
0113 }
0114 
0115 //---------------------------------------------------------------------------//
0116 /*!
0117  * Calculate the minimum intersection, with supplied maximum search distance.
0118  *
0119  * If no intersection is found within max_search_dist, an empty Intersection
0120  * object is returned. The visit_vol argument should be of the form:
0121  *
0122  * detail::Intersection(*)(LocalVolumeId id, real_type max_search_dist)
0123  *
0124  * Other information required by the functor should be handled through
0125  * lambda capture.
0126  */
0127 template<class F>
0128 CELER_FUNCTION auto
0129 BIHIntersectingVolFinder::operator()(BIHIntersectingVolFinder::Ray ray,
0130                                      F&& visit_vol,
0131                                      real_type max_search_dist) const
0132     -> Intersection
0133 {
0134     BIHNodeId previous_node;
0135     BIHNodeId current_node{0};
0136 
0137     Intersection intersection{OnLocalSurface{}, max_search_dist};
0138 
0139     do
0140     {
0141         if (!view_.is_inner(current_node))
0142         {
0143             intersection = this->visit_leaf(
0144                 view_.leaf_node(current_node), ray, intersection, visit_vol);
0145         }
0146 
0147         previous_node = exchange(
0148             current_node,
0149             this->next_node(
0150                 current_node, previous_node, ray, intersection.distance));
0151 
0152     } while (current_node);
0153 
0154     return this->visit_inf_vols(intersection, visit_vol);
0155 }
0156 
0157 //---------------------------------------------------------------------------//
0158 /*!
0159  * Calculate the minimum intersection, without supplied maximum search
0160  * distance.
0161  */
0162 template<class F>
0163 CELER_FUNCTION auto
0164 BIHIntersectingVolFinder::operator()(BIHIntersectingVolFinder::Ray ray,
0165                                      F&& visit_vol) const -> Intersection
0166 {
0167     return (*this)(ray, visit_vol, numeric_limits<real_type>::infinity());
0168 }
0169 
0170 //---------------------------------------------------------------------------//
0171 // HELPER FUNCTIONS
0172 //---------------------------------------------------------------------------//
0173 /*!
0174  *  Get the ID of the next node in the traversal sequence.
0175  */
0176 CELER_FUNCTION
0177 BIHNodeId BIHIntersectingVolFinder::next_node(BIHNodeId current_id,
0178                                               BIHNodeId previous_id,
0179                                               Ray ray,
0180                                               real_type min_dist) const
0181 {
0182     using Side = BIHInnerNode::Side;
0183 
0184     if (!view_.is_inner(current_id))
0185     {
0186         // Leaf node; return to parent
0187         CELER_EXPECT(previous_id == view_.leaf_node(current_id).parent);
0188         return previous_id;
0189     }
0190 
0191     auto const& current_node = view_.inner_node(current_id);
0192     auto const& l_edge = current_node.edges[Side::left];
0193     auto const& r_edge = current_node.edges[Side::right];
0194 
0195     if (previous_id == current_node.parent)
0196     {
0197         // Visiting this inner node for the first time; go down either left
0198         // edge, right edge, or return to the parent
0199         if (this->visit_bbox(l_edge.bbox, ray, min_dist))
0200         {
0201             return l_edge.child;
0202         }
0203         else if (this->visit_bbox(r_edge.bbox, ray, min_dist))
0204         {
0205             return r_edge.child;
0206         }
0207         else
0208         {
0209             return current_node.parent;
0210         }
0211     }
0212 
0213     if (previous_id == current_node.edges[Side::left].child)
0214     {
0215         // Visiting this inner node for the second time; go down right edge
0216         // or return to parent
0217         return this->visit_bbox(r_edge.bbox, ray, min_dist)
0218                    ? r_edge.child
0219                    : current_node.parent;
0220     }
0221 
0222     // Visiting this inner node for the third time; return to parent
0223     CELER_ASSERT(previous_id == current_node.edges[Side::right].child);
0224     return current_node.parent;
0225 }
0226 
0227 //---------------------------------------------------------------------------//
0228 /*!
0229  * Determine if the intersection with an edge/vol bbox is less than min_dist.
0230  */
0231 CELER_FUNCTION
0232 bool BIHIntersectingVolFinder::visit_bbox(FastBBox const& bbox,
0233                                           Ray ray,
0234                                           real_type min_dist) const
0235 {
0236     return is_inside(bbox, ray.pos)
0237            || calc_dist_to_inside(bbox, ray.pos, ray.dir) < min_dist;
0238 }
0239 
0240 //---------------------------------------------------------------------------//
0241 /*!
0242  * Calculate the current min intersection, which may/may not be on this leaf.
0243  */
0244 template<class F>
0245 CELER_FUNCTION auto
0246 BIHIntersectingVolFinder::visit_leaf(BIHLeafNode const& leaf_node,
0247                                      BIHIntersectingVolFinder::Ray ray,
0248                                      Intersection min_intersection,
0249                                      F&& visit_vol) const -> Intersection
0250 {
0251     for (auto id : view_.leaf_vol_ids(leaf_node))
0252     {
0253         auto const& bbox = view_.bbox(id);
0254 
0255         if (this->visit_bbox(bbox, ray, min_intersection.distance))
0256         {
0257             auto intersection = visit_vol(id, min_intersection.distance);
0258             if (intersection
0259                 && intersection.distance < min_intersection.distance)
0260             {
0261                 min_intersection = intersection;
0262             }
0263         }
0264     }
0265     return min_intersection;
0266 }
0267 
0268 //---------------------------------------------------------------------------//
0269 /*!
0270  * Calculate the current min intersection, which may/may not be in inf_vols.
0271  */
0272 template<class F>
0273 CELER_FUNCTION auto
0274 BIHIntersectingVolFinder::visit_inf_vols(Intersection min_intersection,
0275                                          F&& visit_vol) const -> Intersection
0276 {
0277     for (auto id : view_.inf_vol_ids())
0278     {
0279         auto intersection = visit_vol(id, min_intersection.distance);
0280         if (intersection && intersection.distance < min_intersection.distance)
0281         {
0282             min_intersection = intersection;
0283         }
0284     }
0285     return min_intersection;
0286 }
0287 
0288 //---------------------------------------------------------------------------//
0289 }  // namespace detail
0290 }  // namespace celeritas