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

Macros

#define INSTANTIATE_IMPLICIT_DIFF_FOR_MOM_LU(STAGDIR)
 

Functions

void ImplicitDiffForStateLU_S (const Box &bx, const Box &domain, const int level, const int n, const double dt_d, const GpuArray< Real, AMREX_SPACEDIM *2 > &bc_neumann_vals, const Array4< Real > &cell_data, const Gpu::DeviceVector< Real > &stretched_dz_d, const Array4< const Real > &scalar_zflux, const Array4< const Real > &mu_turb, const SolverChoice &solverChoice, const BCRec *bc_ptr, const bool use_SurfLayer, const Real implicit_fac, const bool use_mrf_countergradient)
 
template<int stagdir>
void ImplicitDiffForMomLU_S (const Box &bx, const Box &, const int level, const double dt_d, const Array4< const Real > &cell_data, const Array4< Real > &face_data, const Array4< const Real > &tau, const Array4< const Real > &tau_corr, const Gpu::DeviceVector< Real > &stretched_dz_d, const Array4< const Real > &mu_turb, const SolverChoice &solverChoice, const BCRec *bc_ptr, const bool use_SurfLayer, const Real implicit_fac, const bool use_ysu_mom_countergradient)
 

Macro Definition Documentation

◆ INSTANTIATE_IMPLICIT_DIFF_FOR_MOM_LU

#define INSTANTIATE_IMPLICIT_DIFF_FOR_MOM_LU (   STAGDIR)
Value:
template void ImplicitDiffForMomLU_S<STAGDIR> ( \
const Box&, \
const Box&, \
const int, \
const double, \
const Array4<const Real>&, \
const Array4< Real>&, \
const Array4<const Real>&, \
const Array4<const Real>&, \
const Gpu::DeviceVector<Real>&, \
const Array4<const Real>&, \
const SolverChoice&, \
const BCRec*, \
const bool, \
const Real, \
const bool);
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_DataStruct.H:141

Function Documentation

◆ ImplicitDiffForMomLU_S()

template<int stagdir>
void ImplicitDiffForMomLU_S ( const Box &  bx,
const Box &  ,
const int  level,
const double  dt_d,
const Array4< const Real > &  cell_data,
const Array4< Real > &  face_data,
const Array4< const Real > &  tau,
const Array4< const Real > &  tau_corr,
const Gpu::DeviceVector< Real > &  stretched_dz_d,
const Array4< const Real > &  mu_turb,
const SolverChoice solverChoice,
const BCRec *  bc_ptr,
const bool  use_SurfLayer,
const Real  implicit_fac,
const bool  use_ysu_mom_countergradient 
)

Function for computing the implicit contribution to the vertical diffusion of momentum, with a vertically stretched grid over flat 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]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]stretched_dz_darray over z of dz[k]
[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
253 {
254  BL_PROFILE_VAR("ImplicitDiffForMom_S()",ImplicitDiffForMom_S);
255 
256  Real dt = static_cast<Real>(dt_d);
257 
258  // setup quantities for getRhoAlphaAtFaces()
259  DiffChoice dc = solverChoice.diffChoice;
260  TurbChoice tc = solverChoice.turbChoice[level];
262  bool l_turb = tc.use_kturb;
263  Real mu_eff = (l_consA) ? two * dc.dynamic_viscosity / dc.rho0_trans
264  : two * dc.dynamic_viscosity;
265 
266  // g(S*) coefficient
267  // stagdir==0: tau_corr = myhalf * du/dz * mu_tot
268  // stagdir==1: tau_corr = myhalf * dv/dz * mu_tot
269  // stagdir==2: tau_corr = dw/dz * mu_tot
270  constexpr Real gfac = (stagdir == 2) ? two/three : one;
271 
272  // offsets used to average to faces
273  constexpr int ioff = (stagdir == 0) ? 1 : 0;
274  constexpr int joff = (stagdir == 1) ? 1 : 0;
275 
276  // Box bounds
277  int ilo = bx.smallEnd(0);
278  int ihi = bx.bigEnd(0);
279  int jlo = bx.smallEnd(1);
280  int jhi = bx.bigEnd(1);
281  int klo = bx.smallEnd(2);
282  int khi = bx.bigEnd(2);
283  amrex::ignore_unused(ilo, ihi, jlo, jhi);
284 
285  // Temporary FABs for tridiagonal solve (allocated on column)
286  // A[k] * x[k-1] + B[k] * x[k] + C[k+1] = RHS[k]
287  amrex::FArrayBox RHS_fab, soln_fab, coeffG_fab;
288  RHS_fab.resize(bx,1, amrex::The_Async_Arena());
289  soln_fab.resize(bx,1, amrex::The_Async_Arena());
290  coeffG_fab.resize(bx,1, amrex::The_Async_Arena());
291  auto const& RHS_a = RHS_fab.array();
292  auto const& soln_a = soln_fab.array();
293  auto const& coeffG_a = coeffG_fab.array();
294 
295  auto dz_ptr = stretched_dz_d.data();
296 
297  int bc_comp = BCVars::xvel_bc + stagdir;
298  bool ext_dir_on_zlo = (bc_ptr[bc_comp].lo(2) == ERFBCType::ext_dir ||
299  bc_ptr[bc_comp].lo(2) == ERFBCType::ext_dir_prim);
300  bool ext_dir_on_zhi = (bc_ptr[bc_comp].hi(2) == ERFBCType::ext_dir ||
301  bc_ptr[bc_comp].hi(2) == ERFBCType::ext_dir_prim);
302  bool foextrap_on_zlo = (bc_ptr[bc_comp].lo(2) == ERFBCType::foextrap);
303  bool foextrap_on_zhi = (bc_ptr[bc_comp].hi(2) == ERFBCType::foextrap);
304  amrex::ignore_unused(foextrap_on_zlo,foextrap_on_zhi);
305 
306  AMREX_ASSERT_WITH_MESSAGE(foextrap_on_zlo || ext_dir_on_zlo || use_SurfLayer,
307  "Unexpected lower BC for momentum used with implicit vertical diffusion");
308  AMREX_ASSERT_WITH_MESSAGE(foextrap_on_zhi || ext_dir_on_zhi,
309  "Unexpected upper BC for momentum used with implicit vertical diffusion");
310 
311  Real Fact = implicit_fac * dt;
312 
313 #ifdef AMREX_USE_GPU
314  ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE (int i, int j, int)
315  {
316 #else
317  for (int j(jlo); j<=jhi; ++j) {
318  for (int i(ilo); i<=ihi; ++i) {
319 #endif
320  // Notes:
321  //
322  // - In DiffusionSrcForMom (e.g., for x-mom)
323  //
324  // Real diffContrib = ...
325  // + (tau13(i,j,k+1) - tau13(i,j,k)) / dzinv
326  // rho_u_rhs(i,j,k) -= diffContrib; // note the negative sign
327  //
328  // - We need to scale the explicit _part_ of `tau13` (for x-mom) by (1 - implicit_fac)
329  // The part that needs to be scaled is stored in `tau_corr`.
330  // E.g., tau13 = myhalf * (du/dz + dw/dx)
331  // tau13_corr = myhalf * du/dz
332  //
333  // - The momentum (`face_data`) was set to `S_old + S_rhs * dt`
334  // prior to including "ERF_Implicit.H". Recall that S_rhs includes
335  // sources from advection and other forcings, not just diffusion.
336  //
337  // - To correct momentum, we need to subtract `implicit_fac * diffContrib_corr`
338  // from S_rhs to recover `(1 - implicit_fac) * diffContrib_corr`,
339  // where `diffContrib_corr = -d(tau_corr)/dz`. The negative sign
340  // comes from our convention for the RHS diffusion source.
341  //
342  // Subtracting a negative gives the += below; multiply by dt to
343  // get the intermediate momentum on the RHS of the tridiagonal
344  // system.
345  //
346  // - With a surface_layer BC, tau13/23 holds the vertical flux -d_z(k*u_i)
347  // directly. We must use tau at klo (not tau_corr) with SL BCs.
348  //
349  // - Finally, the terms ~ RHS += (tau_corr_hi - tau_corr_lo) / dz (below)
350  // essentially undo the explicit diffusion update that will be
351  // handled here implicitly.
352 
353  // Bottom boundary coefficients and RHS for L decomp
354  //===================================================
355  Real rhoface, rhoAlpha_lo, rhoAlpha_hi;
356  Real dz_inv, dz_inv_lo, dz_inv_hi;
357  Real a_tmp, b_tmp, c_tmp, inv_b2_tmp;
358  {
359  rhoface = myhalf * (cell_data(i,j,klo,Rho_comp) + cell_data(i-ioff,j-joff,klo,Rho_comp));
360  getRhoAlphaForFaces(i, j, klo, ioff, joff, rhoAlpha_lo, rhoAlpha_hi,
361  cell_data, mu_turb, mu_eff,
362  l_consA, l_turb);
363 
364  dz_inv = one / dz_ptr[klo];
365  dz_inv_lo = dz_inv;
366  dz_inv_hi = two / (dz_ptr[klo] + dz_ptr[klo+1]);
367 
368  a_tmp = zero;
369  c_tmp = -Fact * gfac * rhoAlpha_hi * dz_inv_hi * dz_inv;
370 
371  RHS_a(i,j,klo) = face_data(i,j,klo); // NOTE: this is momenta; solution is velocity
372 
373  // BCs: Dirichlet (u_i = val), slip wall (w = 0), or surface layer (w = 0)
374  if (ext_dir_on_zlo) {
375  RHS_a(i,j,klo) += Fact * gfac * (tau_corr(i,j,klo+1) - tau_corr(i,j,klo)) * dz_inv;
376  if (stagdir==2) {
377  c_tmp = 0.;
378  RHS_a(i,j,klo) = 0.;
379  } else {
380  // NOTE: wall is 1/2 dz away (2 dz_inv)
381  a_tmp = -two * Fact * rhoAlpha_lo * dz_inv_lo * dz_inv;
382  RHS_a(i,j,klo) += two * rhoAlpha_lo * face_data(i,j,klo-1) * dz_inv_lo * dz_inv;
383  }
384  } else if (use_SurfLayer) {
385  // NOTE: tau = -mu*d_z(u_i) w/ SL
386  RHS_a(i,j,klo) += Fact * gfac * (tau_corr(i,j,klo+1) - tau(i,j,klo)) * dz_inv;
387  RHS_a(i,j,klo) += Fact * dz_inv * tau(i,j,klo);
388  } else {
389  // NOTE: FOEXTRAP has zero lower flux (nothing to add to RHS)
390  RHS_a(i,j,klo) += Fact * gfac * (tau_corr(i,j,klo+1) - tau_corr(i,j,klo)) * dz_inv;
391  }
392 
393  // Add YSU momentum countergradient correction at bottom boundary
394  if (use_ysu_mom_countergradient && stagdir < 2) {
395  const int hgam_comp = (stagdir == 0) ? EddyDiff::HGAMU_v : EddyDiff::HGAMV_v;
396  const Real gam_hi = myhalf * (mu_turb(i,j,klo,hgam_comp) + mu_turb(i,j,klo+1,hgam_comp));
397  RHS_a(i,j,klo) += Fact * gfac * dz_inv * rhoAlpha_hi * gam_hi * dz_inv_hi;
398  }
399 
400  b_tmp = rhoface - a_tmp - c_tmp;
401  inv_b2_tmp = one;
402 
403  RHS_a(i,j,klo) /= b_tmp; // NOTE: this is now "rho"
404  coeffG_a(i,j,klo) = c_tmp / b_tmp; // NOTE: this is now "gamma"
405  }
406 
407  // Build the coefficients and RHS for L decomp
408  //===================================================
409  for (int k(klo+1); k < khi; k++) {
410  rhoface = myhalf * (cell_data(i,j,k,Rho_comp) + cell_data(i-ioff,j-joff,k,Rho_comp));
411  getRhoAlphaForFaces(i, j, k, ioff, joff, rhoAlpha_lo, rhoAlpha_hi,
412  cell_data, mu_turb, mu_eff,
413  l_consA, l_turb);
414 
415  dz_inv = one / dz_ptr[k];
416  dz_inv_lo = two / (dz_ptr[k] + dz_ptr[k-1]);
417  dz_inv_hi = two / (dz_ptr[k] + dz_ptr[k+1]);
418 
419  a_tmp = -Fact * rhoAlpha_lo * dz_inv_lo * dz_inv;
420  c_tmp = -Fact * rhoAlpha_hi * dz_inv_hi * dz_inv;
421  b_tmp = rhoface - a_tmp - c_tmp;
422  inv_b2_tmp = one / (b_tmp - a_tmp * coeffG_a(i,j,k-1));
423 
424  RHS_a(i,j,k) = face_data(i,j,k); // NOTE: this is momenta; solution is velocity
425  RHS_a(i,j,k) += Fact * gfac * (tau_corr(i,j,k+1) - tau_corr(i,j,k)) * dz_inv;
426 
427  // Add YSU momentum countergradient correction
428  if (use_ysu_mom_countergradient && stagdir < 2) {
429  const int hgam_comp = (stagdir == 0) ? EddyDiff::HGAMU_v : EddyDiff::HGAMV_v;
430  const Real gam_k = mu_turb(i, j, k, hgam_comp);
431  const Real gam_km1 = mu_turb(i, j, k-1, hgam_comp);
432  const Real gam_kp1 = mu_turb(i, j, k+1, hgam_comp);
433  const Real gam_hi = myhalf * (gam_k + gam_kp1);
434  const Real gam_lo = myhalf * (gam_k + gam_km1);
435  RHS_a(i,j,k) += Fact * gfac * dz_inv * (rhoAlpha_hi * gam_hi * dz_inv_hi - rhoAlpha_lo * gam_lo * dz_inv_lo);
436  }
437 
438  RHS_a(i,j,k) = (RHS_a(i,j,k) - a_tmp * RHS_a(i,j,k-1)) * inv_b2_tmp; // NOTE: This is now "rho"
439  coeffG_a(i,j,k) = c_tmp * inv_b2_tmp; // NOTE: this is now "gamma"
440  } // k
441 
442  // Top boundary coefficients and RHS for L decomp
443  //===================================================
444  {
445  rhoface = myhalf * (cell_data(i,j,khi,Rho_comp) + cell_data(i-ioff,j-joff,khi,Rho_comp));
446  getRhoAlphaForFaces(i, j, khi, ioff, joff, rhoAlpha_lo, rhoAlpha_hi,
447  cell_data, mu_turb, mu_eff,
448  l_consA, l_turb);
449 
450  dz_inv = one / dz_ptr[khi];
451  dz_inv_lo = two / (dz_ptr[khi] + dz_ptr[khi-1]);
452  dz_inv_hi = dz_inv;
453 
454  a_tmp = -Fact * gfac * rhoAlpha_lo * dz_inv_lo * dz_inv;
455  c_tmp = zero;
456 
457  RHS_a(i,j,khi) = face_data(i,j,khi); // NOTE: this is momenta; solution is velocity
458  RHS_a(i,j,khi) += Fact * gfac * (tau_corr(i,j,khi+1) - tau_corr(i,j,khi)) * dz_inv;
459 
460  // BCs: Dirichlet (u_i = val), slip wall (w = 0)
461  if (ext_dir_on_zhi) {
462  if (stagdir==2) {
463  a_tmp = zero;
464  RHS_a(i,j,khi) = zero;
465  } else {
466  // NOTE: wall is 1/2 dz away (2 dz_inv)
467  c_tmp = -two * Fact * rhoAlpha_hi * dz_inv_hi * dz_inv;
468  RHS_a(i,j,khi) += two * rhoAlpha_hi * face_data(i,j,khi+1) * dz_inv_hi * dz_inv;
469  }
470  }
471 
472  b_tmp = rhoface - a_tmp - c_tmp;
473  inv_b2_tmp = one / (b_tmp - a_tmp * coeffG_a(i,j,khi-1));
474 
475  // First solve
476  soln_a(i,j,khi) = (RHS_a(i,j,khi) - a_tmp * RHS_a(i,j,khi-1)) * inv_b2_tmp;
477  }
478 
479  // Back sweep the U decomp solution
480  //===================================================
481  for (int k(khi-1); k>=klo; --k) {
482  soln_a(i,j,k) = RHS_a(i,j,k) - coeffG_a(i,j,k) * soln_a(i,j,k+1);
483  }
484 
485  // Convert back to momenta
486  //===================================================
487  for (int k(klo); k<=khi; ++k) {
488  rhoface = myhalf * (cell_data(i,j,k,Rho_comp) + cell_data(i-ioff,j-joff,k,Rho_comp));
489  face_data(i,j,k) = rhoface * soln_a(i,j,k);
490  }
491 
492 #ifdef AMREX_USE_GPU
493  });
494 #else
495  } // i
496  } // j
497 #endif
498 }
constexpr amrex::Real three
Definition: ERF_Constants.H:11
constexpr amrex::Real two
Definition: ERF_Constants.H:10
constexpr amrex::Real one
Definition: ERF_Constants.H:9
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
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
#define Rho_comp
Definition: ERF_IndexDefines.H:36
const int khi
Definition: ERF_InitCustomPert_Bubble.H:21
ParallelFor(grown_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);})
bool l_turb
Definition: ERF_SetupVertDiff.H:9
bool l_consA
Definition: ERF_SetupVertDiff.H:8
AMREX_ASSERT_WITH_MESSAGE(wbar_cutoff_min > wbar_cutoff_max, "ERROR: wbar_cutoff_min < wbar_cutoff_max")
@ xvel_bc
Definition: ERF_IndexDefines.H:102
@ foextrap
Definition: ERF_IndexDefines.H:247
@ ext_dir
Definition: ERF_IndexDefines.H:248
@ ext_dir_prim
Definition: ERF_IndexDefines.H:251
@ HGAMU_v
Definition: ERF_IndexDefines.H:218
@ HGAMV_v
Definition: ERF_IndexDefines.H:219
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:1248
amrex::Vector< TurbChoice > turbChoice
Definition: ERF_DataStruct.H:1251
Definition: ERF_TurbStruct.H:82
bool use_kturb
Definition: ERF_TurbStruct.H:577
Here is the call graph for this function:

◆ ImplicitDiffForStateLU_S()

void ImplicitDiffForStateLU_S ( const Box &  bx,
const Box &  domain,
const int  level,
const int  n,
const double  dt_d,
const GpuArray< Real, AMREX_SPACEDIM *2 > &  bc_neumann_vals,
const Array4< Real > &  cell_data,
const Gpu::DeviceVector< Real > &  stretched_dz_d,
const Array4< const Real > &  scalar_zflux,
const Array4< const Real > &  mu_turb,
const SolverChoice solverChoice,
const BCRec *  bc_ptr,
const bool  use_SurfLayer,
const Real  implicit_fac,
const bool  use_mrf_countergradient 
)

Function for computing the implicit contribution to the vertical diffusion of theta, with a vertically stretched grid over flat terrain.

Parameters
[in]bxcell-centered box to loop over
[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]stretched_dz_darray over z of dz[k]
[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
[in]use_mrf_countergradientwhether to include MRF countergradient correction
43 {
44  BL_PROFILE_VAR("ImplicitDiffForState_S()",ImplicitDiffForState_S);
45 
46  Real dt = static_cast<Real>(dt_d);
47 
48  // setup quantities for getRhoAlpha()
49 #include "ERF_SetupVertDiff.H"
50  const int qty_index = n;
51  const int prim_index = qty_index - 1;
52  const int prim_scal_index = (qty_index >= RhoScalar_comp && qty_index < RhoScalar_comp+NSCALARS) ? PrimScalar_comp : prim_index;
53 
54  // Box bounds
55  int ilo = bx.smallEnd(0);
56  int ihi = bx.bigEnd(0);
57  int jlo = bx.smallEnd(1);
58  int jhi = bx.bigEnd(1);
59  int klo = bx.smallEnd(2);
60  int khi = bx.bigEnd(2);
61  amrex::ignore_unused(ilo, ihi, jlo, jhi);
62 
63  // Temporary FABs for tridiagonal solve (allocated on column)
64  // A[k] * x[k-1] + B[k] * x[k] + C[k+1] = RHS[k]
65 
66  // With LU decomposition, M * x = r is written as L * U * x = r with U * x = rho
67  // We then first have L * rho = r and U * x = rho
68  amrex::FArrayBox RHS_fab, soln_fab, coeffG_fab;
69  RHS_fab.resize(bx,1, amrex::The_Async_Arena());
70  soln_fab.resize(bx,1, amrex::The_Async_Arena());
71  coeffG_fab.resize(bx,1, amrex::The_Async_Arena());
72  auto const& RHS_a = RHS_fab.array();
73  auto const& soln_a = soln_fab.array();
74  auto const& coeffG_a = coeffG_fab.array();
75 
76  auto dz_ptr = stretched_dz_d.data();
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 for scalars used with implicit vertical diffusion");
87  AMREX_ASSERT_WITH_MESSAGE(foextrap_on_zhi || neumann_on_zhi,
88  "Unexpected upper BC for scalars used with implicit vertical diffusion");
89 
90  Real Fact = implicit_fac * dt;
91 
92 #ifdef AMREX_USE_GPU
93  ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE (int i, int j, int)
94  {
95 #else
96  for (int j(jlo); j<=jhi; ++j) {
97  for (int i(ilo); i<=ihi; ++i) {
98 #endif
99  // Bottom boundary coefficients and RHS for L decomp
100  //===================================================
101  Real rhoAlpha_lo, rhoAlpha_hi;
102  Real dz_inv, dz_inv_lo, dz_inv_hi;
103  Real a_tmp, b_tmp, c_tmp, inv_b2_tmp;
104  {
105  getRhoAlpha(i, j, klo, rhoAlpha_lo, rhoAlpha_hi,
106  cell_data, mu_turb, d_alpha_eff, d_eddy_diff_idz,
107  prim_index, prim_scal_index, l_consA, l_turb);
108 
109  dz_inv = one / dz_ptr[klo];
110  dz_inv_lo = dz_inv;
111  dz_inv_hi = two / (dz_ptr[klo] + dz_ptr[klo+1]);
112 
113  a_tmp = zero;
114  c_tmp = -Fact * rhoAlpha_hi * dz_inv_hi * dz_inv;
115  b_tmp = cell_data(i,j,klo,Rho_comp) - a_tmp - c_tmp;
116  inv_b2_tmp = one;
117 
118  RHS_a(i,j,klo) = cell_data(i,j,klo,n); // NOTE: this is rho*phi; solution is phi
119  if (use_SurfLayer && scalar_zflux) {
120  RHS_a(i,j,klo) += Fact * dz_inv * scalar_zflux(i,j,klo); // NOTE: scalar_zflux = -K*d_z(\phi)
121  } else if (neumann_on_zlo) {
122  RHS_a(i,j,klo) += -Fact * dz_inv * rhoAlpha_lo * bc_neumann_vals[2]; // NOTE: N_val = d_z(\phi)
123  }
124 
125  // Add countergradient correction to RHS at bottom boundary
126  if (use_mrf_countergradient && (n == RhoTheta_comp || n == RhoQ1_comp)) {
127  const int gam_comp = (n == RhoTheta_comp) ? EddyDiff::HGAMT_v : EddyDiff::HGAMQ_v;
128  const Real gam_hi = myhalf * (mu_turb(i, j, klo, gam_comp) + mu_turb(i, j, klo+1, gam_comp));
129  RHS_a(i,j,klo) -= Fact * rhoAlpha_hi * gam_hi * dz_inv_hi;
130  }
131 
132  RHS_a(i,j,klo) /= b_tmp; // NOTE: this is now "rho"
133  coeffG_a(i,j,klo) = c_tmp / b_tmp; // NOTE: this is now "gamma"
134  }
135 
136  // Build the coefficients and RHS for L decomp
137  //===================================================
138  for (int k(klo+1); k < khi; k++) {
139  getRhoAlpha(i, j, k, rhoAlpha_lo, rhoAlpha_hi,
140  cell_data, mu_turb, d_alpha_eff, d_eddy_diff_idz,
141  prim_index, prim_scal_index, l_consA, l_turb);
142 
143  dz_inv = one / dz_ptr[k];
144  dz_inv_lo = two / (dz_ptr[k] + dz_ptr[k-1]);
145  dz_inv_hi = two / (dz_ptr[k] + dz_ptr[k+1]);
146 
147  a_tmp = -Fact * rhoAlpha_lo * dz_inv_lo * dz_inv;
148  c_tmp = -Fact * rhoAlpha_hi * dz_inv_hi * dz_inv;
149  b_tmp = cell_data(i,j,k,Rho_comp) - a_tmp - c_tmp;
150  inv_b2_tmp = one / (b_tmp - a_tmp * coeffG_a(i,j,k-1));
151 
152  RHS_a(i,j,k) = cell_data(i,j,k,n); // NOTE: this is rho*phi; solution is phi
153 
154  // Add countergradient correction to RHS in interior
155  if (use_mrf_countergradient && (n == RhoTheta_comp || n == RhoQ1_comp)) {
156  const int gam_comp = (n == RhoTheta_comp) ? EddyDiff::HGAMT_v : EddyDiff::HGAMQ_v;
157  const Real gam_k = mu_turb(i, j, k, gam_comp);
158  const Real gam_km1 = mu_turb(i, j, k-1, gam_comp);
159  const Real gam_kp1 = mu_turb(i, j, k+1, gam_comp);
160  const Real gam_hi = myhalf * (gam_k + gam_kp1); // at k+½
161  const Real gam_lo = myhalf * (gam_k + gam_km1); // at k-½
162  // Countergradient flux divergence (implicit contribution to RHS):
163  // -Fact * [ρα_{k+½}·γ_{k+½}·dz_inv_hi - ρα_{k-½}·γ_{k-½}·dz_inv_lo]
164  RHS_a(i,j,k) -= Fact * (rhoAlpha_hi * gam_hi * dz_inv_hi - rhoAlpha_lo * gam_lo * dz_inv_lo);
165  }
166 
167  RHS_a(i,j,k) = (RHS_a(i,j,k) - a_tmp * RHS_a(i,j,k-1)) * inv_b2_tmp; // NOTE: This is now "rho"
168  coeffG_a(i,j,k) = c_tmp * inv_b2_tmp; // NOTE: this is now "gamma"
169  } // k
170 
171  // Top boundary coefficients and RHS for L decomp
172  //===================================================
173  {
174  getRhoAlpha(i, j, khi, rhoAlpha_lo, rhoAlpha_hi,
175  cell_data, mu_turb, d_alpha_eff, d_eddy_diff_idz,
176  prim_index, prim_scal_index, l_consA, l_turb);
177 
178  dz_inv = one / dz_ptr[khi];
179  dz_inv_lo = two / (dz_ptr[khi] + dz_ptr[khi-1]);
180  dz_inv_hi = dz_inv;
181 
182  a_tmp = -Fact * rhoAlpha_lo * dz_inv_lo * dz_inv;
183  c_tmp = zero;
184  b_tmp = cell_data(i,j,khi,Rho_comp) - a_tmp - c_tmp;
185  inv_b2_tmp = one / (b_tmp - a_tmp * coeffG_a(i,j,khi-1));
186 
187  RHS_a(i,j,khi) = cell_data(i,j,khi,n); // NOTE: this is rho*phi; solution is phi
188  if (neumann_on_zhi) {
189  RHS_a(i,j,khi) -= -Fact * dz_inv * rhoAlpha_hi * bc_neumann_vals[5]; // NOTE: N_val = d_z(\phi)
190  }
191 
192  // First solve
193  soln_a(i,j,khi) = (RHS_a(i,j,khi) - a_tmp * RHS_a(i,j,khi-1)) * inv_b2_tmp;
194  }
195 
196  // Back sweep the U decomp solution
197  //===================================================
198  for (int k(khi-1); k>=klo; --k) {
199  soln_a(i,j,k) = RHS_a(i,j,k) - coeffG_a(i,j,k) * soln_a(i,j,k+1);
200  }
201 
202  // Convert back to rho*theta
203  //===================================================
204  for (int k(klo); k<=khi; ++k) {
205  cell_data(i,j,k,n) = cell_data(i,j,k,Rho_comp) * soln_a(i,j,k);
206  }
207 
208 #ifdef AMREX_USE_GPU
209  });
210 #else
211  } // i
212  } // j
213 #endif
214 }
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
#define RhoScalar_comp
Definition: ERF_IndexDefines.H:40
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
#define NSCALARS
Definition: ERF_IndexDefines.H:16
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:42
#define PrimScalar_comp
Definition: ERF_IndexDefines.H:57
int * d_eddy_diff_idz
Definition: ERF_SetupVertDiff.H:99
Real * d_alpha_eff
Definition: ERF_SetupVertDiff.H:98
@ neumann
Definition: ERF_IndexDefines.H:253
@ HGAMQ_v
Definition: ERF_IndexDefines.H:217
@ HGAMT_v
Definition: ERF_IndexDefines.H:216
Here is the call graph for this function: