@@ -189,6 +189,217 @@ namespace {
189189 }
190190 }
191191 }
192+
193+ #if (AMREX_SPACEDIM == 3)
194+
195+ AMREX_GPU_DEVICE AMREX_FORCE_INLINE
196+ Real pt_segment_min_d2 (XDim3 const & pt, XDim3 const & a, XDim3 const & b)
197+ {
198+ auto ab = b - a;
199+ auto ap = pt - a;
200+ auto t = dot_product (ab,ap) / dot_product (ab,ab);
201+ t = amrex::Clamp (t, Real (0 ), Real (1 ));
202+ return Math::powi<2 >(t*ab.x -ap.x )
203+ + Math::powi<2 >(t*ab.y -ap.y )
204+ + Math::powi<2 >(t*ab.z -ap.z );
205+ }
206+
207+ AMREX_GPU_DEVICE AMREX_FORCE_INLINE
208+ Real pt_tri_min_d2 (XDim3 const & pt, STLtools::Triangle const & tri)
209+ {
210+ // We want to know whether the projection of the point onto the
211+ // triangle plane is inside the triangle. If so, the closest point
212+ // on the triangle is that projected point. If not, the closest
213+ // point must be on the edges or vertices of the triangle.
214+
215+ // Any point Q on the plane of a triangle (ABC) can be written as Q
216+ // = c1*A + c2*B + c3*C, where c1 + c2 + c3 = 1. The coefficients,
217+ // c1, c2 and c3, are also known as barycentric coordinates of point
218+ // Q relative to the triangle. If all coefficients are between 0 and
219+ // 1, the point lies inisde the triangle. The way to see this is
220+ // that point Q is the interpolation of the three vertices in that
221+ // case. Any point Q on the plance can also be written as (Q-A) =
222+ // s*(B-A) + t*(C-A). The relationship between the two sets of
223+ // coefficients are c1 = 1-s-t, c2 = s, and c3 = t.
224+
225+ // Let AQ = s*AB + t*AC. Let AP = AQ + d*n/|n|, where n is a vector
226+ // perpendicular to the plane, and d is the distance to the
227+ // plane. We can then solve a system of equations.
228+ auto vb = tri.v2 - tri.v1 ; // AB, i.e., B-A
229+ auto vc = tri.v3 - tri.v1 ; // AC
230+ auto n = cross_product (vb, vc);
231+ auto rhs = pt - tri.v1 ; // AP
232+ auto det = dot_product (n,n);
233+ auto detinv = Real (1 ) / det;
234+ auto s = dot_product (rhs, cross_product (vc, n)) * detinv;
235+ if (s >= 0 && s <= Real (1 )) {
236+ auto t = dot_product (vb, cross_product (rhs, n)) * detinv;
237+ auto c1 = Real (1 ) - s - t;
238+ if (t >= 0 && c1 >= 0 ) { // q is inside
239+ auto dn = dot_product (vb, cross_product (vc, rhs));
240+ return dn*dn*detinv;
241+ }
242+ }
243+
244+ auto d2_1 = pt_segment_min_d2 (pt, tri.v1 , tri.v2 );
245+ auto d2_2 = pt_segment_min_d2 (pt, tri.v1 , tri.v3 );
246+ auto d2_3 = pt_segment_min_d2 (pt, tri.v2 , tri.v3 );
247+ return std::min ({d2_1,d2_2,d2_3});
248+ }
249+
250+ AMREX_GPU_DEVICE AMREX_FORCE_INLINE
251+ Real pt_box_min_d2 (XDim3 const & pt, RealBox const & bbox)
252+ {
253+ bool inside_x = (pt.x >= bbox.lo (0 )) && (pt.x <= bbox.hi (0 ));
254+ bool inside_y = (pt.y >= bbox.lo (1 )) && (pt.y <= bbox.hi (1 ));
255+ bool inside_z = (pt.z >= bbox.lo (2 )) && (pt.z <= bbox.hi (2 ));
256+ if (inside_x && inside_y && inside_z) {
257+ return Real (0 );
258+ } else if (inside_x && inside_y) {
259+ if (pt.z < bbox.lo (2 )) {
260+ return Math::powi<2 >(pt.z -bbox.lo (2 ));
261+ } else {
262+ return Math::powi<2 >(pt.z -bbox.hi (2 ));
263+ }
264+ } else if (inside_x && inside_z) {
265+ if (pt.y < bbox.lo (1 )) {
266+ return Math::powi<2 >(pt.y -bbox.lo (1 ));
267+ } else {
268+ return Math::powi<2 >(pt.y -bbox.hi (1 ));
269+ }
270+ } else if (inside_y && inside_z) {
271+ if (pt.x < bbox.lo (0 )) {
272+ return Math::powi<2 >(pt.x -bbox.lo (0 ));
273+ } else {
274+ return Math::powi<2 >(pt.x -bbox.hi (0 ));
275+ }
276+ } else if (inside_x) {
277+ if ((pt.y < bbox.lo (1 )) && (pt.z < bbox.lo (2 ))) {
278+ return Math::powi<2 >(pt.y -bbox.lo (1 ))
279+ + Math::powi<2 >(pt.z -bbox.lo (2 ));
280+ } else if ((pt.y < bbox.lo (1 )) && (pt.z > bbox.hi (2 ))) {
281+ return Math::powi<2 >(pt.y -bbox.lo (1 ))
282+ + Math::powi<2 >(pt.z -bbox.hi (2 ));
283+ } else if ((pt.y > bbox.hi (1 )) && (pt.z < bbox.lo (2 ))) {
284+ return Math::powi<2 >(pt.y -bbox.hi (1 ))
285+ + Math::powi<2 >(pt.z -bbox.lo (2 ));
286+ } else {
287+ return Math::powi<2 >(pt.y -bbox.hi (1 ))
288+ + Math::powi<2 >(pt.z -bbox.hi (2 ));
289+ }
290+ } else if (inside_y) {
291+ if ((pt.x < bbox.lo (0 )) && (pt.z < bbox.lo (2 ))) {
292+ return Math::powi<2 >(pt.x -bbox.lo (0 ))
293+ + Math::powi<2 >(pt.z -bbox.lo (2 ));
294+ } else if ((pt.x < bbox.lo (0 )) && (pt.z > bbox.hi (2 ))) {
295+ return Math::powi<2 >(pt.x -bbox.lo (0 ))
296+ + Math::powi<2 >(pt.z -bbox.hi (2 ));
297+ } else if ((pt.x > bbox.hi (0 )) && (pt.z < bbox.lo (2 ))) {
298+ return Math::powi<2 >(pt.x -bbox.hi (0 ))
299+ + Math::powi<2 >(pt.z -bbox.lo (2 ));
300+ } else {
301+ return Math::powi<2 >(pt.x -bbox.hi (0 ))
302+ + Math::powi<2 >(pt.z -bbox.hi (2 ));
303+ }
304+ } else if (inside_z) {
305+ if ((pt.x < bbox.lo (0 )) && (pt.y < bbox.lo (1 ))) {
306+ return Math::powi<2 >(pt.x -bbox.lo (0 ))
307+ + Math::powi<2 >(pt.y -bbox.lo (1 ));
308+ } else if ((pt.x < bbox.lo (0 )) && (pt.y > bbox.hi (1 ))) {
309+ return Math::powi<2 >(pt.x -bbox.lo (0 ))
310+ + Math::powi<2 >(pt.y -bbox.hi (1 ));
311+
312+ } else if ((pt.x > bbox.hi (0 )) && (pt.y < bbox.lo (1 ))) {
313+ return Math::powi<2 >(pt.x -bbox.hi (0 ))
314+ + Math::powi<2 >(pt.y -bbox.lo (1 ));
315+
316+ } else {
317+ return Math::powi<2 >(pt.x -bbox.hi (0 ))
318+ + Math::powi<2 >(pt.y -bbox.hi (1 ));
319+
320+ }
321+ } else {
322+ if ((pt.x < bbox.lo (0 )) && (pt.y < bbox.lo (1 )) && (pt.z < bbox.lo (2 ))) {
323+ return Math::powi<2 >(pt.x -bbox.lo (0 ))
324+ + Math::powi<2 >(pt.y -bbox.lo (1 ))
325+ + Math::powi<2 >(pt.z -bbox.lo (2 ));
326+ } else if ((pt.x > bbox.hi (0 )) && (pt.y < bbox.lo (1 )) && (pt.z < bbox.lo (2 ))) {
327+ return Math::powi<2 >(pt.x -bbox.hi (0 ))
328+ + Math::powi<2 >(pt.y -bbox.lo (1 ))
329+ + Math::powi<2 >(pt.z -bbox.lo (2 ));
330+ } else if ((pt.x < bbox.lo (0 )) && (pt.y > bbox.hi (1 )) && (pt.z < bbox.lo (2 ))) {
331+ return Math::powi<2 >(pt.x -bbox.lo (0 ))
332+ + Math::powi<2 >(pt.y -bbox.hi (1 ))
333+ + Math::powi<2 >(pt.z -bbox.lo (2 ));
334+ } else if ((pt.x > bbox.hi (0 )) && (pt.y > bbox.hi (1 )) && (pt.z < bbox.lo (2 ))) {
335+ return Math::powi<2 >(pt.x -bbox.hi (0 ))
336+ + Math::powi<2 >(pt.y -bbox.hi (1 ))
337+ + Math::powi<2 >(pt.z -bbox.lo (2 ));
338+ } else if ((pt.x < bbox.lo (0 )) && (pt.y < bbox.lo (1 )) && (pt.z > bbox.hi (2 ))) {
339+ return Math::powi<2 >(pt.x -bbox.lo (0 ))
340+ + Math::powi<2 >(pt.y -bbox.lo (1 ))
341+ + Math::powi<2 >(pt.z -bbox.hi (2 ));
342+ } else if ((pt.x > bbox.hi (0 )) && (pt.y < bbox.lo (1 )) && (pt.z > bbox.hi (2 ))) {
343+ return Math::powi<2 >(pt.x -bbox.hi (0 ))
344+ + Math::powi<2 >(pt.y -bbox.lo (1 ))
345+ + Math::powi<2 >(pt.z -bbox.hi (2 ));
346+ } else if ((pt.x < bbox.lo (0 )) && (pt.y > bbox.hi (1 )) && (pt.z > bbox.hi (2 ))) {
347+ return Math::powi<2 >(pt.x -bbox.lo (0 ))
348+ + Math::powi<2 >(pt.y -bbox.hi (1 ))
349+ + Math::powi<2 >(pt.z -bbox.hi (2 ));
350+ } else {
351+ return Math::powi<2 >(pt.x -bbox.hi (0 ))
352+ + Math::powi<2 >(pt.y -bbox.hi (1 ))
353+ + Math::powi<2 >(pt.z -bbox.hi (2 ));
354+ }
355+ }
356+ }
357+
358+ template <int M, int N>
359+ AMREX_GPU_DEVICE AMREX_FORCE_INLINE
360+ Real bvh_d2 (XDim3 const & pt, STLtools::BVHNodeT<M,N> const * root)
361+ {
362+ Stack<int , STLtools::m_bvh_max_stack_size> nodes_to_do;
363+ Stack<std::int8_t , STLtools::m_bvh_max_stack_size> nchildren_done;
364+ nodes_to_do.push (0 );
365+ nchildren_done.push (0 );
366+
367+ Real d = std::numeric_limits<Real>::max ();
368+
369+ while (!nodes_to_do.empty ()) {
370+ auto const & node = root[nodes_to_do.top ()];
371+ if (node.nchildren == 0 ) { // leaf node
372+ for (std::int8_t it = 0 ; it < node.ntriangles ; ++it) {
373+ Real dmin = pt_tri_min_d2 (pt, node.triangles [it]);
374+ d = std::min (d,dmin);
375+ if (d == 0 ) { return 0 ; }
376+ }
377+ nodes_to_do.pop ();
378+ nchildren_done.pop ();
379+ } else {
380+ auto & ndone = nchildren_done.top ();
381+ if (ndone < node.nchildren ) {
382+ for (auto ichild = ndone; ichild < node.nchildren ; ++ichild) {
383+ ++ndone;
384+ int inode = node.children [ichild];
385+ auto dmin = pt_box_min_d2 (pt, root[inode].boundingbox );
386+ if (d > dmin) {
387+ nodes_to_do.push (inode);
388+ nchildren_done.push (0 );
389+ break ;
390+ }
391+ }
392+ } else {
393+ nodes_to_do.pop ();
394+ nchildren_done.pop ();
395+ }
396+ }
397+ }
398+
399+ return d;
400+ }
401+
402+ #endif
192403}
193404
194405void
@@ -1113,4 +1324,57 @@ STLtools::updateIntercept (Array<Array4<Real>,AMREX_SPACEDIM> const& inter_arr,
11131324 }
11141325}
11151326
1327+ void
1328+ STLtools::fillSignedDistance (MultiFab& mf, IntVect const & nghost, Geometry const & geom) const
1329+ {
1330+ BL_PROFILE (" STLtools::fillSignedDistance" );
1331+
1332+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE (AMREX_SPACEDIM == 3 ,
1333+ " STLtools::fillSignedDistance is only available in 3D" );
1334+
1335+ #if (AMREX_SPACEDIM != 3)
1336+ amrex::ignore_unused (this , mf, nghost, geom);
1337+ #else
1338+ this ->fill (mf, nghost, geom, 1 ._rt , -1 ._rt );
1339+
1340+ const auto plo = geom.ProbLoArray ();
1341+ const auto dx = geom.CellSizeArray ();
1342+
1343+ auto ixt = mf.ixType ();
1344+ RealVect offset (AMREX_D_DECL (ixt.cellCentered (0 ) ? 0 .5_rt : 0 .0_rt,
1345+ ixt.cellCentered (1 ) ? 0 .5_rt : 0 .0_rt,
1346+ ixt.cellCentered (2 ) ? 0 .5_rt : 0 .0_rt));
1347+
1348+ auto const & ma = mf.arrays ();
1349+
1350+ if (m_bvh_optimization) {
1351+ auto const * bvh_root = m_bvh_nodes.data ();
1352+ ParallelFor (mf, nghost, [=] AMREX_GPU_DEVICE (int b, int i, int j, int k)
1353+ {
1354+ XDim3 coords = {plo[0 ]+(static_cast <Real>(i)+offset[0 ])*dx[0 ],
1355+ plo[1 ]+(static_cast <Real>(j)+offset[1 ])*dx[1 ],
1356+ plo[2 ]+(static_cast <Real>(k)+offset[2 ])*dx[2 ]};
1357+ auto d2 = bvh_d2 (coords, bvh_root);
1358+ ma[b](i,j,k) *= std::sqrt (d2);
1359+ });
1360+ } else {
1361+ auto const * tri_pts = m_tri_pts_d.data ();
1362+ int num_triangles = m_num_tri;
1363+ ParallelFor (mf, nghost, [=] AMREX_GPU_DEVICE (int b, int i, int j, int k)
1364+ {
1365+ XDim3 coords = {plo[0 ]+(static_cast <Real>(i)+offset[0 ])*dx[0 ],
1366+ plo[1 ]+(static_cast <Real>(j)+offset[1 ])*dx[1 ],
1367+ plo[2 ]+(static_cast <Real>(k)+offset[2 ])*dx[2 ]};
1368+ auto d2 = std::numeric_limits<Real>::max ();
1369+ for (int tr = 0 ; tr < num_triangles; ++tr) {
1370+ auto tmp = pt_tri_min_d2 (coords, tri_pts[tr]);
1371+ d2 = std::min (d2, tmp);
1372+ }
1373+ ma[b](i,j,k) *= std::sqrt (d2);
1374+ });
1375+ }
1376+ Gpu::streamSynchronize ();
1377+ #endif
1378+ }
1379+
11161380}
0 commit comments