ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_SolveWithEBMLMG.cpp File Reference
#include "ERF.H"
#include "ERF_EB.H"
#include "ERF_Utils.H"
#include "ERF_SolverUtils.H"
#include <AMReX_MLMG.H>
#include <AMReX_MLEBABecLap.H>
Include dependency graph for ERF_SolveWithEBMLMG.cpp:

Functions

template<typename T >
void FillZeroAreaFaceFluxes (MultiFab &phi, Array< MultiFab, AMREX_SPACEDIM > &fluxes, const Geometry &geom, EBFArrayBoxFactory const &ebfact, T const &ebfact_u, T const &ebfact_v, T const &ebfact_w)
 
template<typename T >
void solve_with_EB_mlmg (int lev, Vector< MultiFab > &rhs, Vector< MultiFab > &phi, Vector< Array< MultiFab, AMREX_SPACEDIM >> &fluxes, EBFArrayBoxFactory const &ebfact, T const &ebfact_u, T const &ebfact_v, T const &ebfact_w, const Geometry &geom, const Vector< amrex::IntVect > &ref_ratio, Array< std::string, 2 *AMREX_SPACEDIM > domain_bc_type, int mg_verbose, Real reltol, Real abstol)
 
template void solve_with_EB_mlmg (int, Vector< MultiFab > &, Vector< MultiFab > &, Vector< Array< MultiFab, AMREX_SPACEDIM >> &, EBFArrayBoxFactory const &, EBFArrayBoxFactory const &, EBFArrayBoxFactory const &, EBFArrayBoxFactory const &, const Geometry &, const Vector< amrex::IntVect > &, Array< std::string, 2 *AMREX_SPACEDIM >, int, Real, Real)
 
template void solve_with_EB_mlmg (int, Vector< MultiFab > &, Vector< MultiFab > &, Vector< Array< MultiFab, AMREX_SPACEDIM >> &, EBFArrayBoxFactory const &, eb_aux_ const &, eb_aux_ const &, eb_aux_ const &, const Geometry &, const Vector< amrex::IntVect > &, Array< std::string, 2 *AMREX_SPACEDIM >, int, Real, Real)
 

Function Documentation

◆ FillZeroAreaFaceFluxes()

template<typename T >
void FillZeroAreaFaceFluxes ( MultiFab &  phi,
Array< MultiFab, AMREX_SPACEDIM > &  fluxes,
const Geometry &  geom,
EBFArrayBoxFactory const &  ebfact,
T const &  ebfact_u,
T const &  ebfact_v,
T const &  ebfact_w 
)

Compute phi gradients where the area of the face is zero

Template Parameters
TEB factory or auxiliary EB data type for face-centered grids
Parameters
phiCell-centered solution used to compute gradients
fluxesFace-centered gradient fluxes to fill
geomGeometry used for inverse cell spacing
ebfactCell-centered embedded-boundary factory
ebfact_uEmbedded-boundary data on x-faces
ebfact_vEmbedded-boundary data on y-faces
ebfact_wEmbedded-boundary data on z-faces
26 {
27  BL_PROFILE("ERF::FillZeroAreaFaceFluxes()");
28 
29  const GpuArray<Real, AMREX_SPACEDIM> dxInv = geom.InvCellSizeArray();
30 
31  for (MFIter mfi(phi,TileNoZ()); mfi.isValid(); ++mfi)
32  {
33  const Box& tbx = mfi.tilebox();
34  const Box& xbx = mfi.nodaltilebox(0);
35  const Box& ybx = mfi.nodaltilebox(1);
36  const Box& zbx = mfi.nodaltilebox(2);
37 
38  // EBCellFlagFab const& cflag_fab = (ebfact.get_const_factory())->getMultiEBCellFlagFab()[mfi];
39  EBCellFlagFab const& cflag_fab = (ebfact.getMultiEBCellFlagFab())[mfi];
40  Array4<const EBCellFlag> cflag = cflag_fab.const_array();
41 
42  if (cflag_fab.getType(tbx) == FabType::singlevalued)
43  {
44  Array4<const Real> apx = ebfact.getAreaFrac()[0]->const_array(mfi);
45  Array4<const Real> apy = ebfact.getAreaFrac()[1]->const_array(mfi);
46  Array4<const Real> apz = ebfact.getAreaFrac()[2]->const_array(mfi);
47 
48  Array4<const EBCellFlag> u_cflag = ebfact_u.getMultiEBCellFlagFab()[mfi].const_array();
49  Array4<const EBCellFlag> v_cflag = ebfact_v.getMultiEBCellFlagFab()[mfi].const_array();
50  Array4<const EBCellFlag> w_cflag = ebfact_w.getMultiEBCellFlagFab()[mfi].const_array();
51 
52  Array4<Real const> const& p_arr = phi.const_array(mfi);
53  Array4<Real> const& fx = fluxes[0].array(mfi);
54  Array4<Real> const& fy = fluxes[1].array(mfi);
55  Array4<Real> const& fz = fluxes[2].array(mfi);
56 
57  ParallelFor(xbx, ybx, zbx,
58  // x-face
59  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
60  {
61  if (apx(i,j,k) == zero) {
62  if (!u_cflag(i,j,k).isCovered()) {
63  if (cflag(i,j,k).isCovered() && !cflag(i-1,j,k).isCovered()) {
64  fx(i,j,k) = dxInv[0] * (p_arr(i-3,j,k) - three*p_arr(i-2,j,k) + two*p_arr(i-1,j,k));
65  } else if (cflag(i-1,j,k).isCovered() && !cflag(i,j,k).isCovered()) {
66  fx(i,j,k) = dxInv[0] * (three*p_arr(i+1,j,k) - p_arr(i+2,j,k) - two*p_arr(i,j,k));
67  }
68  }
69  }
70  },
71  // y-face
72  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
73  {
74  if (apy(i,j,k) == zero) {
75  if (!v_cflag(i,j,k).isCovered()) {
76  if (cflag(i,j,k).isCovered() && !cflag(i,j-1,k).isCovered()) {
77  fy(i,j,k) = dxInv[1] * (p_arr(i,j-3,k) - three*p_arr(i,j-2,k) + two*p_arr(i,j-1,k));
78  } else if (cflag(i,j-1,k).isCovered() && !cflag(i,j,k).isCovered()) {
79  fy(i,j,k) = dxInv[1] * (three*p_arr(i,j+1,k) - p_arr(i,j+2,k) - two*p_arr(i,j,k));
80  }
81  }
82  }
83  },
84  // z-face
85  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
86  {
87  if (apz(i,j,k) == zero) {
88  if (!w_cflag(i,j,k).isCovered()) {
89  if (cflag(i,j,k).isCovered() && !cflag(i,j,k-1).isCovered()) {
90  fz(i,j,k) = dxInv[2] * (p_arr(i,j,k-3) - three*p_arr(i,j,k-2) + two*p_arr(i,j,k-1));
91  } else if (cflag(i,j,k-1).isCovered() && !cflag(i,j,k).isCovered()) {
92  fz(i,j,k) = dxInv[2] * (three*p_arr(i,j,k+1) - p_arr(i,j,k+2) - two*p_arr(i,j,k));
93  }
94  }
95  }
96  });
97  } // single-valued
98  } // mfi
99 }
constexpr amrex::Real three
Definition: ERF_Constants.H:11
constexpr amrex::Real two
Definition: ERF_Constants.H:10
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
amrex::GpuArray< Real, AMREX_SPACEDIM > dxInv
Definition: ERF_InitCustomPertVels_ParticleTests.H:17
ParallelFor(fab_box, [=] AMREX_GPU_DEVICE(int i, int j, int k) { qrcuten_arr(i, j, k)=Real(0);qscuten_arr(i, j, k)=Real(0);qicuten_arr(i, j, k)=Real(0);})
AMREX_FORCE_INLINE amrex::IntVect TileNoZ()
Definition: ERF_TileNoZ.H:11

Referenced by solve_with_EB_mlmg().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ solve_with_EB_mlmg() [1/3]

template<typename T >
void solve_with_EB_mlmg ( int  lev,
Vector< MultiFab > &  rhs,
Vector< MultiFab > &  phi,
Vector< Array< MultiFab, AMREX_SPACEDIM >> &  fluxes,
EBFArrayBoxFactory const &  ebfact,
T const &  ebfact_u,
T const &  ebfact_v,
T const &  ebfact_w,
const Geometry &  geom,
const Vector< amrex::IntVect > &  ref_ratio,
Array< std::string, 2 *AMREX_SPACEDIM >  domain_bc_type,
int  mg_verbose,
Real  reltol,
Real  abstol 
)

Solve the Poisson equation using EB_enabled MLMG Note that the level may or may not be level zero

Important: we solve on the whole level even if there are disjoint regions

Template Parameters
TEB factory or auxiliary EB data type for face-centered grids
Parameters
levLevel index for the solve
rhsRight-hand side MultiFab vector
phiSolution MultiFab vector to fill
fluxesFace-centered gradient fluxes to fill
ebfactCell-centered embedded-boundary factory
ebfact_uEmbedded-boundary data on x-faces
ebfact_vEmbedded-boundary data on y-faces
ebfact_wEmbedded-boundary data on z-faces
geomGeometry for the solve level
ref_ratioCoarse-fine refinement ratios
domain_bc_typeDomain boundary-condition names
mg_verboseMLMG verbosity level
reltolRelative solver tolerance
abstolAbsolute solver tolerance
58 {
59  BL_PROFILE("ERF::solve_with_EB_mlmg()");
60 
61  auto const dom_lo = lbound(geom.Domain());
62  auto const dom_hi = ubound(geom.Domain());
63 
64  LPInfo info;
65  // Allow a hidden direction if the domain is one cell wide in any lateral direction
66  if (dom_lo.x == dom_hi.x) {
67  info.setHiddenDirection(0);
68  } else if (dom_lo.y == dom_hi.y) {
69  info.setHiddenDirection(1);
70  }
71 
72  // Make sure the solver only sees the levels over which we are solving
73  Vector<BoxArray> ba_tmp; ba_tmp.push_back(rhs[0].boxArray());
74  Vector<DistributionMapping> dm_tmp; dm_tmp.push_back(rhs[0].DistributionMap());
75  Vector<Geometry> geom_tmp; geom_tmp.push_back(geom);
76 
77  auto bclo = get_lo_projection_bc(geom,domain_bc_type);
78  auto bchi = get_hi_projection_bc(geom,domain_bc_type);
79 
80  amrex::Print() << "BCLO " << bclo[0] << " " << bclo[1] << " " << bclo[2] << std::endl;
81  amrex::Print() << "BCHI " << bchi[0] << " " << bchi[1] << " " << bchi[2] << std::endl;
82 
83  // ****************************************************************************
84  // Multigrid solve
85  // ****************************************************************************
86 
87  MLEBABecLap mleb (geom_tmp, ba_tmp, dm_tmp, info, {&ebfact});
88 
89  mleb.setMaxOrder(2);
90  mleb.setDomainBC(bclo, bchi);
91  if (lev > 0) {
92  mleb.setCoarseFineBC(nullptr, ref_ratio[lev-1], LinOpBCType::Neumann);
93  }
94  mleb.setLevelBC(0, nullptr);
95 
96  //
97  // This sets A = 0, B = 1 so that
98  // the operator A alpha - b del dot beta grad to b
99  // becomes - del dot beta grad
100  //
101  mleb.setScalars(zero, one);
102 
103  Array<MultiFab,AMREX_SPACEDIM> bcoef;
104  for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
105  bcoef[idim].define(convert(ba_tmp[0],IntVect::TheDimensionVector(idim)),
106  dm_tmp[0], 1, 0, MFInfo(), ebfact);
107  bcoef[idim].setVal(-1.0);
108  }
109  mleb.setBCoeffs(0, amrex::GetArrOfConstPtrs(bcoef));
110 
111  MLMG mlmg(mleb);
112 
113  int max_iter = 100;
114  mlmg.setMaxIter(max_iter);
115  mlmg.setVerbose(mg_verbose);
116  mlmg.setBottomVerbose(0);
117 
118  mlmg.solve(GetVecOfPtrs(phi), GetVecOfConstPtrs(rhs), reltol, abstol);
119 
120  mlmg.getFluxes(GetVecOfArrOfPtrs(fluxes));
121 
122  // Add the flux values (gradient phi) to the face-centered cell with zero area fraction
123  // (mlmg.getFluxes does not fill gradient phi at faces with zero area fraction)
124  FillZeroAreaFaceFluxes(phi[0], fluxes[0], geom, ebfact, ebfact_u, ebfact_v, ebfact_w);
125 
126  // ImposeBCsOnPhi(lev,phi[0], geom[lev].Domain());
127 
128  //
129  // This arises because we solve MINUS del dot beta grad phi = div (rho u)
130  //
131  fluxes[0][0].mult(-one);
132  fluxes[0][1].mult(-one);
133  fluxes[0][2].mult(-one);
134 }
constexpr amrex::Real one
Definition: ERF_Constants.H:9
void FillZeroAreaFaceFluxes(MultiFab &phi, Array< MultiFab, AMREX_SPACEDIM > &fluxes, const Geometry &geom, EBFArrayBoxFactory const &ebfact, T const &ebfact_u, T const &ebfact_v, T const &ebfact_w)
Definition: ERF_FillZeroAreaFaceFluxes.cpp:23
Array< LinOpBCType, AMREX_SPACEDIM > get_lo_projection_bc(Geometry const &lev_geom, Array< std::string, 2 *AMREX_SPACEDIM > l_domain_bc_type)
Definition: ERF_SolverUtils.H:20
Array< LinOpBCType, AMREX_SPACEDIM > get_hi_projection_bc(Geometry const &lev_geom, Array< std::string, 2 *AMREX_SPACEDIM > l_domain_bc_type)
Definition: ERF_SolverUtils.H:48
Here is the call graph for this function:

◆ solve_with_EB_mlmg() [2/3]

template void solve_with_EB_mlmg ( int  ,
Vector< MultiFab > &  ,
Vector< MultiFab > &  ,
Vector< Array< MultiFab, AMREX_SPACEDIM >> &  ,
EBFArrayBoxFactory const &  ,
eb_aux_ const &  ,
eb_aux_ const &  ,
eb_aux_ const &  ,
const Geometry &  ,
const Vector< amrex::IntVect > &  ,
Array< std::string, 2 *AMREX_SPACEDIM >  ,
int  ,
Real  ,
Real   
)

◆ solve_with_EB_mlmg() [3/3]

template void solve_with_EB_mlmg ( int  ,
Vector< MultiFab > &  ,
Vector< MultiFab > &  ,
Vector< Array< MultiFab, AMREX_SPACEDIM >> &  ,
EBFArrayBoxFactory const &  ,
EBFArrayBoxFactory const &  ,
EBFArrayBoxFactory const &  ,
EBFArrayBoxFactory const &  ,
const Geometry &  ,
const Vector< amrex::IntVect > &  ,
Array< std::string, 2 *AMREX_SPACEDIM >  ,
int  ,
Real  ,
Real   
)