Skip to content

Commit 2d931f6

Browse files
authored
Maintain the high end of the 'roundoff domain' in both float and double precision (AMReX-Codes#2839)
* Maintain the high end of the 'roundoff domain' in both float and double precision * fix shadowing * fix warning * fix float conversion warning * fix logic * Update Src/Base/AMReX_Geometry.H * Update Src/Base/AMReX_Geometry.H
1 parent 104466d commit 2d931f6

File tree

4 files changed

+74
-52
lines changed

4 files changed

+74
-52
lines changed

Src/Base/AMReX_Geometry.H

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,32 @@ public:
6767
int coord;
6868
};
6969

70+
namespace detail {
71+
template <typename T>
72+
T bisect_prob_hi (amrex::Real plo, amrex::Real phi, amrex::Real idx, int ilo, int ihi, amrex::Real tol) {
73+
T hi = static_cast<T>(phi - tol);
74+
bool safe;
75+
{
76+
int i = int(Math::floor((hi - plo)*idx)) + ilo;
77+
safe = i >= ilo && i <= ihi;
78+
}
79+
if (safe) {
80+
return hi;
81+
} else {
82+
// bisect the point at which the cell no longer maps to inside the domain
83+
T lo = static_cast<T>(phi - 0.5_rt/idx);
84+
T mid = bisect(lo, hi,
85+
[=] AMREX_GPU_HOST_DEVICE (T x) -> T
86+
{
87+
int i = int(Math::floor((x - plo)*idx)) + ilo;
88+
bool inside = i >= ilo && i <= ihi;
89+
return static_cast<T>(inside) - T(0.5);
90+
}, static_cast<T>(tol));
91+
return mid - static_cast<T>(tol);
92+
}
93+
}
94+
}
95+
7096
class Geometry
7197
:
7298
public CoordSys
@@ -168,8 +194,6 @@ public:
168194

169195
//! Returns the problem domain.
170196
const RealBox& ProbDomain () const noexcept { return prob_domain; }
171-
//! Returns the roundoff domain.
172-
const RealBox& RoundoffDomain () const noexcept { return roundoff_domain; }
173197
//! Sets the problem domain.
174198
void ProbDomain (const RealBox& rb) noexcept
175199
{
@@ -193,12 +217,12 @@ public:
193217
return {{AMREX_D_DECL(prob_domain.hi(0),prob_domain.hi(1),prob_domain.hi(2))}};
194218
}
195219

196-
GpuArray<Real,AMREX_SPACEDIM> RoundoffLoArray () const noexcept {
197-
return {{AMREX_D_DECL(roundoff_domain.lo(0),roundoff_domain.lo(1),roundoff_domain.lo(2))}};
198-
}
199-
200-
GpuArray<Real,AMREX_SPACEDIM> RoundoffHiArray () const noexcept {
201-
return {{AMREX_D_DECL(roundoff_domain.hi(0),roundoff_domain.hi(1),roundoff_domain.hi(2))}};
220+
GpuArray<ParticleReal,AMREX_SPACEDIM> ProbHiArrayInParticleReal () const noexcept {
221+
#ifdef AMREX_SINGLE_PRECISION_PARTICLES
222+
return roundoff_hi_f;
223+
#else
224+
return roundoff_hi_d;
225+
#endif
202226
}
203227

204228
//! Returns the overall size of the domain by multiplying the ProbLength's together
@@ -406,15 +430,15 @@ public:
406430
* are sure to be mapped to cells inside the Domain() box. Note that
407431
* the same need not be true for all points inside ProbDomain().
408432
*/
409-
bool outsideRoundoffDomain (AMREX_D_DECL(Real x, Real y, Real z)) const;
433+
bool outsideRoundoffDomain (AMREX_D_DECL(ParticleReal x, ParticleReal y, ParticleReal z)) const;
410434

411435
/**
412436
* \brief Returns true if a point is inside the roundoff domain.
413437
* All particles with positions inside the roundoff domain
414438
* are sure to be mapped to cells inside the Domain() box. Note that
415439
* the same need not be true for all points inside ProbDomain().
416440
*/
417-
bool insideRoundoffDomain (AMREX_D_DECL(Real x, Real y, Real z)) const;
441+
bool insideRoundoffDomain (AMREX_D_DECL(ParticleReal x, ParticleReal y, ParticleReal z)) const;
418442

419443
/**
420444
* \brief Compute the roundoff domain. Public because it contains an
@@ -430,10 +454,11 @@ private:
430454
RealBox prob_domain;
431455

432456
// Due to round-off errors, not all floating point numbers for which plo >= x < phi
433-
// will map to a cell that is inside "domain". "roundoff_domain" stores a phi
434-
// that is very close to that in prob_domain, and for which all floating point numbers
435-
// inside it according to a naive inequality check will map to a cell inside domain.
436-
RealBox roundoff_domain;
457+
// will map to a cell that is inside "domain". "roundoff_hi_d" and "roundoff_hi_f" each store
458+
// a phi that is very close to that in prob_domain, and for which all doubles and floats less than
459+
// it will map to a cell inside domain.
460+
GpuArray<double, AMREX_SPACEDIM> roundoff_hi_d;
461+
GpuArray<float , AMREX_SPACEDIM> roundoff_hi_f;
437462

438463
//
439464
Box domain;

Src/Base/AMReX_Geometry.cpp

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,6 @@ Geometry::computeRoundoffDomain ()
506506
inv_dx[k] = 1.0_rt/dx[k];
507507
}
508508

509-
roundoff_domain = prob_domain;
510509
for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
511510
{
512511
int ilo = Domain().smallEnd(idim);
@@ -516,40 +515,37 @@ Geometry::computeRoundoffDomain ()
516515
Real idx = InvCellSize(idim);
517516
Real deltax = CellSize(idim);
518517

519-
#ifdef AMREX_SINGLE_PRECISION_PARTICLES
520-
Real tolerance = std::max(1.e-4_rt*deltax, 2.e-7_rt*phi);
521-
#else
522-
Real tolerance = std::max(1.e-8_rt*deltax, 1.e-14_rt*phi);
523-
#endif
524-
// bisect the point at which the cell no longer maps to inside the domain
525-
Real lo = static_cast<Real>(phi) - Real(0.5)*static_cast<Real>(deltax);
526-
Real hi = static_cast<Real>(phi) + Real(0.5)*static_cast<Real>(deltax);
527-
528-
Real mid = bisect(lo, hi,
529-
[=] AMREX_GPU_HOST_DEVICE (Real x) -> Real
530-
{
531-
int i = int(Math::floor((x - plo)*idx)) + ilo;
532-
bool inside = i >= ilo && i <= ihi;
533-
return static_cast<Real>(inside) - Real(0.5);
534-
}, tolerance);
535-
roundoff_domain.setHi(idim, mid - tolerance);
518+
Real ftol = std::max(1.e-4_rt*deltax, 2.e-7_rt*phi);
519+
Real dtol = std::max(1.e-8_rt*deltax, 1.e-14_rt*phi);
520+
521+
roundoff_hi_f[idim] = detail::bisect_prob_hi<float> (plo, phi, idx, ilo, ihi, ftol);
522+
roundoff_hi_d[idim] = detail::bisect_prob_hi<double>(plo, phi, idx, ilo, ihi, dtol);
536523
}
537524
}
538525

539526
bool
540-
Geometry::outsideRoundoffDomain (AMREX_D_DECL(Real x, Real y, Real z)) const
527+
Geometry::outsideRoundoffDomain (AMREX_D_DECL(ParticleReal x, ParticleReal y, ParticleReal z)) const
541528
{
542-
bool outside = AMREX_D_TERM(x < roundoff_domain.lo(0)
543-
|| x >= roundoff_domain.hi(0),
544-
|| y < roundoff_domain.lo(1)
545-
|| y >= roundoff_domain.hi(1),
546-
|| z < roundoff_domain.lo(2)
547-
|| z >= roundoff_domain.hi(2));
529+
#ifdef AMREX_SINGLE_PRECISION_PARTICLES
530+
bool outside = AMREX_D_TERM(x < prob_domain.lo(0)
531+
|| x >= roundoff_hi_f[0],
532+
|| y < prob_domain.lo(1)
533+
|| y >= roundoff_hi_f[1],
534+
|| z < prob_domain.lo(2)
535+
|| z >= roundoff_hi_f[2]);
536+
#else
537+
bool outside = AMREX_D_TERM(x < prob_domain.lo(0)
538+
|| x >= roundoff_hi_d[0],
539+
|| y < prob_domain.lo(1)
540+
|| y >= roundoff_hi_d[1],
541+
|| z < prob_domain.lo(2)
542+
|| z >= roundoff_hi_d[2]);
543+
#endif
548544
return outside;
549545
}
550546

551547
bool
552-
Geometry::insideRoundoffDomain (AMREX_D_DECL(Real x, Real y, Real z)) const
548+
Geometry::insideRoundoffDomain (AMREX_D_DECL(ParticleReal x, ParticleReal y, ParticleReal z)) const
553549
{
554550
return !outsideRoundoffDomain(AMREX_D_DECL(x, y, z));
555551
}

Src/Particle/AMReX_ParticleContainerI.H

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ ParticleContainer<NStructReal, NStructInt, NArrayReal, NArrayInt, Allocator>
239239
const auto& geom = Geom(0);
240240
const auto plo = geom.ProbLoArray();
241241
const auto phi = geom.ProbHiArray();
242-
const auto rhi = geom.RoundoffHiArray();
242+
const auto rhi = geom.ProbHiArrayInParticleReal();
243243
const auto is_per = geom.isPeriodicArray();
244244

245245
return enforcePeriodic(p, plo, phi, rhi, is_per);
@@ -314,20 +314,21 @@ ParticleContainer<NStructReal, NStructInt, NArrayReal, NArrayInt, Allocator>::lo
314314

315315
if (! outside)
316316
{
317-
if (Geom(0).outsideRoundoffDomain(AMREX_D_DECL(Real(p.pos(0)), Real(p.pos(1)), Real(p.pos(2)))))
317+
if (Geom(0).outsideRoundoffDomain(AMREX_D_DECL(p.pos(0), p.pos(1), p.pos(2))))
318318
{
319-
RealBox roundoff_domain = Geom(0).RoundoffDomain();
319+
RealBox prob_domain = Geom(0).ProbDomain();
320+
GpuArray<ParticleReal, AMREX_SPACEDIM> phi = Geom(0).ProbHiArrayInParticleReal();
320321
for (int idim=0; idim < AMREX_SPACEDIM; ++idim)
321322
{
322-
if (p.pos(idim) <= roundoff_domain.lo(idim)) {
323-
p.pos(idim) = std::nextafter((ParticleReal) roundoff_domain.lo(idim), (ParticleReal) roundoff_domain.hi(idim));
323+
if (p.pos(idim) <= prob_domain.lo(idim)) {
324+
p.pos(idim) = std::nextafter((ParticleReal) prob_domain.lo(idim), phi[idim]);
324325
}
325-
if (p.pos(idim) >= roundoff_domain.hi(idim)) {
326-
p.pos(idim) = std::nextafter((ParticleReal) roundoff_domain.hi(idim), (ParticleReal) roundoff_domain.lo(idim));
326+
if (p.pos(idim) >= phi[idim]) {
327+
p.pos(idim) = std::nextafter(phi[idim], (ParticleReal) prob_domain.lo(idim));
327328
}
328329
}
329330

330-
AMREX_ASSERT(! Geom(0).outsideRoundoffDomain(AMREX_D_DECL(Real(p.pos(0)), Real(p.pos(1)), Real(p.pos(2)))));
331+
AMREX_ASSERT(! Geom(0).outsideRoundoffDomain(AMREX_D_DECL(p.pos(0), p.pos(1), p.pos(2))));
331332
}
332333
}
333334

@@ -1233,7 +1234,7 @@ ParticleContainer<NStructReal, NStructInt, NArrayReal, NArrayInt, Allocator>
12331234
Vector<std::map<int, int> > new_sizes(num_levels);
12341235
const auto plo = Geom(0).ProbLoArray();
12351236
const auto phi = Geom(0).ProbHiArray();
1236-
const auto rhi = Geom(0).RoundoffHiArray();
1237+
const auto rhi = Geom(0).ProbHiArrayInParticleReal();
12371238
const auto is_per = Geom(0).isPeriodicArray();
12381239
for (int lev = lev_min; lev <= finest_lev_particles; ++lev)
12391240
{

Src/Particle/AMReX_ParticleUtil.H

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
517517
bool enforcePeriodic (P& p,
518518
amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> const& plo,
519519
amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> const& phi,
520-
amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> const& rhi,
520+
amrex::GpuArray<amrex::ParticleReal,AMREX_SPACEDIM> const& rhi,
521521
amrex::GpuArray<int,AMREX_SPACEDIM> const& is_per) noexcept
522522
{
523523
bool shifted = false;
@@ -537,7 +537,7 @@ bool enforcePeriodic (P& p,
537537
p.pos(idim) += static_cast<ParticleReal>(phi[idim] - plo[idim]);
538538
}
539539
// clamp to avoid precision issues;
540-
if (p.pos(idim) >= rhi[idim]) {
540+
if (p.pos(idim) > rhi[idim]) {
541541
p.pos(idim) = static_cast<ParticleReal>(rhi[idim]);
542542
}
543543
shifted = true;
@@ -555,7 +555,7 @@ int
555555
partitionParticlesByDest (PTile& ptile, const PLocator& ploc, const ParticleBufferMap& pmap,
556556
const GpuArray<Real,AMREX_SPACEDIM>& plo,
557557
const GpuArray<Real,AMREX_SPACEDIM>& phi,
558-
const GpuArray<Real,AMREX_SPACEDIM>& rhi,
558+
const GpuArray<ParticleReal,AMREX_SPACEDIM>& rhi,
559559
const GpuArray<int ,AMREX_SPACEDIM>& is_per,
560560
int lev, int gid, int /*tid*/,
561561
int lev_min, int lev_max, int nGrow, bool remove_negative)

0 commit comments

Comments
 (0)