ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_ImplicitDiff_N.cpp File Reference
Include dependency graph for ERF_ImplicitDiff_N.cpp:

Macros

#define INSTANTIATE_IMPLICIT_DIFF_FOR_MOM(STAGDIR)
 

Functions

void ImplicitDiffForState_N (const Box &bx, const Box &domain, const int level, const Real dt, const GpuArray< Real, AMREX_SPACEDIM *2 > &bc_neumann_vals, const Array4< Real > &cell_data, const GpuArray< Real, AMREX_SPACEDIM > &cellSizeInv, const Array4< const Real > &hfx_z, const Array4< const Real > &mu_turb, const SolverChoice &solverChoice, const BCRec *bc_ptr, const bool use_SurfLayer, const Real implicit_fac)
 
template<int stagdir>
void ImplicitDiffForMom_N (const Box &bx, const Box &domain, const int level, const Real dt, const Array4< const Real > &cell_data, const Array4< Real > &face_data, const Array4< const Real > &tau_corr, const GpuArray< Real, AMREX_SPACEDIM > &cellSizeInv, const Array4< const Real > &mu_turb, const SolverChoice &solverChoice, const BCRec *bc_ptr, const bool use_SurfLayer, const Real implicit_fac)
 

Macro Definition Documentation

◆ INSTANTIATE_IMPLICIT_DIFF_FOR_MOM

#define INSTANTIATE_IMPLICIT_DIFF_FOR_MOM (   STAGDIR)
Value:
template void ImplicitDiffForMom_N<STAGDIR> ( \
const Box&, \
const Box&, \
const int, \
const Real, \
const Array4<const Real>&, \
const Array4< Real>&, \
const Array4<const Real>&, \
const GpuArray<Real, AMREX_SPACEDIM>&, \
const Array4<const Real>&, \
const SolverChoice&, \
const BCRec*, \
const bool, \
const Real);
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_DataStruct.H:128

Function Documentation

◆ ImplicitDiffForMom_N()

template<int stagdir>
void ImplicitDiffForMom_N ( const Box &  bx,
const Box &  domain,
const int  level,
const Real  dt,
const Array4< const Real > &  cell_data,
const Array4< Real > &  face_data,
const Array4< const Real > &  tau_corr,
const GpuArray< Real, AMREX_SPACEDIM > &  cellSizeInv,
const Array4< const Real > &  mu_turb,
const SolverChoice solverChoice,
const BCRec *  bc_ptr,
const bool  use_SurfLayer,
const Real  implicit_fac 
)

Function for computing the implicit contribution to the vertical diffusion of momentum, with a uniform grid and no terrain.

This function (explicitly instantiated below) handles staggering in x, y, or z through the template parameter, stagdir.

Parameters
[in]bxcell-centered box to loop over
[in]levelAMR level
[in]domainbox of the whole domain
[in]dttime step
[in]cell_dataconserved cell-centered rho
[in,out]face_dataconserved momentum
[in]tau_corrstress contribution to momentum that will be corrected by the implicit solve
[in]cellSizeInvinverse cell size array
[in]mu_turbturbulent viscosity
[in]solverChoicecontainer of parameters
[in]bc_ptrcontainer with boundary conditions
[in]use_SurfLayerwhether we have turned on subgrid diffusion
[in]implicit_facif 1 then fully implicit; if 0 then fully explicit
182 {
183  BL_PROFILE_VAR("ImplicitDiffForMom_N()",ImplicitDiffForMom_N);
184 
185  // setup quantities for getRhoAlphaAtFaces()
186  DiffChoice dc = solverChoice.diffChoice;
187  TurbChoice tc = solverChoice.turbChoice[level];
189  bool l_turb = tc.use_kturb;
190  Real mu_eff = (l_consA) ? 2.0 * dc.dynamic_viscosity / dc.rho0_trans
191  : 2.0 * dc.dynamic_viscosity;
192 
193  // g(S*) coefficient
194  // stagdir==0: tau_corr = 0.5 * du/dz * mu_tot
195  // stagdir==1: tau_corr = 0.5 * dv/dz * mu_tot
196  // stagdir==2: tau_corr = dw/dz * mu_tot
197  constexpr Real gfac = (stagdir == 2) ? 2.0/3.0 : 1.0;
198 
199  // offsets used to average to faces
200  constexpr int ioff = (stagdir == 0) ? 1 : 0;
201  constexpr int joff = (stagdir == 1) ? 1 : 0;
202 
203  // Box bounds
204  int ilo = bx.smallEnd(0);
205  int ihi = bx.bigEnd(0);
206  int jlo = bx.smallEnd(1);
207  int jhi = bx.bigEnd(1);
208  int klo = bx.smallEnd(2);
209  int khi = bx.bigEnd(2);
210  amrex::ignore_unused(ilo, ihi, jlo, jhi);
211 
212  // Temporary FABs for tridiagonal solve (allocated on column)
213  // A[k] * x[k-1] + B[k] * x[k] + C[k+1] = RHS[k]
214  amrex::FArrayBox RHS_fab, soln_fab, coeffA_fab, coeffB_fab, inv_coeffB_fab, coeffC_fab;
215  RHS_fab.resize(bx,1, amrex::The_Async_Arena());
216  soln_fab.resize(bx,1, amrex::The_Async_Arena());
217  coeffA_fab.resize(bx,1, amrex::The_Async_Arena());
218  coeffB_fab.resize(bx,1, amrex::The_Async_Arena());
219  inv_coeffB_fab.resize(bx,1, amrex::The_Async_Arena());
220  coeffC_fab.resize(bx,1, amrex::The_Async_Arena());
221  auto const& RHS_a = RHS_fab.array();
222  auto const& soln_a = soln_fab.array();
223  auto const& coeffA_a = coeffA_fab.array(); // lower diagonal
224  auto const& coeffB_a = coeffB_fab.array(); // diagonal
225  auto const& inv_coeffB_a = inv_coeffB_fab.array();
226  auto const& coeffC_a = coeffC_fab.array(); // upper diagonal
227 
228  const auto& dom_lo = lbound(domain);
229  const auto& dom_hi = ubound(domain);
230  Real dz_inv = cellSizeInv[2];
231 
232  int bc_comp = BCVars::xvel_bc + stagdir;
233  bool ext_dir_on_zlo = (bc_ptr[bc_comp].lo(2) == ERFBCType::ext_dir ||
234  bc_ptr[bc_comp].lo(2) == ERFBCType::ext_dir_prim);
235  bool ext_dir_on_zhi = (bc_ptr[bc_comp].hi(2) == ERFBCType::ext_dir ||
236  bc_ptr[bc_comp].hi(2) == ERFBCType::ext_dir_prim);
237  bool foextrap_on_zhi = (bc_ptr[bc_comp].hi(2) == ERFBCType::foextrap);
238  amrex::ignore_unused(foextrap_on_zhi);
239 
240  AMREX_ASSERT_WITH_MESSAGE(ext_dir_on_zlo || ext_dir_on_zhi || use_SurfLayer,
241  "Unexpected lower BC used with implicit vertical diffusion");
242  AMREX_ASSERT_WITH_MESSAGE(foextrap_on_zhi,
243  "Unexpected upper BC used with implicit vertical diffusion");
244  if (stagdir < 2 && (ext_dir_on_zlo || ext_dir_on_zhi)) {
245  amrex::Warning("No-slip walls have not been fully tested");
246  }
247 
248 #ifdef AMREX_USE_GPU
249  ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE (int i, int j, int)
250  {
251 #else
252  for (int j(jlo); j<=jhi; ++j) {
253  for (int i(ilo); i<=ihi; ++i) {
254 #endif
255  // Build the coefficients and RHS
256  for (int k(klo); k <= khi; k++)
257  {
258  // Note: either ioff or joff are 1
259  Real rhoface = 0.5 * (cell_data(i,j,k,Rho_comp) + cell_data(i-ioff,j-joff,k,Rho_comp));
260 
261  Real rhoAlpha_lo, rhoAlpha_hi;
262  getRhoAlphaForFaces(i, j, k, ioff, joff, rhoAlpha_lo, rhoAlpha_hi,
263  cell_data, mu_turb, mu_eff,
264  l_consA, l_turb);
265 
266  // Face data currently holds the _fully_ explicit solution, which
267  // will be used to determine the velocity gradient for the bottom
268  // BC
269  RHS_a(i,j,k) = face_data(i,j,k); // Note this is momentum but solution will be velocity
270 
271  // Notes:
272  //
273  // - In DiffusionSrcForMom (e.g., for x-mom)
274  //
275  // Real diffContrib = ...
276  // + (tau13(i,j,k+1) - tau13(i,j,k)) / dzinv
277  // rho_u_rhs(i,j,k) -= diffContrib; // note the negative sign
278  //
279  // - We need to scale the explicit _part_ of `tau13` (for x-mom) by (1 - implicit_fac)
280  // The part that needs to be scaled is stored in `tau_corr`.
281  // E.g., tau13 = 0.5 * (du/dz + dw/dx)
282  // tau13_corr = 0.5 * du/dz
283  //
284  // - The momentum (`face_data`) was set to `S_old + S_rhs * dt`
285  // prior to including "ERF_Implicit.H". Recall that S_rhs includes
286  // sources from advection and other forcings, not just diffusion.
287  //
288  // - To correct momentum, we need to subtract `implicit_fac * diffContrib_corr`
289  // from S_rhs to recover `(1 - implicit_fac) * diffContrib_corr`,
290  // where `diffContrib_corr = -d(tau_corr)/dz`. The negative sign
291  // comes from our convention for the RHS diffusion source.
292  //
293  // Subtracting a negative gives the += below; multiply by dt to
294  // get the intermediate momentum on the RHS of the tridiagonal
295  // system.
296  RHS_a(i,j,k) += implicit_fac * gfac * (tau_corr(i,j,k+1) - tau_corr(i,j,k))*dz_inv * dt;
297 
298  // This represents the face-centered finite difference of two
299  // edge-centered finite differences (hi and lo)
300  coeffA_a(i,j,k) = -implicit_fac * gfac * rhoAlpha_lo * dt * dz_inv * dz_inv;
301  coeffC_a(i,j,k) = -implicit_fac * gfac * rhoAlpha_hi * dt * dz_inv * dz_inv;
302 
303  // Setup BCs
304  if (k == dom_lo.z) {
305  if (ext_dir_on_zlo) {
306  // This can be a no-slip wall (u = v = w = 0), slip wall (w = 0), or surface layer (w = 0)
307  if (stagdir==2) {
308  coeffC_a(i,j,klo) = 0.;
309  RHS_a(i,j,klo) = 0.;
310  } else {
311  // first-order:
312  // u(klo) - (u(klo+1) - u(klo)) * 1/2 = u_dir
313  coeffC_a(i,j,klo) = -0.5;
314  RHS_a(i,j,klo) = face_data(i,j,klo-1); // Dirichlet value
315  }
316  } else if (use_SurfLayer) {
317  // Match explicit grad(u) at the surface
318  Real uhi = 2.0 * face_data(i,j,klo ) / (cell_data(i,j,klo ,Rho_comp) + cell_data(i-ioff,j-joff,klo ,Rho_comp));
319  Real ulo = 2.0 * face_data(i,j,klo-1) / (cell_data(i,j,klo-1,Rho_comp) + cell_data(i-ioff,j-joff,klo-1,Rho_comp));
320  RHS_a(i,j,klo) += coeffA_a(i,j,klo) * (uhi - ulo);
321  }
322 
323  // default is foextrap
324  coeffA_a(i,j,klo) = 0.;
325  }
326  if (k == dom_hi.z) {
327  if (ext_dir_on_zhi) {
328  if (stagdir==2) {
329  coeffA_a(i,j,khi) = 0.;
330  RHS_a(i,j,khi) = 0.;
331  } else {
332  // first-order:
333  // u(khi) + (u(khi) - u(khi-1)) * 1/2 = u_dir
334  coeffA_a(i,j,khi) = -0.5;
335  RHS_a(i,j,khi) = face_data(i,j,khi+1); // Dirichlet value
336  }
337  }
338 
339  // default is foextrap
340  coeffC_a(i,j,khi) = 0.;
341  }
342 
343  coeffB_a(i,j,k) = rhoface - coeffA_a(i,j,k) - coeffC_a(i,j,k);
344  } // k
345 
346  SolveTridiag(i,j,klo,khi,soln_a,coeffA_a,coeffB_a,inv_coeffB_a,coeffC_a,RHS_a);
347  for (int k(klo); k<=khi; ++k) {
348  Real rhoface = 0.5 * (cell_data(i,j,k,Rho_comp) + cell_data(i-ioff,j-joff,k,Rho_comp));
349  face_data(i,j,k) = rhoface * soln_a(i,j,k);
350  }
351 
352 #ifdef AMREX_USE_GPU
353  });
354 #else
355  } // i
356  } // j
357 #endif
358 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void getRhoAlphaForFaces(int i, int j, int k, int ioff, int joff, amrex::Real &rhoAlpha_lo, amrex::Real &rhoAlpha_hi, const amrex::Array4< const amrex::Real > &cell_data, const amrex::Array4< const amrex::Real > &mu_turb, const amrex::Real mu_eff, bool l_consA, bool l_turb)
Definition: ERF_GetRhoAlphaForFaces.H:5
void ImplicitDiffForMom_N(const Box &bx, const Box &domain, const int level, const Real dt, const Array4< const Real > &cell_data, const Array4< Real > &face_data, const Array4< const Real > &tau_corr, const GpuArray< Real, AMREX_SPACEDIM > &cellSizeInv, const Array4< const Real > &mu_turb, const SolverChoice &solverChoice, const BCRec *bc_ptr, const bool use_SurfLayer, const Real implicit_fac)
Definition: ERF_ImplicitDiff_N.cpp:169
#define Rho_comp
Definition: ERF_IndexDefines.H:36
const auto & dom_hi
Definition: ERF_SetupVertDiff.H:2
bool l_turb
Definition: ERF_SetupVertDiff.H:8
const auto & dom_lo
Definition: ERF_SetupVertDiff.H:1
bool l_consA
Definition: ERF_SetupVertDiff.H:7
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void SolveTridiag(int i, int j, int klo, int khi, const amrex::Array4< amrex::Real > &soln_a, const amrex::Array4< const amrex::Real > &coeffA_a, const amrex::Array4< amrex::Real > &coeffB_a, const amrex::Array4< amrex::Real > &inv_coeffB_a, const amrex::Array4< const amrex::Real > &coeffC_a, const amrex::Array4< const amrex::Real > &RHS_a)
Definition: ERF_SolveTridiag.H:6
@ xvel_bc
Definition: ERF_IndexDefines.H:87
@ foextrap
Definition: ERF_IndexDefines.H:208
@ ext_dir
Definition: ERF_IndexDefines.H:209
@ ext_dir_prim
Definition: ERF_IndexDefines.H:211
Definition: ERF_DiffStruct.H:19
amrex::Real rho0_trans
Definition: ERF_DiffStruct.H:91
MolecDiffType molec_diff_type
Definition: ERF_DiffStruct.H:84
amrex::Real dynamic_viscosity
Definition: ERF_DiffStruct.H:96
DiffChoice diffChoice
Definition: ERF_DataStruct.H:992
amrex::Vector< TurbChoice > turbChoice
Definition: ERF_DataStruct.H:995
Definition: ERF_TurbStruct.H:41
bool use_kturb
Definition: ERF_TurbStruct.H:396
Here is the call graph for this function:

◆ ImplicitDiffForState_N()

void ImplicitDiffForState_N ( const Box &  bx,
const Box &  domain,
const int  level,
const Real  dt,
const GpuArray< Real, AMREX_SPACEDIM *2 > &  bc_neumann_vals,
const Array4< Real > &  cell_data,
const GpuArray< Real, AMREX_SPACEDIM > &  cellSizeInv,
const Array4< const Real > &  hfx_z,
const Array4< const Real > &  mu_turb,
const SolverChoice solverChoice,
const BCRec *  bc_ptr,
const bool  use_SurfLayer,
const Real  implicit_fac 
)

Function for computing the implicit contribution to the vertical diffusion of theta, with a uniform grid and no terrain.

Parameters
[in]bxcell-centered box to loop over
[in]levelAMR level
[in]domainbox of the whole domain
[in]dttime step
[in]bc_neumann_valsvalues of derivatives if bc_type == Neumann
[in,out]cell_dataconserved cell-centered rho, rho theta
[in]cellSizeInvinverse cell size array
[in,out]hfx_zheat flux in z-dir
[in]mu_turbturbulent viscosity
[in]solverChoicecontainer of parameters
[in]bc_ptrcontainer with boundary conditions
[in]use_SurfLayerwhether we have turned on subgrid diffusion
[in]implicit_facif 1 then fully implicit; if 0 then fully explicit
41 {
42  BL_PROFILE_VAR("ImplicitDiffForState_N()",ImplicitDiffForState_N);
43 
44  // setup quantities for getRhoAlpha()
45 #include "ERF_SetupVertDiff.H"
46  const int n = RhoTheta_comp;
47  const int qty_index = RhoTheta_comp;
48  const int prim_index = qty_index - 1;
49  const int prim_scal_index = (qty_index >= RhoScalar_comp && qty_index < RhoScalar_comp+NSCALARS) ? PrimScalar_comp : prim_index;
50 
51  // Box bounds
52  int ilo = bx.smallEnd(0);
53  int ihi = bx.bigEnd(0);
54  int jlo = bx.smallEnd(1);
55  int jhi = bx.bigEnd(1);
56  int klo = bx.smallEnd(2);
57  int khi = bx.bigEnd(2);
58  amrex::ignore_unused(ilo, ihi, jlo, jhi);
59 
60  // Temporary FABs for tridiagonal solve (allocated on column)
61  // A[k] * x[k-1] + B[k] * x[k] + C[k+1] = RHS[k]
62  amrex::FArrayBox RHS_fab, soln_fab, coeffA_fab, coeffB_fab, inv_coeffB_fab, coeffC_fab;
63  RHS_fab.resize(bx,1, amrex::The_Async_Arena());
64  soln_fab.resize(bx,1, amrex::The_Async_Arena());
65  coeffA_fab.resize(bx,1, amrex::The_Async_Arena());
66  coeffB_fab.resize(bx,1, amrex::The_Async_Arena());
67  inv_coeffB_fab.resize(bx,1, amrex::The_Async_Arena());
68  coeffC_fab.resize(bx,1, amrex::The_Async_Arena());
69  auto const& RHS_a = RHS_fab.array();
70  auto const& soln_a = soln_fab.array();
71  auto const& coeffA_a = coeffA_fab.array(); // lower diagonal
72  auto const& coeffB_a = coeffB_fab.array(); // diagonal
73  auto const& inv_coeffB_a = inv_coeffB_fab.array();
74  auto const& coeffC_a = coeffC_fab.array(); // upper diagonal
75 
76  Real dz_inv = cellSizeInv[2];
77 
78  int bc_comp = qty_index;
79  bool foextrap_on_zlo = (bc_ptr[bc_comp].lo(2) == ERFBCType::foextrap);
80  bool foextrap_on_zhi = (bc_ptr[bc_comp].hi(2) == ERFBCType::foextrap);
81  bool neumann_on_zlo = (bc_ptr[bc_comp].lo(2) == ERFBCType::neumann);
82  bool neumann_on_zhi = (bc_ptr[bc_comp].hi(2) == ERFBCType::neumann);
83  amrex::ignore_unused(foextrap_on_zlo, foextrap_on_zhi);
84 
85  AMREX_ASSERT_WITH_MESSAGE(foextrap_on_zlo || neumann_on_zlo || use_SurfLayer,
86  "Unexpected lower BC used with implicit vertical diffusion");
87  AMREX_ASSERT_WITH_MESSAGE(foextrap_on_zhi || neumann_on_zhi,
88  "Unexpected upper BC used with implicit vertical diffusion");
89 
90 #ifdef AMREX_USE_GPU
91  ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE (int i, int j, int)
92  {
93 #else
94  for (int j(jlo); j<=jhi; ++j) {
95  for (int i(ilo); i<=ihi; ++i) {
96 #endif
97  // Build the coefficients and RHS
98  for (int k(klo); k <= khi; k++)
99  {
100  Real rhoAlpha_lo, rhoAlpha_hi;
101  getRhoAlpha(i, j, k, rhoAlpha_lo, rhoAlpha_hi,
102  cell_data, mu_turb, d_alpha_eff, d_eddy_diff_idz,
103  prim_index, prim_scal_index, l_consA, l_turb);
104 
105  RHS_a(i,j,k) = cell_data(i,j,k,n); // Note this is rho*theta, whereas solution will be theta
106 
107  // This represents the cell-centered finite difference of two
108  // face-centered finite differences (hi and lo)
109  coeffA_a(i,j,k) = -implicit_fac * rhoAlpha_lo * dt * dz_inv * dz_inv;
110  coeffC_a(i,j,k) = -implicit_fac * rhoAlpha_hi * dt * dz_inv * dz_inv;
111 
112  // Setup BCs
113  if (k == dom_lo.z) {
114  if (use_SurfLayer) {
115  RHS_a(i,j,klo) += implicit_fac * dt * dz_inv * hfx_z(i,j,0);
116  } else if (neumann_on_zlo) {
117  RHS_a(i,j,klo) += coeffA_a(i,j,klo) * bc_neumann_vals[2] / dz_inv;
118  }
119 
120  coeffA_a(i,j,klo) = 0.;
121  }
122  if (k == dom_hi.z) {
123  if (neumann_on_zhi) {
124  RHS_a(i,j,khi) -= coeffC_a(i,j,khi) * bc_neumann_vals[5] / dz_inv;
125  }
126 
127  coeffC_a(i,j,khi) = 0.;
128  }
129 
130  coeffB_a(i,j,k) = cell_data(i,j,k,Rho_comp) - coeffA_a(i,j,k) - coeffC_a(i,j,k);
131  } // k
132 
133  SolveTridiag(i,j,klo,khi,soln_a,coeffA_a,coeffB_a,inv_coeffB_a,coeffC_a,RHS_a);
134  for (int k(klo); k<=khi; ++k) {
135  cell_data(i,j,k,n) = cell_data(i,j,k,Rho_comp) * soln_a(i,j,k);
136  }
137 
138 #ifdef AMREX_USE_GPU
139  });
140 #else
141  } // i
142  } // j
143 #endif
144 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void getRhoAlpha(int i, int j, int k, amrex::Real &rhoAlpha_lo, amrex::Real &rhoAlpha_hi, const amrex::Array4< const amrex::Real > &cell_data, const amrex::Array4< const amrex::Real > &mu_turb, const amrex::Real *d_alpha_eff, const int *d_eddy_diff_idz, int prim_index, int prim_scal_index, bool l_consA, bool l_turb)
Definition: ERF_GetRhoAlpha.H:5
void ImplicitDiffForState_N(const Box &bx, const Box &domain, const int level, const Real dt, const GpuArray< Real, AMREX_SPACEDIM *2 > &bc_neumann_vals, const Array4< Real > &cell_data, const GpuArray< Real, AMREX_SPACEDIM > &cellSizeInv, const Array4< const Real > &hfx_z, const Array4< const Real > &mu_turb, const SolverChoice &solverChoice, const BCRec *bc_ptr, const bool use_SurfLayer, const Real implicit_fac)
Definition: ERF_ImplicitDiff_N.cpp:29
#define RhoScalar_comp
Definition: ERF_IndexDefines.H:40
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
#define NSCALARS
Definition: ERF_IndexDefines.H:16
#define PrimScalar_comp
Definition: ERF_IndexDefines.H:52
int * d_eddy_diff_idz
Definition: ERF_SetupVertDiff.H:107
Real * d_alpha_eff
Definition: ERF_SetupVertDiff.H:104
@ neumann
Definition: ERF_IndexDefines.H:213
Here is the call graph for this function: