ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_ComputeTurbulentViscosity.cpp File Reference
#include <ERF_ABLMost.H>
#include <ERF_EddyViscosity.H>
#include <ERF_Diffusion.H>
#include <ERF_PBLModels.H>
#include <ERF_TileNoZ.H>
#include <ERF_TerrainMetrics.H>
Include dependency graph for ERF_ComputeTurbulentViscosity.cpp:

Functions

void ComputeTurbulentViscosityLES (const MultiFab &Tau11, const MultiFab &Tau22, const MultiFab &Tau33, const MultiFab &Tau12, const MultiFab &Tau13, const MultiFab &Tau23, const MultiFab &cons_in, MultiFab &eddyViscosity, MultiFab &Hfx1, MultiFab &Hfx2, MultiFab &Hfx3, MultiFab &Diss, const Geometry &geom, const MultiFab &mapfac_u, const MultiFab &mapfac_v, const std::unique_ptr< MultiFab > &z_phys_nd, const TurbChoice &turbChoice, const Real const_grav, std::unique_ptr< ABLMost > &most, const bool &exp_most)
 
void ComputeTurbulentViscosityRANS (const MultiFab &, const MultiFab &, const MultiFab &, const MultiFab &, const MultiFab &, const MultiFab &, const MultiFab &cons_in, const MultiFab &wdist, MultiFab &eddyViscosity, MultiFab &Hfx1, MultiFab &Hfx2, MultiFab &Hfx3, MultiFab &Diss, const Geometry &geom, const MultiFab &, const MultiFab &, const std::unique_ptr< MultiFab > &z_phys_nd, const TurbChoice &turbChoice, const Real const_grav, std::unique_ptr< ABLMost > &most, const FArrayBox *z_0, const bool &exp_most)
 
void ComputeTurbulentViscosity (const MultiFab &xvel, const MultiFab &yvel, const MultiFab &Tau11, const MultiFab &Tau22, const MultiFab &Tau33, const MultiFab &Tau12, const MultiFab &Tau13, const MultiFab &Tau23, const MultiFab &cons_in, const MultiFab &wdist, MultiFab &eddyViscosity, MultiFab &Hfx1, MultiFab &Hfx2, MultiFab &Hfx3, MultiFab &Diss, const Geometry &geom, const MultiFab &mapfac_u, const MultiFab &mapfac_v, const std::unique_ptr< MultiFab > &z_phys_nd, const SolverChoice &solverChoice, std::unique_ptr< ABLMost > &most, const amrex::FArrayBox *z_0, const bool &exp_most, const bool &use_moisture, int level, const BCRec *bc_ptr, bool vert_only)
 

Function Documentation

◆ ComputeTurbulentViscosity()

void ComputeTurbulentViscosity ( const MultiFab &  xvel,
const MultiFab &  yvel,
const MultiFab &  Tau11,
const MultiFab &  Tau22,
const MultiFab &  Tau33,
const MultiFab &  Tau12,
const MultiFab &  Tau13,
const MultiFab &  Tau23,
const MultiFab &  cons_in,
const MultiFab &  wdist,
MultiFab &  eddyViscosity,
MultiFab &  Hfx1,
MultiFab &  Hfx2,
MultiFab &  Hfx3,
MultiFab &  Diss,
const Geometry &  geom,
const MultiFab &  mapfac_u,
const MultiFab &  mapfac_v,
const std::unique_ptr< MultiFab > &  z_phys_nd,
const SolverChoice solverChoice,
std::unique_ptr< ABLMost > &  most,
const amrex::FArrayBox *  z_0,
const bool &  exp_most,
const bool &  use_moisture,
int  level,
const BCRec *  bc_ptr,
bool  vert_only 
)

Wrapper to compute turbulent viscosity with LES or PBL.

Parameters
[in]xvelvelocity in x-dir
[in]yvelvelocity in y-dir
[in]Tau1111 strain
[in]Tau2222 strain
[in]Tau3333 strain
[in]Tau1212 strain
[in]Tau1313 strain
[in]Tau2323 strain
[in]cons_incell center conserved quantities
[out]eddyViscosityturbulent viscosity
[in]Hfx1heat flux in x-dir
[in]Hfx2heat flux in y-dir
[in]Hfx3heat flux in z-dir
[in]Dissdissipation of turbulent kinetic energy
[in]geomproblem geometry
[in]mapfac_umap factor at x-face
[in]mapfac_vmap factor at y-face
[in]turbChoicecontainer with turbulence parameters
[in]mostpointer to Monin-Obukhov class if instantiated
[in]vert_onlyflag for vertical components of eddyViscosity
802 {
803  BL_PROFILE_VAR("ComputeTurbulentViscosity()",ComputeTurbulentViscosity);
804  //
805  // In LES mode, the turbulent viscosity is isotropic, so the LES model sets both horizontal and vertical viscosities
806  // In PBL mode, the primary purpose of the PBL model is to control vertical transport, so the PBL model sets the vertical viscosity.
807  // Optionally, the PBL model can be run in conjunction with an LES model that sets the horizontal viscosity
808  // (this isn’t truly LES, but the model form is the same as Smagorinsky).
809  //
810  // ComputeTurbulentViscosityLES populates the LES viscosity for both horizontal and vertical components.
811  // ComputeTurbulentViscosityPBL computes the PBL viscosity just for the vertical component.
812  //
813 
814  TurbChoice turbChoice = solverChoice.turbChoice[level];
815  const Real const_grav = solverChoice.gravity;
816 
817  if (most) {
818  bool l_use_turb = ( turbChoice.les_type == LESType::Smagorinsky ||
819  turbChoice.les_type == LESType::Deardorff ||
820  turbChoice.rans_type == RANSType::kEqn ||
821  turbChoice.pbl_type == PBLType::MYNN25 ||
822  turbChoice.pbl_type == PBLType::YSU );
823  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(l_use_turb,
824  "A turbulence model must be utilized with MOST boundaries to compute the turbulent viscosity");
825  } else {
826  AMREX_ALWAYS_ASSERT(!vert_only);
827  }
828 
829  if (turbChoice.les_type != LESType::None) {
830  ComputeTurbulentViscosityLES(Tau11, Tau22, Tau33,
831  Tau12, Tau13, Tau23,
832  cons_in, eddyViscosity,
833  Hfx1, Hfx2, Hfx3, Diss,
834  geom, mapfac_u, mapfac_v,
835  z_phys_nd, turbChoice, const_grav,
836  most, exp_most);
837  }
838 
839  if (turbChoice.rans_type != RANSType::None) {
840  ComputeTurbulentViscosityRANS(Tau11, Tau22, Tau33,
841  Tau12, Tau13, Tau23,
842  cons_in, wdist,
843  eddyViscosity,
844  Hfx1, Hfx2, Hfx3, Diss,
845  geom, mapfac_u, mapfac_v,
846  z_phys_nd, turbChoice, const_grav,
847  most, z_0, exp_most);
848  }
849 
850  if (turbChoice.pbl_type == PBLType::MYNN25) {
851  ComputeDiffusivityMYNN25(xvel, yvel, cons_in, eddyViscosity,
852  geom, turbChoice, most, use_moisture,
853  level, bc_ptr, vert_only, z_phys_nd,
854  solverChoice.RhoQv_comp, solverChoice.RhoQc_comp,
855  solverChoice.RhoQr_comp);
856  } else if (turbChoice.pbl_type == PBLType::YSU) {
857  ComputeDiffusivityYSU(xvel, yvel, cons_in, eddyViscosity,
858  geom, turbChoice, most, use_moisture,
859  level, bc_ptr, vert_only, z_phys_nd);
860  }
861 }
void ComputeDiffusivityMYNN25(const MultiFab &xvel, const MultiFab &yvel, const MultiFab &cons_in, MultiFab &eddyViscosity, const Geometry &geom, const TurbChoice &turbChoice, std::unique_ptr< ABLMost > &most, bool use_moisture, int level, const BCRec *bc_ptr, bool, const std::unique_ptr< MultiFab > &z_phys_nd, const int RhoQv_comp, const int RhoQc_comp, const int RhoQr_comp)
Definition: ERF_ComputeDiffusivityMYNN25.cpp:11
void ComputeDiffusivityYSU(const MultiFab &xvel, const MultiFab &yvel, const MultiFab &cons_in, MultiFab &eddyViscosity, const Geometry &geom, const TurbChoice &turbChoice, std::unique_ptr< ABLMost > &most, bool, int level, const BCRec *bc_ptr, bool, const std::unique_ptr< MultiFab > &z_phys_nd)
Definition: ERF_ComputeDiffusivityYSU.cpp:11
void ComputeTurbulentViscosityLES(const MultiFab &Tau11, const MultiFab &Tau22, const MultiFab &Tau33, const MultiFab &Tau12, const MultiFab &Tau13, const MultiFab &Tau23, const MultiFab &cons_in, MultiFab &eddyViscosity, MultiFab &Hfx1, MultiFab &Hfx2, MultiFab &Hfx3, MultiFab &Diss, const Geometry &geom, const MultiFab &mapfac_u, const MultiFab &mapfac_v, const std::unique_ptr< MultiFab > &z_phys_nd, const TurbChoice &turbChoice, const Real const_grav, std::unique_ptr< ABLMost > &most, const bool &exp_most)
Definition: ERF_ComputeTurbulentViscosity.cpp:32
void ComputeTurbulentViscosity(const MultiFab &xvel, const MultiFab &yvel, const MultiFab &Tau11, const MultiFab &Tau22, const MultiFab &Tau33, const MultiFab &Tau12, const MultiFab &Tau13, const MultiFab &Tau23, const MultiFab &cons_in, const MultiFab &wdist, MultiFab &eddyViscosity, MultiFab &Hfx1, MultiFab &Hfx2, MultiFab &Hfx3, MultiFab &Diss, const Geometry &geom, const MultiFab &mapfac_u, const MultiFab &mapfac_v, const std::unique_ptr< MultiFab > &z_phys_nd, const SolverChoice &solverChoice, std::unique_ptr< ABLMost > &most, const amrex::FArrayBox *z_0, const bool &exp_most, const bool &use_moisture, int level, const BCRec *bc_ptr, bool vert_only)
Definition: ERF_ComputeTurbulentViscosity.cpp:784
void ComputeTurbulentViscosityRANS(const MultiFab &, const MultiFab &, const MultiFab &, const MultiFab &, const MultiFab &, const MultiFab &, const MultiFab &cons_in, const MultiFab &wdist, MultiFab &eddyViscosity, MultiFab &Hfx1, MultiFab &Hfx2, MultiFab &Hfx3, MultiFab &Diss, const Geometry &geom, const MultiFab &, const MultiFab &, const std::unique_ptr< MultiFab > &z_phys_nd, const TurbChoice &turbChoice, const Real const_grav, std::unique_ptr< ABLMost > &most, const FArrayBox *z_0, const bool &exp_most)
Definition: ERF_ComputeTurbulentViscosity.cpp:431
@ xvel
Definition: ERF_IndexDefines.H:130
@ yvel
Definition: ERF_IndexDefines.H:131
int RhoQr_comp
Definition: ERF_DataStruct.H:700
amrex::Real gravity
Definition: ERF_DataStruct.H:630
int RhoQc_comp
Definition: ERF_DataStruct.H:694
int RhoQv_comp
Definition: ERF_DataStruct.H:693
amrex::Vector< TurbChoice > turbChoice
Definition: ERF_DataStruct.H:594
Definition: ERF_TurbStruct.H:31
PBLType pbl_type
Definition: ERF_TurbStruct.H:241
RANSType rans_type
Definition: ERF_TurbStruct.H:238
LESType les_type
Definition: ERF_TurbStruct.H:205

Referenced by ERF::advance_dycore().

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

◆ ComputeTurbulentViscosityLES()

void ComputeTurbulentViscosityLES ( const MultiFab &  Tau11,
const MultiFab &  Tau22,
const MultiFab &  Tau33,
const MultiFab &  Tau12,
const MultiFab &  Tau13,
const MultiFab &  Tau23,
const MultiFab &  cons_in,
MultiFab &  eddyViscosity,
MultiFab &  Hfx1,
MultiFab &  Hfx2,
MultiFab &  Hfx3,
MultiFab &  Diss,
const Geometry &  geom,
const MultiFab &  mapfac_u,
const MultiFab &  mapfac_v,
const std::unique_ptr< MultiFab > &  z_phys_nd,
const TurbChoice turbChoice,
const Real  const_grav,
std::unique_ptr< ABLMost > &  most,
const bool &  exp_most 
)

Function for computing the turbulent viscosity with LES.

Parameters
[in]Tau1111 strain
[in]Tau2222 strain
[in]Tau3333 strain
[in]Tau1212 strain
[in]Tau1313 strain
[in]Tau2323 strain
[in]cons_incell center conserved quantities
[out]eddyViscosityturbulent viscosity
[in]Hfx1heat flux in x-dir
[in]Hfx2heat flux in y-dir
[in]Hfx3heat flux in z-dir
[in]Dissdissipation of turbulent kinetic energy
[in]geomproblem geometry
[in]mapfac_umap factor at x-face
[in]mapfac_vmap factor at y-face
[in]turbChoicecontainer with turbulence parameters
41 {
42  const GpuArray<Real, AMREX_SPACEDIM> cellSizeInv = geom.InvCellSizeArray();
43  const Box& domain = geom.Domain();
44  const int& klo = domain.smallEnd(2);
45  const bool use_most = (most != nullptr);
46  const bool use_terrain = (z_phys_nd != nullptr);
47 
48  Real inv_Pr_t = turbChoice.Pr_t_inv;
49  Real inv_Sc_t = turbChoice.Sc_t_inv;
50  Real inv_sigma_k = 1.0 / turbChoice.sigma_k;
51 
52  // SMAGORINSKY: Fill Kturb for momentum in horizontal and vertical
53  //***********************************************************************************
54  if (turbChoice.les_type == LESType::Smagorinsky)
55  {
56  Real Cs = turbChoice.Cs;
57 
58 #ifdef _OPENMP
59 #pragma omp parallel if (Gpu::notInLaunchRegion())
60 #endif
61  for (MFIter mfi(eddyViscosity,TilingIfNotGPU()); mfi.isValid(); ++mfi)
62  {
63  // NOTE: This gets us the lateral ghost cells for lev>0; which
64  // have been filled from FP Two Levels.
65  Box bxcc = mfi.growntilebox(1) & domain;
66 
67  const Array4<Real>& mu_turb = eddyViscosity.array(mfi);
68  const Array4<Real>& hfx_x = Hfx1.array(mfi);
69  const Array4<Real>& hfx_y = Hfx2.array(mfi);
70  const Array4<Real>& hfx_z = Hfx3.array(mfi);
71  const Array4<Real const > &cell_data = cons_in.array(mfi);
72 
73  Array4<Real const> tau11 = Tau11.array(mfi);
74  Array4<Real const> tau22 = Tau22.array(mfi);
75  Array4<Real const> tau33 = Tau33.array(mfi);
76  Array4<Real const> tau12 = Tau12.array(mfi);
77  Array4<Real const> tau13 = Tau13.array(mfi);
78  Array4<Real const> tau23 = Tau23.array(mfi);
79 
80  Array4<Real const> mf_u = mapfac_u.array(mfi);
81  Array4<Real const> mf_v = mapfac_v.array(mfi);
82 
83  Array4<Real const> z_nd_arr = (use_terrain) ? z_phys_nd->const_array(mfi) : Array4<Real const>{};
84 
85  ParallelFor(bxcc, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
86  {
87  Real SmnSmn = ComputeSmnSmn(i,j,k,tau11,tau22,tau33,tau12,tau13,tau23,klo,use_most,exp_most);
88  Real dxInv = cellSizeInv[0];
89  Real dyInv = cellSizeInv[1];
90  Real dzInv = cellSizeInv[2];
91  if (use_terrain) {
92  // the terrain grid is only deformed in z for now
93  dzInv /= Compute_h_zeta_AtCellCenter(i,j,k, cellSizeInv, z_nd_arr);
94  }
95  Real cellVolMsf = 1.0 / (dxInv * mf_u(i,j,0) * dyInv * mf_v(i,j,0) * dzInv);
96  Real DeltaMsf = std::pow(cellVolMsf,1.0/3.0);
97  Real CsDeltaSqrMsf = Cs*Cs*DeltaMsf*DeltaMsf;
98 
99  mu_turb(i, j, k, EddyDiff::Mom_h) = CsDeltaSqrMsf * cell_data(i, j, k, Rho_comp) * std::sqrt(2.0*SmnSmn);
100  mu_turb(i, j, k, EddyDiff::Mom_v) = mu_turb(i, j, k, EddyDiff::Mom_h);
101 
102  // Calculate SFS quantities
103  Real dtheta_dz;
104  if (use_most && k==klo) {
105  if (exp_most) {
106  dtheta_dz = ( cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp)
107  - cell_data(i,j,k ,RhoTheta_comp)/cell_data(i,j,k ,Rho_comp) )*dzInv;
108  } else {
109  dtheta_dz = 0.5 * (-3 * cell_data(i,j,k ,RhoTheta_comp)
110  / cell_data(i,j,k ,Rho_comp)
111  + 4 * cell_data(i,j,k+1,RhoTheta_comp)
112  / cell_data(i,j,k+1,Rho_comp)
113  - cell_data(i,j,k+2,RhoTheta_comp)
114  / cell_data(i,j,k+2,Rho_comp) ) * dzInv;
115  }
116  } else {
117  dtheta_dz = 0.5 * ( cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp)
118  - cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp) )*dzInv;
119  }
120  // - heat flux
121  // (Note: If using ERF_EXPLICIT_MOST_STRESS, the value at k=0 will
122  // be overwritten when BCs are applied)
123  hfx_x(i,j,k) = 0.0;
124  hfx_y(i,j,k) = 0.0;
125  hfx_z(i,j,k) = -inv_Pr_t*mu_turb(i,j,k,EddyDiff::Mom_v) * dtheta_dz; // (rho*w)' theta' [kg m^-2 s^-1 K]
126  });
127  }
128  }
129  // DEARDORFF: Fill Kturb for momentum in horizontal and vertical
130  //***********************************************************************************
131  else if (turbChoice.les_type == LESType::Deardorff)
132  {
133  const Real l_C_k = turbChoice.Ck;
134  const Real l_C_e = turbChoice.Ce;
135  const Real l_C_e_wall = turbChoice.Ce_wall;
136  const Real Ce_lcoeff = amrex::max(0.0, l_C_e - 1.9*l_C_k);
137  const Real l_abs_g = const_grav;
138  const Real l_inv_theta0 = 1.0 / turbChoice.theta_ref;
139 
140 #ifdef _OPENMP
141 #pragma omp parallel if (Gpu::notInLaunchRegion())
142 #endif
143  for ( MFIter mfi(eddyViscosity,TilingIfNotGPU()); mfi.isValid(); ++mfi)
144  {
145  Box bxcc = mfi.tilebox();
146 
147  const Array4<Real>& mu_turb = eddyViscosity.array(mfi);
148  const Array4<Real>& hfx_x = Hfx1.array(mfi);
149  const Array4<Real>& hfx_y = Hfx2.array(mfi);
150  const Array4<Real>& hfx_z = Hfx3.array(mfi);
151  const Array4<Real>& diss = Diss.array(mfi);
152 
153  const Array4<Real const > &cell_data = cons_in.array(mfi);
154 
155  Array4<Real const> mf_u = mapfac_u.array(mfi);
156  Array4<Real const> mf_v = mapfac_v.array(mfi);
157 
158  Array4<Real const> z_nd_arr = (use_terrain) ? z_phys_nd->const_array(mfi) : Array4<Real const>{};
159 
160  ParallelFor(bxcc, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
161  {
162  Real dxInv = cellSizeInv[0];
163  Real dyInv = cellSizeInv[1];
164  Real dzInv = cellSizeInv[2];
165  if (use_terrain) {
166  // the terrain grid is only deformed in z for now
167  dzInv /= Compute_h_zeta_AtCellCenter(i,j,k, cellSizeInv, z_nd_arr);
168  }
169  Real cellVolMsf = 1.0 / (dxInv * mf_u(i,j,0) * dyInv * mf_v(i,j,0) * dzInv);
170  Real DeltaMsf = std::pow(cellVolMsf,1.0/3.0);
171 
172  // Calculate stratification-dependent mixing length (Deardorff 1980)
173  Real eps = std::numeric_limits<Real>::epsilon();
174  Real dtheta_dz;
175  if (use_most && k==klo) {
176  if (exp_most) {
177  dtheta_dz = ( cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp)
178  - cell_data(i,j,k ,RhoTheta_comp)/cell_data(i,j,k ,Rho_comp) )*dzInv;
179  } else {
180  dtheta_dz = 0.5 * (-3 * cell_data(i,j,k ,RhoTheta_comp)
181  / cell_data(i,j,k ,Rho_comp)
182  + 4 * cell_data(i,j,k+1,RhoTheta_comp)
183  / cell_data(i,j,k+1,Rho_comp)
184  - cell_data(i,j,k+2,RhoTheta_comp)
185  / cell_data(i,j,k+2,Rho_comp) ) * dzInv;
186  }
187  } else {
188  dtheta_dz = 0.5 * ( cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp)
189  - cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp) )*dzInv;
190  }
191  Real E = amrex::max(cell_data(i,j,k,RhoKE_comp)/cell_data(i,j,k,Rho_comp),Real(0.0));
192  Real stratification = l_abs_g * dtheta_dz * l_inv_theta0;
193  Real length;
194  if (stratification <= eps) {
195  length = DeltaMsf;
196  } else {
197  length = 0.76 * std::sqrt(E / amrex::max(stratification,eps));
198  // mixing length should be _reduced_ for stable stratification
199  length = amrex::min(length, DeltaMsf);
200  // following WRF, make sure the mixing length isn't too small
201  length = amrex::max(length, 0.001 * DeltaMsf);
202  }
203 
204  // Calculate eddy diffusivities
205  // K = rho * C_k * l * KE^(1/2)
206  mu_turb(i,j,k,EddyDiff::Mom_h) = cell_data(i,j,k,Rho_comp) * l_C_k * length * std::sqrt(E);
207  mu_turb(i,j,k,EddyDiff::Mom_v) = mu_turb(i,j,k,EddyDiff::Mom_h);
208  // KH = (1 + 2*l/delta) * mu_turb
209  mu_turb(i,j,k,EddyDiff::Theta_v) = (1.+2.*length/DeltaMsf) * mu_turb(i,j,k,EddyDiff::Mom_v);
210  // Store lengthscale for TKE source terms
211  mu_turb(i,j,k,EddyDiff::Turb_lengthscale) = length;
212 
213  // Calculate SFS quantities
214  // - dissipation
215  Real Ce;
216  if ((l_C_e_wall > 0) && (k==0)) {
217  Ce = l_C_e_wall;
218  } else {
219  Ce = 1.9*l_C_k + Ce_lcoeff*length / DeltaMsf;
220  }
221  diss(i,j,k) = cell_data(i,j,k,Rho_comp) * Ce * std::pow(E,1.5) / length;
222 
223  // - heat flux
224  // (Note: If using ERF_EXPLICIT_MOST_STRESS, the value at k=0 will
225  // be overwritten when BCs are applied)
226  hfx_x(i,j,k) = 0.0;
227  hfx_y(i,j,k) = 0.0;
228  hfx_z(i,j,k) = -mu_turb(i,j,k,EddyDiff::Theta_v) * dtheta_dz; // (rho*w)' theta' [kg m^-2 s^-1 K]
229  });
230  }
231  }
232 
233  // Extrapolate Kturb in x/y, fill remaining elements (relevant to lev==0)
234  //***********************************************************************************
235  int ngc(1);
236  // EddyDiff mapping : Theta_h KE_h Scalar_h Q_h
237  Vector<Real> Factors = {inv_Pr_t, inv_sigma_k, inv_Sc_t, inv_Sc_t}; // alpha = mu/Pr
238  Gpu::AsyncVector<Real> d_Factors; d_Factors.resize(Factors.size());
239  Gpu::copy(Gpu::hostToDevice, Factors.begin(), Factors.end(), d_Factors.begin());
240  Real* fac_ptr = d_Factors.data();
241 
242  const bool use_KE = ( turbChoice.les_type == LESType::Deardorff );
243 
244 #ifdef _OPENMP
245 #pragma omp parallel if (Gpu::notInLaunchRegion())
246 #endif
247  for ( MFIter mfi(eddyViscosity,TilingIfNotGPU()); mfi.isValid(); ++mfi)
248  {
249  Box bxcc = mfi.tilebox();
250  Box planex = bxcc; planex.setSmall(0, 1); planex.setBig(0, ngc); planex.grow(1,1);
251  Box planey = bxcc; planey.setSmall(1, 1); planey.setBig(1, ngc); planey.grow(0,1);
252  int i_lo = bxcc.smallEnd(0); int i_hi = bxcc.bigEnd(0);
253  int j_lo = bxcc.smallEnd(1); int j_hi = bxcc.bigEnd(1);
254  bxcc.growLo(0,ngc); bxcc.growHi(0,ngc);
255  bxcc.growLo(1,ngc); bxcc.growHi(1,ngc);
256 
257  const Array4<Real>& mu_turb = eddyViscosity.array(mfi);
258 
259  // Extrapolate outside the domain in lateral directions (planex owns corner cells)
260  if (i_lo == domain.smallEnd(0)) {
261  ParallelFor(planex, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
262  {
263  int lj = amrex::min(amrex::max(j, domain.smallEnd(1)), domain.bigEnd(1));
264  mu_turb(i_lo-i, j, k, EddyDiff::Mom_h) = mu_turb(i_lo, lj, k, EddyDiff::Mom_h);
265  mu_turb(i_lo-i, j, k, EddyDiff::Mom_v) = mu_turb(i_lo, lj, k, EddyDiff::Mom_v);
266  });
267  }
268  if (i_hi == domain.bigEnd(0)) {
269  ParallelFor(planex, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
270  {
271  int lj = amrex::min(amrex::max(j, domain.smallEnd(1)), domain.bigEnd(1));
272  mu_turb(i_hi+i, j, k, EddyDiff::Mom_h) = mu_turb(i_hi, lj, k, EddyDiff::Mom_h);
273  mu_turb(i_hi+i, j, k, EddyDiff::Mom_v) = mu_turb(i_hi, lj, k, EddyDiff::Mom_v);
274  });
275  }
276  if (j_lo == domain.smallEnd(1)) {
277  ParallelFor(planey, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
278  {
279  int li = amrex::min(amrex::max(i, domain.smallEnd(0)), domain.bigEnd(0));
280  mu_turb(i, j_lo-j, k, EddyDiff::Mom_h) = mu_turb(li, j_lo, k, EddyDiff::Mom_h);
281  mu_turb(i, j_lo-j, k, EddyDiff::Mom_v) = mu_turb(li, j_lo, k, EddyDiff::Mom_v);
282  });
283  }
284  if (j_hi == domain.bigEnd(1)) {
285  ParallelFor(planey, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
286  {
287  int li = amrex::min(amrex::max(i, domain.smallEnd(0)), domain.bigEnd(0));
288  mu_turb(i, j_hi+j, k, EddyDiff::Mom_h) = mu_turb(li, j_hi, k, EddyDiff::Mom_h);
289  mu_turb(i, j_hi+j, k, EddyDiff::Mom_v) = mu_turb(li, j_hi, k, EddyDiff::Mom_v);
290  });
291  }
292 
293  // Copy Theta_v component into lateral ghost cells if using Deardorff (populated above)
294  if (use_KE) {
295  if (i_lo == domain.smallEnd(0)) {
296  ParallelFor(planex, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
297  {
298  int lj = amrex::min(amrex::max(j, domain.smallEnd(1)), domain.bigEnd(1));
299  mu_turb(i_lo-i, j, k, EddyDiff::Theta_v) = mu_turb(i_lo, lj, k, EddyDiff::Theta_v);
300  });
301  }
302  if (i_hi == domain.bigEnd(0)) {
303  ParallelFor(planex, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
304  {
305  int lj = amrex::min(amrex::max(j, domain.smallEnd(1)), domain.bigEnd(1));
306  mu_turb(i_hi+i, j, k, EddyDiff::Theta_v) = mu_turb(i_hi, lj, k, EddyDiff::Theta_v);
307  });
308  }
309  if (j_lo == domain.smallEnd(1)) {
310  ParallelFor(planey, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
311  {
312  int li = amrex::min(amrex::max(i, domain.smallEnd(0)), domain.bigEnd(0));
313  mu_turb(i, j_lo-j, k, EddyDiff::Theta_v) = mu_turb(li, j_lo, k, EddyDiff::Theta_v);
314  });
315  }
316  if (j_hi == domain.bigEnd(1)) {
317  ParallelFor(planey, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
318  {
319  int li = amrex::min(amrex::max(i, domain.smallEnd(0)), domain.bigEnd(0));
320  mu_turb(i, j_hi+j, k, EddyDiff::Theta_v) = mu_turb(li, j_hi, k, EddyDiff::Theta_v);
321  });
322  }
323  }
324 
325  for (auto n = 1; n < (EddyDiff::NumDiffs-1)/2; ++n) {
326  int offset = (EddyDiff::NumDiffs-1)/2;
327  switch (n)
328  {
329  case EddyDiff::KE_h:
330  if (use_KE) {
331  ParallelFor(bxcc, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
332  {
333  int indx = n;
334  int indx_v = indx + offset;
335  mu_turb(i,j,k,indx) = mu_turb(i,j,k,EddyDiff::Mom_h) * fac_ptr[indx-1];
336  mu_turb(i,j,k,indx_v) = mu_turb(i,j,k,indx);
337  });
338  }
339  break;
340  default:
341  ParallelFor(bxcc, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
342  {
343  int indx = n;
344  int indx_v = indx + offset;
345 
346  mu_turb(i,j,k,indx) = mu_turb(i,j,k,EddyDiff::Mom_h) * fac_ptr[indx-1];
347 
348  // NOTE: Theta_v has already been set for Deardorff
349  if (!(indx_v == EddyDiff::Theta_v && use_KE)) {
350  mu_turb(i,j,k,indx_v) = mu_turb(i,j,k,indx);
351  }
352  });
353  break;
354  }
355  }
356  }
357 
358  // Fill interior ghost cells and any ghost cells outside a periodic domain
359  //***********************************************************************************
360  eddyViscosity.FillBoundary(geom.periodicity());
361 
362 
363  // Extrapolate top & bottom
364  //***********************************************************************************
365 #ifdef _OPENMP
366 #pragma omp parallel if (Gpu::notInLaunchRegion())
367 #endif
368  for ( MFIter mfi(eddyViscosity,TileNoZ()); mfi.isValid(); ++mfi)
369  {
370  Box bxcc = mfi.tilebox();
371  Box planez = bxcc; planez.setSmall(2, 1); planez.setBig(2, ngc);
372  int k_lo = bxcc.smallEnd(2); int k_hi = bxcc.bigEnd(2);
373  planez.growLo(0,ngc); planez.growHi(0,ngc);
374  planez.growLo(1,ngc); planez.growHi(1,ngc);
375 
376  const Array4<Real>& mu_turb = eddyViscosity.array(mfi);
377 
378  for (auto n = 0; n < (EddyDiff::NumDiffs-1)/2; ++n) {
379  int offset = (EddyDiff::NumDiffs-1)/2;
380  switch (n)
381  {
382  case EddyDiff::KE_h:
383  if (use_KE) {
384  ParallelFor(planez, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
385  {
386  int indx = n;
387  int indx_v = indx + offset;
388  mu_turb(i, j, k_lo-k, indx ) = mu_turb(i, j, k_lo, indx );
389  mu_turb(i, j, k_hi+k, indx ) = mu_turb(i, j, k_hi, indx );
390  mu_turb(i, j, k_lo-k, indx_v) = mu_turb(i, j, k_lo, indx_v);
391  mu_turb(i, j, k_hi+k, indx_v) = mu_turb(i, j, k_hi, indx_v);
392  });
393  }
394  break;
395  default:
396  ParallelFor(planez, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
397  {
398  int indx = n;
399  int indx_v = indx + offset;
400  mu_turb(i, j, k_lo-k, indx ) = mu_turb(i, j, k_lo, indx );
401  mu_turb(i, j, k_hi+k, indx ) = mu_turb(i, j, k_hi, indx );
402  mu_turb(i, j, k_lo-k, indx_v) = mu_turb(i, j, k_lo, indx_v);
403  mu_turb(i, j, k_hi+k, indx_v) = mu_turb(i, j, k_hi, indx_v);
404  });
405  break;
406  }
407  }
408  }
409 }
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real ComputeSmnSmn(int &i, int &j, int &k, const amrex::Array4< amrex::Real const > &tau11, const amrex::Array4< amrex::Real const > &tau22, const amrex::Array4< amrex::Real const > &tau33, const amrex::Array4< amrex::Real const > &tau12, const amrex::Array4< amrex::Real const > &tau13, const amrex::Array4< amrex::Real const > &tau23, const int &klo, const bool &use_most, const bool &exp_most)
Definition: ERF_EddyViscosity.H:32
#define Rho_comp
Definition: ERF_IndexDefines.H:36
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
#define RhoKE_comp
Definition: ERF_IndexDefines.H:38
AMREX_FORCE_INLINE IntVect offset(const int face_dir, const int normal)
Definition: ERF_ReadBndryPlanes.cpp:28
AMREX_FORCE_INLINE AMREX_GPU_DEVICE amrex::Real Compute_h_zeta_AtCellCenter(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:39
AMREX_FORCE_INLINE amrex::IntVect TileNoZ()
Definition: ERF_TileNoZ.H:11
@ Theta_v
Definition: ERF_IndexDefines.H:157
@ Turb_lengthscale
Definition: ERF_IndexDefines.H:161
@ Mom_h
Definition: ERF_IndexDefines.H:151
@ Mom_v
Definition: ERF_IndexDefines.H:156
@ NumDiffs
Definition: ERF_IndexDefines.H:162
@ KE_h
Definition: ERF_IndexDefines.H:153
amrex::Real sigma_k
Definition: ERF_TurbStruct.H:232
amrex::Real Sc_t_inv
Definition: ERF_TurbStruct.H:213
amrex::Real Ck
Definition: ERF_TurbStruct.H:221
amrex::Real Cs
Definition: ERF_TurbStruct.H:216
amrex::Real Pr_t_inv
Definition: ERF_TurbStruct.H:209
amrex::Real Ce_wall
Definition: ERF_TurbStruct.H:220
amrex::Real Ce
Definition: ERF_TurbStruct.H:219
amrex::Real theta_ref
Definition: ERF_TurbStruct.H:235

Referenced by ComputeTurbulentViscosity().

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

◆ ComputeTurbulentViscosityRANS()

void ComputeTurbulentViscosityRANS ( const MultiFab &  ,
const MultiFab &  ,
const MultiFab &  ,
const MultiFab &  ,
const MultiFab &  ,
const MultiFab &  ,
const MultiFab &  cons_in,
const MultiFab &  wdist,
MultiFab &  eddyViscosity,
MultiFab &  Hfx1,
MultiFab &  Hfx2,
MultiFab &  Hfx3,
MultiFab &  Diss,
const Geometry &  geom,
const MultiFab &  ,
const MultiFab &  ,
const std::unique_ptr< MultiFab > &  z_phys_nd,
const TurbChoice turbChoice,
const Real  const_grav,
std::unique_ptr< ABLMost > &  most,
const FArrayBox *  z_0,
const bool &  exp_most 
)

Function for computing the eddy viscosity with RANS.

Parameters
[in]Tau1111 strain
[in]Tau2222 strain
[in]Tau3333 strain
[in]Tau1212 strain
[in]Tau1313 strain
[in]Tau2323 strain
[in]cons_incell center conserved quantities
[out]eddyViscosityturbulent viscosity
[in]Hfx1heat flux in x-dir
[in]Hfx2heat flux in y-dir
[in]Hfx3heat flux in z-dir
[in]Dissdissipation of turbulent kinetic energy
[in]geomproblem geometry
[in]mapfac_umap factor at x-face
[in]mapfac_vmap factor at y-face
[in]turbChoicecontainer with turbulence parameters
441 {
442  const GpuArray<Real, AMREX_SPACEDIM> cellSizeInv = geom.InvCellSizeArray();
443  const Box& domain = geom.Domain();
444  const int& klo = domain.smallEnd(2);
445  const bool use_most = (most != nullptr);
446  const bool use_terrain = (z_phys_nd != nullptr);
447 
448  Real inv_Pr_t = turbChoice.Pr_t_inv;
449  Real inv_Sc_t = turbChoice.Sc_t_inv;
450  Real inv_sigma_k = 1.0 / turbChoice.sigma_k;
451 
452  // One-Equation k model (Axell & Liungman 2001, Environ Fluid Mech)
453  //***********************************************************************************
454  if (turbChoice.rans_type == RANSType::kEqn)
455  {
456  const Real Cmu0 = turbChoice.Cmu0;
457  const Real Cmu0_pow3 = Cmu0 * Cmu0 * Cmu0;
458  const Real inv_Cb_sq = 1.0 / (turbChoice.Cb * turbChoice.Cb);
459  const Real Rt_crit = turbChoice.Rt_crit;
460  const Real Rt_min = turbChoice.Rt_min;
461  const Real l_g_max = turbChoice.l_g_max;
462 
463  const Real abs_g = const_grav;
464  const Real inv_theta0 = 1.0 / turbChoice.theta_ref;
465 
466 #ifdef _OPENMP
467 #pragma omp parallel if (Gpu::notInLaunchRegion())
468 #endif
469  for ( MFIter mfi(eddyViscosity,TilingIfNotGPU()); mfi.isValid(); ++mfi)
470  {
471  Box bxcc = mfi.tilebox();
472 
473  const Array4<Real const>& d_arr = wdist.const_array(mfi);
474  const Array4<Real const>& z0_arr = (use_most) ? z_0->const_array() : Array4<Real const>{};
475 
476  const Array4<Real>& mu_turb = eddyViscosity.array(mfi);
477  const Array4<Real>& hfx_x = Hfx1.array(mfi);
478  const Array4<Real>& hfx_y = Hfx2.array(mfi);
479  const Array4<Real>& hfx_z = Hfx3.array(mfi);
480  const Array4<Real>& diss = Diss.array(mfi);
481 
482  const Array4<Real const>& cell_data = cons_in.array(mfi);
483 
484  const Array4<Real const>& z_nd_arr = (use_terrain) ? z_phys_nd->const_array(mfi) : Array4<Real const>{};
485 
486  ParallelFor(bxcc, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
487  {
488  Real eps = std::numeric_limits<Real>::epsilon();
489  Real tke = amrex::max(cell_data(i,j,k,RhoKE_comp)/cell_data(i,j,k,Rho_comp), eps);
490 
491  // Estimate stratification
492  Real dtheta_dz;
493  Real dzInv = cellSizeInv[2];
494  if (use_terrain) {
495  // the terrain grid is only deformed in z for now
496  dzInv /= Compute_h_zeta_AtCellCenter(i,j,k, cellSizeInv, z_nd_arr);
497  }
498  if (use_most && k==klo) {
499  if (exp_most) {
500  dtheta_dz = ( cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp)
501  - cell_data(i,j,k ,RhoTheta_comp)/cell_data(i,j,k ,Rho_comp) )*dzInv;
502  } else {
503  dtheta_dz = 0.5 * (-3 * cell_data(i,j,k ,RhoTheta_comp)
504  / cell_data(i,j,k ,Rho_comp)
505  + 4 * cell_data(i,j,k+1,RhoTheta_comp)
506  / cell_data(i,j,k+1,Rho_comp)
507  - cell_data(i,j,k+2,RhoTheta_comp)
508  / cell_data(i,j,k+2,Rho_comp) ) * dzInv;
509  }
510  } else {
511  dtheta_dz = 0.5 * ( cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp)
512  - cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp) )*dzInv;
513  }
514  Real N2 = abs_g * inv_theta0 * dtheta_dz; // Brunt–Väisälä frequency squared
515 
516  // Geometric length scale (AL01, Eqn. 22)
517  Real l_g = (z0_arr) ? KAPPA * (d_arr(i, j, k) + z0_arr(i, j, 0))
518  : KAPPA * d_arr(i, j, k);
519 
520  // Enforce a maximum value
521  l_g = l_g_max * l_g / (l_g_max + l_g);
522 
523  // Turbulent Richardson number (AL01, Eqn. 29)
524  // using the old dissipation value
525  Real diss0 = max(diss(i, j, k) / cell_data(i, j, k, Rho_comp),
526  eps);
527  Real Rt = tke*tke * N2 / diss0;
528 
529  // Turbulent length scale
530  Real length;
531  if (std::abs(N2) <= eps) {
532  length = l_g;
533  } else if (N2 > eps) {
534  // Stable (AL01, Eqn. 26)
535  length = std::sqrt(1.0 /
536  (1.0 / (l_g * l_g) + inv_Cb_sq * N2 / tke));
537  } else {
538  // Unstable (AL01, Eqn. 28)
539  length = l_g * std::sqrt(1.0 - Cmu0_pow3*Cmu0_pow3 * inv_Cb_sq * Rt);
540  }
541  mu_turb(i, j, k, EddyDiff::Turb_lengthscale) = length;
542 
543  // Burchard & Petersen smoothing function
544  Rt = (Rt >= Rt_crit) ? Rt
545  : std::max(Rt,
546  Rt - std::pow(Rt - Rt_crit, 2) /
547  (Rt + Rt_min - 2*Rt_crit));
548 
549  // Stability functions
550  // Note: These use the smoothed turbulent Richardson number
551  Real cmu = (Cmu0 + 0.108*Rt)
552  / (1.0 + 0.308*Rt + 0.00837*Rt*Rt); // (AL01, Eqn. 31)
553  Real cmu_prime = Cmu0 / (1 + 0.277*Rt); // (AL01, Eqn. 32)
554 
555  // Calculate eddy diffusivities
556  // K = rho * nu_t = rho * c_mu * tke^(1/2) * length
557  Real nut = cmu * std::sqrt(tke) * length; // eddy viscosity
558  Real nut_prime = cmu_prime / cmu * nut; // eddy diffusivity
559  mu_turb(i, j, k, EddyDiff::Mom_h) = cell_data(i, j, k, Rho_comp) * nut;
560  mu_turb(i, j, k, EddyDiff::Mom_v) = mu_turb(i, j, k, EddyDiff::Mom_h);
561  mu_turb(i, j, k, EddyDiff::Theta_v) = cell_data(i, j, k, Rho_comp) * nut_prime;
562 
563  // Calculate SFS quantities
564  // - dissipation (AL01 Eqn. 19)
565  diss(i, j, k) = cell_data(i, j, k, Rho_comp) * Cmu0_pow3 * std::pow(tke,1.5) / length;
566 
567  // - heat flux
568  // (Note: If using ERF_EXPLICIT_MOST_STRESS, the value at k=0 will
569  // be overwritten when BCs are applied)
570  hfx_x(i, j, k) = 0.0;
571  hfx_y(i, j, k) = 0.0;
572  // Note: buoyant production = g/theta0 * hfx == -nut_prime * N^2 (c.f. AL01 Eqn. 15)
573  // = nut_prime * g/theta0 * dtheta/dz
574  // ==> hfx = nut_prime * dtheta/dz
575  // Our convention is such that dtheta/dz < 0 gives a positive
576  // (upward) heat flux.
577  hfx_z(i, j, k) = -mu_turb(i, j, k, EddyDiff::Theta_v) * dtheta_dz; // (rho*w)' theta' [kg m^-2 s^-1 K]
578  });
579  }
580  }
581 
582  // Extrapolate Kturb in x/y, fill remaining elements (relevant to lev==0)
583  //***********************************************************************************
584  int ngc(1);
585  // EddyDiff mapping : Theta_h KE_h Scalar_h Q_h
586  Vector<Real> Factors = {inv_Pr_t, inv_sigma_k, inv_Sc_t, inv_Sc_t}; // alpha = mu/Pr
587  Gpu::AsyncVector<Real> d_Factors; d_Factors.resize(Factors.size());
588  Gpu::copy(Gpu::hostToDevice, Factors.begin(), Factors.end(), d_Factors.begin());
589  Real* fac_ptr = d_Factors.data();
590 
591  const bool use_KE = ( turbChoice.rans_type == RANSType::kEqn );
592 
593 #ifdef _OPENMP
594 #pragma omp parallel if (Gpu::notInLaunchRegion())
595 #endif
596  for ( MFIter mfi(eddyViscosity,TilingIfNotGPU()); mfi.isValid(); ++mfi)
597  {
598  Box bxcc = mfi.tilebox();
599  Box planex = bxcc; planex.setSmall(0, 1); planex.setBig(0, ngc); planex.grow(1,1);
600  Box planey = bxcc; planey.setSmall(1, 1); planey.setBig(1, ngc); planey.grow(0,1);
601  int i_lo = bxcc.smallEnd(0); int i_hi = bxcc.bigEnd(0);
602  int j_lo = bxcc.smallEnd(1); int j_hi = bxcc.bigEnd(1);
603  bxcc.growLo(0,ngc); bxcc.growHi(0,ngc);
604  bxcc.growLo(1,ngc); bxcc.growHi(1,ngc);
605 
606  const Array4<Real>& mu_turb = eddyViscosity.array(mfi);
607 
608  // Extrapolate outside the domain in lateral directions (planex owns corner cells)
609  if (i_lo == domain.smallEnd(0)) {
610  ParallelFor(planex, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
611  {
612  int lj = amrex::min(amrex::max(j, domain.smallEnd(1)), domain.bigEnd(1));
613  mu_turb(i_lo-i, j, k, EddyDiff::Mom_h) = mu_turb(i_lo, lj, k, EddyDiff::Mom_h);
614  mu_turb(i_lo-i, j, k, EddyDiff::Mom_v) = mu_turb(i_lo, lj, k, EddyDiff::Mom_v);
615  });
616  }
617  if (i_hi == domain.bigEnd(0)) {
618  ParallelFor(planex, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
619  {
620  int lj = amrex::min(amrex::max(j, domain.smallEnd(1)), domain.bigEnd(1));
621  mu_turb(i_hi+i, j, k, EddyDiff::Mom_h) = mu_turb(i_hi, lj, k, EddyDiff::Mom_h);
622  mu_turb(i_hi+i, j, k, EddyDiff::Mom_v) = mu_turb(i_hi, lj, k, EddyDiff::Mom_v);
623  });
624  }
625  if (j_lo == domain.smallEnd(1)) {
626  ParallelFor(planey, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
627  {
628  int li = amrex::min(amrex::max(i, domain.smallEnd(0)), domain.bigEnd(0));
629  mu_turb(i, j_lo-j, k, EddyDiff::Mom_h) = mu_turb(li, j_lo, k, EddyDiff::Mom_h);
630  mu_turb(i, j_lo-j, k, EddyDiff::Mom_v) = mu_turb(li, j_lo, k, EddyDiff::Mom_v);
631  });
632  }
633  if (j_hi == domain.bigEnd(1)) {
634  ParallelFor(planey, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
635  {
636  int li = amrex::min(amrex::max(i, domain.smallEnd(0)), domain.bigEnd(0));
637  mu_turb(i, j_hi+j, k, EddyDiff::Mom_h) = mu_turb(li, j_hi, k, EddyDiff::Mom_h);
638  mu_turb(i, j_hi+j, k, EddyDiff::Mom_v) = mu_turb(li, j_hi, k, EddyDiff::Mom_v);
639  });
640  }
641 
642  // Copy Theta_v component into lateral ghost cells if using Deardorff (populated above)
643  if (use_KE) {
644  if (i_lo == domain.smallEnd(0)) {
645  ParallelFor(planex, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
646  {
647  int lj = amrex::min(amrex::max(j, domain.smallEnd(1)), domain.bigEnd(1));
648  mu_turb(i_lo-i, j, k, EddyDiff::Theta_v) = mu_turb(i_lo, lj, k, EddyDiff::Theta_v);
649  });
650  }
651  if (i_hi == domain.bigEnd(0)) {
652  ParallelFor(planex, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
653  {
654  int lj = amrex::min(amrex::max(j, domain.smallEnd(1)), domain.bigEnd(1));
655  mu_turb(i_hi+i, j, k, EddyDiff::Theta_v) = mu_turb(i_hi, lj, k, EddyDiff::Theta_v);
656  });
657  }
658  if (j_lo == domain.smallEnd(1)) {
659  ParallelFor(planey, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
660  {
661  int li = amrex::min(amrex::max(i, domain.smallEnd(0)), domain.bigEnd(0));
662  mu_turb(i, j_lo-j, k, EddyDiff::Theta_v) = mu_turb(li, j_lo, k, EddyDiff::Theta_v);
663  });
664  }
665  if (j_hi == domain.bigEnd(1)) {
666  ParallelFor(planey, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
667  {
668  int li = amrex::min(amrex::max(i, domain.smallEnd(0)), domain.bigEnd(0));
669  mu_turb(i, j_hi+j, k, EddyDiff::Theta_v) = mu_turb(li, j_hi, k, EddyDiff::Theta_v);
670  });
671  }
672  }
673 
674  for (auto n = 1; n < (EddyDiff::NumDiffs-1)/2; ++n) {
675  int offset = (EddyDiff::NumDiffs-1)/2;
676  switch (n)
677  {
678  case EddyDiff::KE_h:
679  if (use_KE) {
680  ParallelFor(bxcc, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
681  {
682  int indx = n;
683  int indx_v = indx + offset;
684  mu_turb(i,j,k,indx) = mu_turb(i,j,k,EddyDiff::Mom_h) * fac_ptr[indx-1];
685  mu_turb(i,j,k,indx_v) = mu_turb(i,j,k,indx);
686  });
687  }
688  break;
689  default:
690  ParallelFor(bxcc, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
691  {
692  int indx = n;
693  int indx_v = indx + offset;
694 
695  mu_turb(i,j,k,indx) = mu_turb(i,j,k,EddyDiff::Mom_h) * fac_ptr[indx-1];
696 
697  // NOTE: Theta_v has already been set for Deardorff
698  if (!(indx_v == EddyDiff::Theta_v && use_KE)) {
699  mu_turb(i,j,k,indx_v) = mu_turb(i,j,k,indx);
700  }
701  });
702  break;
703  }
704  }
705  }
706 
707  // Fill interior ghost cells and any ghost cells outside a periodic domain
708  //***********************************************************************************
709  eddyViscosity.FillBoundary(geom.periodicity());
710 
711 
712  // Extrapolate top & bottom
713  //***********************************************************************************
714 #ifdef _OPENMP
715 #pragma omp parallel if (Gpu::notInLaunchRegion())
716 #endif
717  for ( MFIter mfi(eddyViscosity,TileNoZ()); mfi.isValid(); ++mfi)
718  {
719  Box bxcc = mfi.tilebox();
720  Box planez = bxcc; planez.setSmall(2, 1); planez.setBig(2, ngc);
721  int k_lo = bxcc.smallEnd(2); int k_hi = bxcc.bigEnd(2);
722  planez.growLo(0,ngc); planez.growHi(0,ngc);
723  planez.growLo(1,ngc); planez.growHi(1,ngc);
724 
725  const Array4<Real>& mu_turb = eddyViscosity.array(mfi);
726 
727  for (auto n = 0; n < (EddyDiff::NumDiffs-1)/2; ++n) {
728  int offset = (EddyDiff::NumDiffs-1)/2;
729  switch (n)
730  {
731  case EddyDiff::KE_h:
732  if (use_KE) {
733  ParallelFor(planez, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
734  {
735  int indx = n;
736  int indx_v = indx + offset;
737  mu_turb(i, j, k_lo-k, indx ) = mu_turb(i, j, k_lo, indx );
738  mu_turb(i, j, k_hi+k, indx ) = mu_turb(i, j, k_hi, indx );
739  mu_turb(i, j, k_lo-k, indx_v) = mu_turb(i, j, k_lo, indx_v);
740  mu_turb(i, j, k_hi+k, indx_v) = mu_turb(i, j, k_hi, indx_v);
741  });
742  }
743  break;
744  default:
745  ParallelFor(planez, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
746  {
747  int indx = n;
748  int indx_v = indx + offset;
749  mu_turb(i, j, k_lo-k, indx ) = mu_turb(i, j, k_lo, indx );
750  mu_turb(i, j, k_hi+k, indx ) = mu_turb(i, j, k_hi, indx );
751  mu_turb(i, j, k_lo-k, indx_v) = mu_turb(i, j, k_lo, indx_v);
752  mu_turb(i, j, k_hi+k, indx_v) = mu_turb(i, j, k_hi, indx_v);
753  });
754  break;
755  }
756  }
757  }
758 }
constexpr amrex::Real KAPPA
Definition: ERF_Constants.H:20
amrex::Real Rt_min
Definition: ERF_TurbStruct.H:227
amrex::Real Cmu0
Definition: ERF_TurbStruct.H:224
amrex::Real Cb
Definition: ERF_TurbStruct.H:225
amrex::Real Rt_crit
Definition: ERF_TurbStruct.H:226
amrex::Real l_g_max
Definition: ERF_TurbStruct.H:228

Referenced by ComputeTurbulentViscosity().

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