Skip to content

Commit 0234442

Browse files
committed
Open Boundary Poisson Solver
This adds an open boundary Poisson solver based on the James's algorithm. To use it, the user builds an amrex:OpenBCSolver object, which can be reused until the grids change, and then call OpenBCSolver::solver. Currently, this is for 3D cell-centered data only. The solver works on CPU, Nvidia GPUS, and AMD GPUs. The SYCL version of a couple of kernels for Intel GPUs are to be implemented.
1 parent 1bda173 commit 0234442

File tree

9 files changed

+1230
-2
lines changed

9 files changed

+1230
-2
lines changed

Src/Base/AMReX_DistributionMapping.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,7 @@ DistributionMapping::SFCProcessorMap (const BoxArray& boxes,
13001300

13011301
for (int i = 0, N = boxes.size(); i < N; ++i)
13021302
{
1303-
wgts.push_back(boxes[i].volume());
1303+
wgts.push_back(boxes[i].numPts());
13041304
}
13051305

13061306
SFCProcessorMapDoIt(boxes,wgts,nprocs);
@@ -1769,7 +1769,7 @@ DistributionMapping::makeSFC (const BoxArray& ba, bool use_box_vol, const int np
17691769
{
17701770
const Box& bx = ba[i];
17711771
tokens.push_back(makeSFCToken(i, bx.smallEnd()));
1772-
const Long v = use_box_vol ? bx.volume() : Long(1);
1772+
const Long v = use_box_vol ? bx.numPts() : Long(1);
17731773
vol_sum += v;
17741774
wgts.push_back(v);
17751775
}

Src/Boundary/AMReX_LOUtil_K.H

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,22 @@ void poly_interp_coeff (Real xInt, Real const* AMREX_RESTRICT x, int N, Real* AM
3434
}
3535
}
3636

37+
template <int N>
38+
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
39+
void poly_interp_coeff (Real xInt, Real const* AMREX_RESTRICT x, Real* AMREX_RESTRICT c) noexcept
40+
{
41+
for (int j = 0; j < N; ++j) {
42+
Real num = 1.0, den = 1.0;
43+
for (int i = 0; i < N; ++i) {
44+
if (i != j) {
45+
num *= xInt-x[i];
46+
den *= x[j]-x[i];
47+
}
48+
}
49+
c[j] = num / den;
50+
}
51+
}
52+
3753
}
3854

3955
#endif

Src/LinearSolvers/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,14 @@ if (AMReX_HYPRE)
9898
MLMG/AMReX_MLNodeLaplacian_hypre.cpp
9999
)
100100
endif ()
101+
102+
if (AMReX_SPACEDIM EQUAL 3)
103+
104+
target_include_directories(amrex PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/OpenBC>)
105+
106+
target_sources(amrex
107+
PRIVATE
108+
OpenBC/AMReX_OpenBC.H
109+
OpenBC/AMReX_OpenBC.cpp
110+
)
111+
endif ()

Src/LinearSolvers/MLMG/AMReX_MLPoisson.H

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ public:
7070

7171
virtual void copyNSolveSolution (MultiFab& dst, MultiFab const& src) const final override;
7272

73+
//! Compute dphi/dn on domain faces after the solver has converged.
74+
void get_dpdn_on_domain_faces (Array<MultiFab*,AMREX_SPACEDIM> const& dpdn,
75+
MultiFab const& phi);
76+
7377
private:
7478

7579
Vector<int> m_is_singular;

Src/LinearSolvers/MLMG/AMReX_MLPoisson.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,4 +702,63 @@ MLPoisson::copyNSolveSolution (MultiFab& dst, MultiFab const& src) const
702702
dst.ParallelCopy(src);
703703
}
704704

705+
void
706+
MLPoisson::get_dpdn_on_domain_faces (Array<MultiFab*,AMREX_SPACEDIM> const& dpdn,
707+
MultiFab const& phi)
708+
{
709+
BL_PROFILE("MLPoisson::dpdn_faces()");
710+
711+
// We do not need to call applyBC because this function is used by the
712+
// OpenBC solver after solver has converged. That means the BC has been
713+
// filled to check the residual.
714+
715+
Box const& domain0 = m_geom[0][0].Domain();
716+
AMREX_D_TERM(const Real dxi = m_geom[0][0].InvCellSize(0);,
717+
const Real dyi = m_geom[0][0].InvCellSize(1);,
718+
const Real dzi = m_geom[0][0].InvCellSize(2);)
719+
720+
#ifdef AMREX_USE_OMP
721+
#pragma omp parallel if (Gpu::notInLaunchRegion())
722+
#endif
723+
for (MFIter mfi(phi); mfi.isValid(); ++mfi)
724+
{
725+
Box const& vbx = mfi.validbox();
726+
for (OrientationIter oit; oit.isValid(); ++oit) {
727+
Orientation face = oit();
728+
if (vbx[face] == domain0[face]) {
729+
int dir = face.coordDir();
730+
Array4<Real const> const& p = phi.const_array(mfi);
731+
Array4<Real> const& gp = dpdn[dir]->array(mfi);
732+
Box const& b2d = amrex::bdryNode(vbx,face);
733+
if (dir == 0) {
734+
// because it's dphi/dn, not dphi/dx.
735+
Real fac = dxi * (face.isLow() ? -1.0_rt : 1._rt);
736+
AMREX_HOST_DEVICE_PARALLEL_FOR_3D(b2d, i, j, k,
737+
{
738+
gp(i,j,k) = fac * (p(i,j,k) - p(i-1,j,k));
739+
});
740+
}
741+
#if (AMREX_SPACEDIM > 1)
742+
else if (dir == 1) {
743+
Real fac = dyi * (face.isLow() ? -1.0_rt : 1._rt);
744+
AMREX_HOST_DEVICE_PARALLEL_FOR_3D(b2d, i, j, k,
745+
{
746+
gp(i,j,k) = fac * (p(i,j,k) - p(i,j-1,k));
747+
});
748+
}
749+
#if (AMREX_SPACEDIM > 2)
750+
else {
751+
Real fac = dzi * (face.isLow() ? -1.0_rt : 1._rt);
752+
AMREX_HOST_DEVICE_PARALLEL_FOR_3D(b2d, i, j, k,
753+
{
754+
gp(i,j,k) = fac * (p(i,j,k) - p(i,j,k-1));
755+
});
756+
}
757+
#endif
758+
#endif
759+
}
760+
}
761+
}
762+
}
763+
705764
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#ifndef AMREX_OPENBC_H_
2+
#define AMREX_OPENBC_H_
3+
#include <AMReX_Config.H>
4+
5+
#include <AMReX_MLMG.H>
6+
#include <AMReX_MLPoisson.H>
7+
8+
namespace amrex
9+
{
10+
11+
namespace openbc {
12+
13+
static constexpr int M = 7; // highest order of moments
14+
static constexpr int P = 3;
15+
16+
struct Moments
17+
{
18+
typedef GpuArray<Real,(M+2)*(M+1)/2> array_type;
19+
array_type mom;
20+
Real x, y, z;
21+
Orientation face;
22+
};
23+
24+
struct MomTag
25+
{
26+
Array4<Real const> gp;
27+
Box b2d;
28+
Orientation face;
29+
int offset;
30+
};
31+
32+
std::ostream& operator<< (std::ostream& os, Moments const& mom);
33+
}
34+
35+
#if defined(AMREX_USE_CUDA) || defined(AMREX_USE_HIP)
36+
template<>
37+
struct Gpu::SharedMemory<openbc::Moments::array_type>
38+
{
39+
AMREX_GPU_DEVICE openbc::Moments::array_type* dataPtr () noexcept {
40+
AMREX_HIP_OR_CUDA(HIP_DYNAMIC_SHARED(openbc::Moments::array_type,amrex_openbc_momarray);,
41+
extern __shared__ openbc::Moments::array_type amrex_openbc_momarray[];)
42+
return amrex_openbc_momarray;
43+
}
44+
};
45+
#endif
46+
47+
/**
48+
* \brief Open Boundary Poisson Solver
49+
*
50+
* References:
51+
* (1) The Solution of Poisson's Equation for Isolated Source
52+
* Distributions, R. A. James, 1977, JCP 25, 71
53+
* (2) A Local Corrections Algorithm for Solving Poisson's Equation in Three
54+
* Dimensions, P. McCorquodale, P. Colella, G. T. Balls, & S. B. Baden,
55+
* 2007, Communications in Applied Mathematics and Computational Science,
56+
* 2, 1, 57-81
57+
*/
58+
class OpenBCSolver
59+
{
60+
public:
61+
OpenBCSolver ();
62+
63+
OpenBCSolver (const Vector<Geometry>& a_geom,
64+
const Vector<BoxArray>& a_grids,
65+
const Vector<DistributionMapping>& a_dmap,
66+
const LPInfo& a_info = LPInfo());
67+
68+
~OpenBCSolver ();
69+
70+
OpenBCSolver (const OpenBCSolver&) = delete;
71+
OpenBCSolver (OpenBCSolver&&) = delete;
72+
OpenBCSolver& operator= (const OpenBCSolver&) = delete;
73+
OpenBCSolver& operator= (OpenBCSolver&&) = delete;
74+
75+
void define (const Vector<Geometry>& a_geom,
76+
const Vector<BoxArray>& a_grids,
77+
const Vector<DistributionMapping>& a_dmap,
78+
const LPInfo& a_info = LPInfo());
79+
80+
void setVerbose (int v) noexcept;
81+
82+
Real solve (const Vector<MultiFab*>& a_sol, const Vector<MultiFab const*>& a_rhs,
83+
Real a_tol_rel, Real a_tol_abs);
84+
85+
public: // public for cuda
86+
87+
void compute_moments (Gpu::DeviceVector<openbc::Moments>& moments);
88+
void compute_potential (Gpu::DeviceVector<openbc::Moments> const& moments);
89+
void interpolate_potential (MultiFab& solg);
90+
91+
private:
92+
93+
#ifdef AMREX_USE_MPI
94+
void bcast_moments (Gpu::DeviceVector<openbc::Moments>& moments);
95+
#endif
96+
97+
int m_verbose = 0;
98+
Vector<Geometry> m_geom;
99+
Vector<BoxArray> m_grids;
100+
Vector<DistributionMapping> m_dmap;
101+
LPInfo m_info;
102+
std::unique_ptr<MLPoisson> m_poisson_1;
103+
std::unique_ptr<MLPoisson> m_poisson_2;
104+
std::unique_ptr<MLMG> m_mlmg_1;
105+
std::unique_ptr<MLMG> m_mlmg_2;
106+
107+
int m_coarsen_ratio = 0;
108+
Array<MultiFab,AMREX_SPACEDIM> m_dpdn;
109+
Gpu::PinnedVector<openbc::MomTag> m_momtags_h;
110+
#ifdef AMREX_USE_GPU
111+
Gpu::DeviceVector<openbc::MomTag> m_momtags_d;
112+
Gpu::PinnedVector<int> m_ngpublocks_h;
113+
Gpu::DeviceVector<int> m_ngpublocks_d;
114+
int m_nthreads_momtag;
115+
#endif
116+
117+
int m_nblocks_local = 0;
118+
int m_nblocks = 0;
119+
#ifdef AMREX_USE_MPI
120+
Vector<int> m_countvec;
121+
Vector<int> m_offset;
122+
#endif
123+
124+
IntVect m_ngrowdomain;
125+
MultiFab m_crse_grown_faces_phi;
126+
MultiFab m_phind;
127+
BoxArray m_bag;
128+
129+
BoxArray m_ba_all;
130+
DistributionMapping m_dm_all;
131+
Geometry m_geom_all;
132+
};
133+
134+
}
135+
136+
#endif

0 commit comments

Comments
 (0)