Skip to content

Commit 0c7df10

Browse files
authored
STL optimization: Bounding volume hierarchy (#4140)
Speed up EB geometry generation with STL by using the bounding volume hierarchy (BVH) method. The BVH tree is stored in a contiguous chunk of memory making it easier for GPUs. Using a fixed size stack, recursion is avoided when traversing the tree. X-Ref: https://rmrsk.github.io/EBGeometry/Concepts.html#bounding-volume-hierarchies
1 parent c333708 commit 0c7df10

File tree

8 files changed

+578
-152
lines changed

8 files changed

+578
-152
lines changed

Src/EB/AMReX_EB2.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,14 +216,17 @@ Build (const Geometry& geom, int required_coarsening_level,
216216
pp.queryAdd("stl_center", stl_center);
217217
bool stl_reverse_normal = false;
218218
pp.queryAdd("stl_reverse_normal", stl_reverse_normal);
219+
bool stl_use_bvh = true;
220+
pp.queryAdd("stl_use_bvh", stl_use_bvh);
219221
IndexSpace::push(new IndexSpaceSTL(stl_file, stl_scale, // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks)
220222
{stl_center[0], stl_center[1], stl_center[2]},
221223
int(stl_reverse_normal),
222224
geom, required_coarsening_level,
223225
max_coarsening_level, ngrow,
224226
build_coarse_level_by_coarsening,
225227
a_extend_domain_face,
226-
a_num_coarsen_opt));
228+
a_num_coarsen_opt,
229+
stl_use_bvh));
227230
}
228231
else
229232
{

Src/EB/AMReX_EB2_2D_C.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,8 @@ int build_faces (Box const& bx, Array4<EBCellFlag> const& cell,
342342
nsmallfaces += *(hp+1);
343343

344344
if (*hp > 0 && !cover_multiple_cuts) {
345-
amrex::Abort("amrex::EB2::build_faces: more than 2 cuts not supported");
345+
amrex::Abort("amrex::EB2::build_faces: more than 2 cuts not supported. "
346+
"You can try to fix it by using runtime parameter eb2.cover_multiple_cuts=1.");
346347
}
347348

348349
return *hp;

Src/EB/AMReX_EB2_3D_C.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,8 @@ int build_faces (Box const& bx, Array4<EBCellFlag> const& cell,
768768
}
769769
});
770770
} else {
771-
amrex::Abort("amrex::EB2::build_faces: more than 2 cuts not supported");
771+
amrex::Abort("amrex::EB2::build_faces: more than 2 cuts not supported. "
772+
"You can try to fix it by using runtime parameter eb2.cover_multiple_cuts=1.");
772773
}
773774
}
774775

@@ -932,7 +933,8 @@ void build_cells (Box const& bx, Array4<EBCellFlag> const& cell,
932933

933934
if (nsmallcells > 0 || nmulticuts > 0) {
934935
if (!cover_multiple_cuts && nmulticuts > 0) {
935-
amrex::Abort("amrex::EB2::build_cells: multi-cuts not supported");
936+
amrex::Abort("amrex::EB2::build_cells: multi-cuts not supported. "
937+
"You can try to fix it by using runtime parameter eb2.cover_multiple_cuts=1.");
936938
}
937939
return;
938940
} else {

Src/EB/AMReX_EB2_IndexSpace_STL.H

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public:
1919
const Geometry& geom, int required_coarsening_level,
2020
int max_coarsening_level, int ngrow,
2121
bool build_coarse_level_by_coarsening,
22-
bool extend_domain_face, int num_coarsen_opt);
22+
bool extend_domain_face, int num_coarsen_opt, bool bvh_optimization);
2323

2424
IndexSpaceSTL (IndexSpaceSTL const&) = delete;
2525
IndexSpaceSTL (IndexSpaceSTL &&) = delete;

Src/EB/AMReX_EB2_IndexSpace_STL.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ IndexSpaceSTL::IndexSpaceSTL (const std::string& stl_file, Real stl_scale,
77
const Geometry& geom, int required_coarsening_level,
88
int max_coarsening_level, int ngrow,
99
bool build_coarse_level_by_coarsening,
10-
bool extend_domain_face, int num_coarsen_opt)
10+
bool extend_domain_face, int num_coarsen_opt,
11+
bool bvh_optimization)
1112
{
1213
Gpu::LaunchSafeGuard lsg(true); // Always use GPU
1314

1415
STLtools stl_tools;
16+
stl_tools.setBVHOptimization(bvh_optimization);
1517
stl_tools.read_stl_file(stl_file, stl_scale, stl_center, stl_reverse_normal);
1618

1719
// build finest level (i.e., level 0) first

Src/EB/AMReX_EB_STL_utils.H

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
#include <AMReX_Dim3.H>
88
#include <AMReX_EB2_Graph.H>
99

10+
#include <algorithm>
11+
#include <cstdint>
12+
#include <limits>
13+
#include <utility>
14+
1015
namespace amrex
1116
{
1217

@@ -15,33 +20,47 @@ class STLtools
1520
public:
1621
struct Triangle {
1722
XDim3 v1, v2, v3;
18-
};
19-
20-
static constexpr int allregular = -1;
21-
static constexpr int mixedcells = 0;
22-
static constexpr int allcovered = 1;
23-
24-
private:
2523

26-
Gpu::PinnedVector<Triangle> m_tri_pts_h;
27-
Gpu::DeviceVector<Triangle> m_tri_pts_d;
28-
Gpu::DeviceVector<XDim3> m_tri_normals_d;
24+
[[nodiscard]] Real cent (int d) const
25+
{
26+
static_assert(sizeof(XDim3) == sizeof(Real)*3);
27+
return Real(1./3.)*((&v1.x)[d] + (&v2.x)[d] + (&v3.x)[d]);
28+
}
29+
30+
[[nodiscard]] std::pair<Real,Real> minmax (int d) const
31+
{
32+
static_assert(sizeof(XDim3) == sizeof(Real)*3);
33+
return std::minmax({(&v1.x)[d], (&v2.x)[d], (&v3.x)[d]});
34+
}
35+
};
2936

30-
int m_num_tri=0;
37+
template <int M, int N>
38+
struct BVHNodeT
39+
{
40+
RealBox boundingbox{AMREX_D_DECL(std::numeric_limits<Real>::max(),
41+
std::numeric_limits<Real>::max(),
42+
std::numeric_limits<Real>::max()),
43+
AMREX_D_DECL(std::numeric_limits<Real>::lowest(),
44+
std::numeric_limits<Real>::lowest(),
45+
std::numeric_limits<Real>::lowest())};
46+
STLtools::Triangle triangles[M];
47+
XDim3 trinorm[M];
48+
int children[N];
49+
std::int8_t ntriangles = 0;
50+
std::int8_t nchildren = 0;
51+
};
3152

32-
XDim3 m_ptmin; // All triangles are inside the bounding box defined by
33-
XDim3 m_ptmax; // m_ptmin and m_ptmax.
34-
XDim3 m_ptref; // The reference point is slightly outside the bounding box.
35-
bool m_boundry_is_outside; // Is the bounding box boundary outside or inside the object?
53+
static constexpr int m_bvh_max_size = 4; // max # of triangles in a leaf node
54+
static constexpr int m_bvh_max_splits = 4; // max # of children
55+
static constexpr int m_bvh_max_stack_size = 12; // max depth of the tree
3656

37-
void read_ascii_stl_file (std::string const& fname, Real scale,
38-
Array<Real,3> const& center, int reverse_normal);
39-
void read_binary_stl_file (std::string const& fname, Real scale,
40-
Array<Real,3> const& center, int reverse_normal);
57+
using Node = BVHNodeT<m_bvh_max_size,m_bvh_max_splits>;
4158

42-
public:
59+
static constexpr int allregular = -1;
60+
static constexpr int mixedcells = 0;
61+
static constexpr int allcovered = 1;
4362

44-
void prepare (); // public for cuda
63+
void setBVHOptimization (bool flag) { m_bvh_optimization = flag; }
4564

4665
void read_stl_file (std::string const& fname, Real scale, Array<Real,3> const& center,
4766
int reverse_normal);
@@ -65,6 +84,32 @@ public:
6584
Array<Array4<EB2::Type_t const>,AMREX_SPACEDIM> const& type_arr,
6685
Array4<Real const> const& lst, Geometry const& geom) ;
6786

87+
void prepare (Gpu::PinnedVector<Triangle> a_tri_pts); // public for cuda
88+
89+
private:
90+
91+
bool m_bvh_optimization = true;
92+
93+
Gpu::DeviceVector<Triangle> m_tri_pts_d;
94+
Gpu::DeviceVector<XDim3> m_tri_normals_d;
95+
Gpu::DeviceVector<Node> m_bvh_nodes;
96+
97+
int m_num_tri=0;
98+
99+
XDim3 m_ptmin; // All triangles are inside the bounding box defined by
100+
XDim3 m_ptmax; // m_ptmin and m_ptmax.
101+
XDim3 m_ptref; // The reference point is slightly outside the bounding box.
102+
bool m_boundry_is_outside; // Is the bounding box boundary outside or inside the object?
103+
104+
void read_ascii_stl_file (std::string const& fname, Real scale,
105+
Array<Real,3> const& center, int reverse_normal,
106+
Gpu::PinnedVector<Triangle>& a_tri_pts);
107+
void read_binary_stl_file (std::string const& fname, Real scale,
108+
Array<Real,3> const& center, int reverse_normal,
109+
Gpu::PinnedVector<Triangle>& a_tri_pts);
110+
111+
static void build_bvh (Triangle* begin, Triangle * end, Gpu::PinnedVector<Node>& bvh_nodes);
112+
static void bvh_size (int ntri, std::size_t& nnodes);
68113
};
69114

70115
}

0 commit comments

Comments
 (0)