diff --git a/src/axom/spin/BVH.hpp b/src/axom/spin/BVH.hpp index 767cd05afa..81fa8b2534 100644 --- a/src/axom/spin/BVH.hpp +++ b/src/axom/spin/BVH.hpp @@ -195,7 +195,43 @@ class BVH BVH() : m_AllocatorID(axom::execution_space::allocatorID()) { } /*! - * \brief Initializes a BVH instance, of specified dimension, over a given set + * \brief Constructs a BVH instance of specified dimension over a given set + * of geometric entities, each represented by its corresponding axis-aligned + * bounding box. + * + * \param [in] boxes buffer consisting of bounding boxes for each entity. + * \param [in] numItems the total number of items to store in the BVH. + * \param [in] allocatorID the ID of the allocator to use in BVH construction. + * \param [in] scaleFactor the scale factor for the given bounding boxes. + * \param [in] tolerance the tolerance to use when querying the BVH. + * + * \warning The supplied boxes array must point to a buffer in a memory space + * that is compatible with the execution space. For example, when using + * CUDA_EXEC, boxes must be in unified memory or GPU memory. The supplied + * allocator ID must also correspond to an umpire allocator and be compatible + * with the execution space. The code currently does not check for these + * conditions. + * + * \pre boxes != nullptr + * \pre numItems > 0 + * \pre allocatorID must correspond to an Umpire allocator and be compatible + * with the execution space + */ + template + BVH(const BoxIndexable boxes, + IndexType numItems, + int allocatorID = axom::execution_space::allocatorID(), + FloatType tolerance = DEFAULT_TOLERANCE, + FloatType scaleFactor = DEFAULT_SCALE_FACTOR) + : m_AllocatorID {allocatorID} + , m_tolerance {tolerance} + , m_scaleFactor {scaleFactor} + { + initialize(boxes, numItems); + } + + /*! + * \brief Initializes a BVH instance of specified dimension over a given set * of geometric entities, each represented by its corresponding axis-aligned * bounding box. * diff --git a/src/axom/spin/internal/linear_bvh/build_radix_tree.hpp b/src/axom/spin/internal/linear_bvh/build_radix_tree.hpp index b86d606fad..785caa22c4 100644 --- a/src/axom/spin/internal/linear_bvh/build_radix_tree.hpp +++ b/src/axom/spin/internal/linear_bvh/build_radix_tree.hpp @@ -97,11 +97,8 @@ void transform_boxes(const BoxIndexable boxes, for_all( size, AXOM_LAMBDA(std::int32_t i) { - primal::BoundingBox aabb = boxes[i]; - - aabb.scale(scale_factor); - - aabbs[i] = aabb; + aabbs[i] = boxes[i]; + aabbs[i].scale(scale_factor); }); } diff --git a/src/axom/spin/tests/spin_bvh.cpp b/src/axom/spin/tests/spin_bvh.cpp index bf0a96c86e..5b8e3fa2e6 100644 --- a/src/axom/spin/tests/spin_bvh.cpp +++ b/src/axom/spin/tests/spin_bvh.cpp @@ -196,17 +196,16 @@ void generate_aabbs_and_centroids( //------------------------------------------------------------------------------ /*! - * \brief Tests the construction of the BVH in 2D by inserting two bounding - * boxes in the BVH and ensuring that the bounds of the BVH are as expected. + * \brief Tests building the BVH by inserting two bounding boxes + * in the BVH and ensuring that the bounds of the BVH are as expected. */ -template -void check_build_bvh2d() +template +void check_build_bvh() { constexpr int NUM_BOXES = 2; - constexpr int NDIMS = 2; - using BoxType = typename primal::BoundingBox; - using PointType = typename primal::Point; + using BoxType = typename primal::BoundingBox; + using PointType = typename primal::Point; const int hostAllocatorID = axom::execution_space::allocatorID(); @@ -216,20 +215,18 @@ void check_build_bvh2d() boxes[0] = BoxType {PointType(0.), PointType(1.)}; boxes[1] = BoxType {PointType(1.), PointType(2.)}; - spin::BVH bvh; - // Copy boxes to device axom::Array boxesDevice(boxes, deviceAllocatorID); + spin::BVH bvh; bvh.setScaleFactor(1.0); // i.e., no scaling bvh.initialize(boxesDevice.view(), NUM_BOXES); - int allocatorID = bvh.getAllocatorID(); - EXPECT_EQ(allocatorID, axom::execution_space::allocatorID()); + EXPECT_EQ(bvh.getAllocatorID(), deviceAllocatorID); BoxType bounds = bvh.getBounds(); - for(int idim = 0; idim < NDIMS; ++idim) + for(int idim = 0; idim < Dimension; ++idim) { EXPECT_NEAR(bounds.getMin()[idim], 0.0, EPS); EXPECT_NEAR(bounds.getMax()[idim], 2.0, EPS); @@ -239,17 +236,16 @@ void check_build_bvh2d() //------------------------------------------------------------------------------ /*! - * \brief Tests the construction of the BVH in 3D by inserting two bounding + * \brief Tests the constructor of the BVH by inserting two bounding * boxes in the BVH and ensuring that the bounds of the BVH are as expected. */ -template -void check_build_bvh3d() +template +void check_construct_bvh() { constexpr int NUM_BOXES = 2; - constexpr int NDIMS = 3; - using BoxType = typename primal::BoundingBox; - using PointType = typename primal::Point; + using BoxType = typename primal::BoundingBox; + using PointType = typename primal::Point; const int hostAllocatorID = axom::execution_space::allocatorID(); @@ -259,20 +255,25 @@ void check_build_bvh3d() boxes[0] = BoxType {PointType(0.), PointType(1.)}; boxes[1] = BoxType {PointType(1.), PointType(2.)}; - spin::BVH bvh; - // Copy boxes to device axom::Array boxesDevice(boxes, deviceAllocatorID); - bvh.setScaleFactor(1.0); // i.e., no scaling - bvh.initialize(boxesDevice.view(), NUM_BOXES); + FloatType tolerance = static_cast(0.0); // i.e., no tolerance + FloatType scaleFactor = static_cast(1.0); // i.e., no scaling - int allocatorID = bvh.getAllocatorID(); - EXPECT_EQ(allocatorID, axom::execution_space::allocatorID()); + spin::BVH bvh(boxesDevice.view(), + NUM_BOXES, + deviceAllocatorID, + tolerance, + scaleFactor); + + EXPECT_EQ(bvh.getAllocatorID(), deviceAllocatorID); + EXPECT_EQ(bvh.getTolerance(), tolerance); + EXPECT_EQ(bvh.getScaleFactor(), scaleFactor); BoxType bounds = bvh.getBounds(); - for(int idim = 0; idim < NDIMS; ++idim) + for(int idim = 0; idim < Dimension; ++idim) { EXPECT_NEAR(bounds.getMin()[idim], 0.0, EPS); EXPECT_NEAR(bounds.getMax()[idim], 2.0, EPS); @@ -1644,18 +1645,32 @@ void check_0_or_1_bbox_2d() //------------------------------------------------------------------------------ // UNIT TESTS +//------------------------------------------------------------------------------ +TEST(spin_bvh, build2D_sequential) +{ + check_build_bvh<2, axom::SEQ_EXEC, double>(); + check_build_bvh<2, axom::SEQ_EXEC, float>(); +} + //------------------------------------------------------------------------------ TEST(spin_bvh, construct2D_sequential) { - check_build_bvh2d(); - check_build_bvh2d(); + check_construct_bvh<2, axom::SEQ_EXEC, double>(); + check_construct_bvh<2, axom::SEQ_EXEC, float>(); +} + +//------------------------------------------------------------------------------ +TEST(spin_bvh, build3D_sequential) +{ + check_build_bvh<3, axom::SEQ_EXEC, double>(); + check_build_bvh<3, axom::SEQ_EXEC, float>(); } //------------------------------------------------------------------------------ TEST(spin_bvh, construct3D_sequential) { - check_build_bvh3d(); - check_build_bvh3d(); + check_construct_bvh<3, axom::SEQ_EXEC, double>(); + check_construct_bvh<3, axom::SEQ_EXEC, float>(); } //------------------------------------------------------------------------------ @@ -1745,17 +1760,31 @@ TEST(spin_bvh, single_bbox_sequential) //------------------------------------------------------------------------------ #if defined(AXOM_USE_OPENMP) && defined(AXOM_USE_RAJA) +TEST(spin_bvh, build2D_omp) +{ + check_build_bvh<2, axom::OMP_EXEC, double>(); + check_build_bvh<2, axom::OMP_EXEC, float>(); +} + +//------------------------------------------------------------------------------ TEST(spin_bvh, construct2D_omp) { - check_build_bvh2d(); - check_build_bvh2d(); + check_construct_bvh<2, axom::OMP_EXEC, double>(); + check_construct_bvh<2, axom::OMP_EXEC, float>(); +} + +//------------------------------------------------------------------------------ +TEST(spin_bvh, build3D_omp) +{ + check_build_bvh<3, axom::OMP_EXEC, double>(); + check_build_bvh<3, axom::OMP_EXEC, float>(); } //------------------------------------------------------------------------------ TEST(spin_bvh, construct3D_omp) { - check_build_bvh3d(); - check_build_bvh3d(); + check_construct_bvh<3, axom::OMP_EXEC, double>(); + check_construct_bvh<3, axom::OMP_EXEC, float>(); } //------------------------------------------------------------------------------ @@ -1825,6 +1854,23 @@ TEST(spin_bvh, single_bbox_omp) //------------------------------------------------------------------------------ #if defined(AXOM_USE_GPU) && defined(AXOM_USE_RAJA) && defined(AXOM_USE_UMPIRE) +TEST(spin_bvh, build2D_device) +{ + constexpr int BLOCK_SIZE = 256; + + #if defined(__CUDACC__) + using exec = axom::CUDA_EXEC; + #elif defined(__HIPCC__) + using exec = axom::HIP_EXEC; + #else + using exec = axom::SEQ_EXEC; + #endif + + check_build_bvh<2, exec, double>(); + check_build_bvh<2, exec, float>(); +} + +//------------------------------------------------------------------------------ TEST(spin_bvh, construct2D_device) { constexpr int BLOCK_SIZE = 256; @@ -1837,8 +1883,25 @@ TEST(spin_bvh, construct2D_device) using exec = axom::SEQ_EXEC; #endif - check_build_bvh2d(); - check_build_bvh2d(); + check_construct_bvh<2, exec, double>(); + check_construct_bvh<2, exec, float>(); +} + +//------------------------------------------------------------------------------ +TEST(spin_bvh, build3D_device) +{ + constexpr int BLOCK_SIZE = 256; + + #if defined(__CUDACC__) + using exec = axom::CUDA_EXEC; + #elif defined(__HIPCC__) + using exec = axom::HIP_EXEC; + #else + using exec = axom::SEQ_EXEC; + #endif + + check_build_bvh<3, exec, double>(); + check_build_bvh<3, exec, float>(); } //------------------------------------------------------------------------------ @@ -1854,8 +1917,8 @@ TEST(spin_bvh, construct3D_device) using exec = axom::SEQ_EXEC; #endif - check_build_bvh3d(); - check_build_bvh3d(); + check_construct_bvh<3, exec, double>(); + check_construct_bvh<3, exec, float>(); } //------------------------------------------------------------------------------