ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_ImplicitDiff_T.cpp File Reference
#include "ERF_Diffusion.H"
#include "ERF_EddyViscosity.H"
#include "ERF_PBLModels.H"
#include "ERF_SetupVertDiff.H"
Include dependency graph for ERF_ImplicitDiff_T.cpp:

Functions

void ImplicitDiffForState_T (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 Array4< const Real > &z_nd, const Array4< const Real > &detJ, const GpuArray< Real, AMREX_SPACEDIM > &cellSizeInv, const Array4< 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 Documentation

◆ ImplicitDiffForState_T()

void ImplicitDiffForState_T ( 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 Array4< const Real > &  z_nd,
const Array4< const Real > &  detJ,
const GpuArray< Real, AMREX_SPACEDIM > &  cellSizeInv,
const Array4< 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 scalar RHS for diffusion operator without 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 center vars
[in]z_ndnodal array of z
[in]detJJacobian determinant
[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
40 {
41  BL_PROFILE_VAR("ImplicitDiffForState_T()",ImplicitDiffForState_T);
42 
43  // this uses domain, level, start_comp, num_comp
44 #include "ERF_SetupVertDiff.H"
45 
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  int bc_comp = qty_index;
77 
78  Real dz_inv = cellSizeInv[2];
79 
80 // bool ext_dir_on_zlo = (bc_ptr[bc_comp].lo(2) == ERFBCType::ext_dir ||
81 // bc_ptr[bc_comp].lo(2) == ERFBCType::ext_dir_prim)
82 // bool ext_dir_on_zhi = (bc_ptr[bc_comp].hi(2) == ERFBCType::ext_dir ||
83 // bc_ptr[bc_comp].hi(2) == ERFBCType::ext_dir_prim)
84  bool neumann_on_zlo = (bc_ptr[bc_comp].lo(2) == ERFBCType::neumann);
85  bool neumann_on_zhi = (bc_ptr[bc_comp].hi(2) == ERFBCType::neumann);
86 
87 #ifdef AMREX_USE_GPU
88  ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE (int i, int j, int)
89  {
90 #else
91  for (int j(jlo); j<=jhi; ++j) {
92  for (int i(ilo); i<=ihi; ++i) {
93 #endif
94  // Build the coefficients and RHS
95  for (int k(klo); k <= khi; k++)
96  {
97  Real rhoAlpha_lo;
98  Real rhoAlpha_hi;
99 
100  if (l_consA && l_turb) {
101  rhoAlpha_lo = 0.5 * ( cell_data(i,j,k,Rho_comp) + cell_data(i,j,k-1,Rho_comp) ) * d_alpha_eff[prim_scal_index]
102  + 0.5 * ( mu_turb(i,j,k , d_eddy_diff_idz[prim_scal_index])
103  + mu_turb(i,j,k-1, d_eddy_diff_idz[prim_scal_index]) );
104  rhoAlpha_hi = 0.5 * ( cell_data(i,j,k,Rho_comp) + cell_data(i,j,k+1,Rho_comp) ) * d_alpha_eff[prim_scal_index]
105  + 0.5 * ( mu_turb(i,j,k , d_eddy_diff_idz[prim_scal_index])
106  + mu_turb(i,j,k+1, d_eddy_diff_idz[prim_scal_index]) );
107  }
108  else if (l_turb) // with MolecDiffType::Constant or None
109  {
110  rhoAlpha_lo = d_alpha_eff[prim_index]
111  + 0.5 * ( mu_turb(i,j,k , d_eddy_diff_idz[prim_index])
112  + mu_turb(i,j,k-1, d_eddy_diff_idz[prim_index]) );
113  rhoAlpha_hi = d_alpha_eff[prim_index]
114  + 0.5 * ( mu_turb(i,j,k , d_eddy_diff_idz[prim_index])
115  + mu_turb(i,j,k+1, d_eddy_diff_idz[prim_index]) );
116  }
117  else if (l_consA) // without an LES/PBL model
118  {
119  rhoAlpha_lo = 0.5 * ( cell_data(i,j,k,Rho_comp) + cell_data(i,j,k-1,Rho_comp) ) * d_alpha_eff[prim_index];
120  rhoAlpha_hi = 0.5 * ( cell_data(i,j,k,Rho_comp) + cell_data(i,j,k+1,Rho_comp) ) * d_alpha_eff[prim_index];
121  }
122  else // with MolecDiffType::Constant or None - without an LES/PBL model
123  {
124  rhoAlpha_lo = d_alpha_eff[prim_index];
125  rhoAlpha_hi = d_alpha_eff[prim_index];
126  }
127 
128  Real met_h_zeta_lo = Compute_h_zeta_AtKface(i,j,k ,cellSizeInv,z_nd);
129  Real met_h_zeta_hi = Compute_h_zeta_AtKface(i,j,k+1,cellSizeInv,z_nd);
130 
131  RHS_a(i,j,k) = detJ(i,j,k) * cell_data(i,j,k,n); // Note this is rho*theta, whereas solution will be theta
132 
133  // Note that the additional factor of detJ is multiplied through so we don't see it here
134  // in the denominator but do see it multiplying the B coeff and the RHS
135  coeffA_a(i,j,k) = -implicit_fac * rhoAlpha_lo * dt * dz_inv * dz_inv / met_h_zeta_lo;
136  coeffC_a(i,j,k) = -implicit_fac * rhoAlpha_hi * dt * dz_inv * dz_inv / met_h_zeta_hi;
137 
138  if (k == dom_lo.z) {
139  if (use_SurfLayer) {
140  RHS_a(i,j,klo) += implicit_fac * dt * dz_inv * hfx_z(i,j,0);
141  } else if (neumann_on_zlo) {
142  RHS_a(i,j,klo) += coeffA_a(i,j,klo) * bc_neumann_vals[2] / dz_inv*met_h_zeta_lo;
143  }
144 
145  coeffA_a(i,j,klo) = 0.;
146  }
147  if (k == dom_hi.z) {
148  if (neumann_on_zhi) {
149  RHS_a(i,j,khi) -= coeffC_a(i,j,khi) * bc_neumann_vals[5] / dz_inv*met_h_zeta_hi;
150  }
151 
152  coeffC_a(i,j,khi) = 0.;
153  }
154 
155  coeffB_a(i,j,k) = detJ(i,j,k)*cell_data(i,j,k,Rho_comp) - coeffA_a(i,j,k) - coeffC_a(i,j,k);
156  } // k
157 
158  // Forward sweep
159 
160  Real bet = coeffB_a(i,j,klo);
161 
162  for (int k(klo+1); k<=khi; ++k) {
163  Real gam = coeffC_a(i,j,k-1) / bet;
164  bet = coeffB_a(i,j,k) - coeffA_a(i,j,k)*gam;
165  AMREX_ASSERT(bet != 0.0);
166  coeffB_a(i,j,k) = bet;
167  }
168 
169  for (int k(klo); k<=khi; ++k) {
170  inv_coeffB_a(i,j,k) = 1.0 / coeffB_a(i,j,k);
171  }
172 
173  //
174  // Tridiagonal solve
175  //
176  soln_a(i,j,klo) = RHS_a(i,j,klo) * inv_coeffB_a(i,j,klo);
177 
178  for (int k(klo+1); k<=khi; ++k) {
179  soln_a(i,j,k) = (RHS_a(i,j,k)-coeffA_a(i,j,k)*soln_a(i,j,k-1)) * inv_coeffB_a(i,j,k);
180  }
181 
182  for (int k(khi-1); k>=klo; --k) {
183  soln_a(i,j,k) -= ( coeffC_a(i,j,k) * inv_coeffB_a(i,j,k) ) * soln_a(i,j,k+1);
184  }
185 
186  //
187  // Transfer back to original array
188  //
189  for (int k(klo); k<=khi; ++k) {
190  cell_data(i,j,k,n) = soln_a(i,j,k) * cell_data(i,j,k,Rho_comp);
191  }
192 #ifdef AMREX_USE_GPU
193  });
194 #else
195  } // i
196  } // j
197 #endif
198 }
void ImplicitDiffForState_T(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 Array4< const Real > &z_nd, const Array4< const Real > &detJ, const GpuArray< Real, AMREX_SPACEDIM > &cellSizeInv, const Array4< 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_T.cpp:26
const int bc_comp
Definition: ERF_Implicit.H:8
#define RhoScalar_comp
Definition: ERF_IndexDefines.H:40
#define Rho_comp
Definition: ERF_IndexDefines.H:36
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
#define NSCALARS
Definition: ERF_IndexDefines.H:16
#define PrimScalar_comp
Definition: ERF_IndexDefines.H:52
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
int * d_eddy_diff_idz
Definition: ERF_SetupVertDiff.H:107
Real * d_alpha_eff
Definition: ERF_SetupVertDiff.H:104
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_zeta_AtKface(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:182
@ neumann
Definition: ERF_IndexDefines.H:213
Here is the call graph for this function: