ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_InitCustomPert_TurbulentInflow.H
Go to the documentation of this file.
1 
2  // On a mesh other than ConstantDz, heights come from z_cc and the vertical levels,
3  // not from geomdata's prob_lo[2], prob_hi[2] and CellSize(2)
4  const Real phys_z_lo = phys_zlo(geomdata, lev);
5  const Real phys_z_hi = phys_zhi(geomdata, lev);
6 
7  ParmParse pp("prob");
8 
9  Real rho_0 = one; pp.query("rho_0", rho_0);
10  Real T_0 = amrex::Real(300.0); pp.query("T_0", T_0);
11 
12  Real A_0 = one; pp.query("A_0", A_0);
13  Real KE_0 = amrex::Real(0.1); pp.query("KE_0", KE_0);
14 
15  Real KE_decay_height = -1; pp.query("KE_decay_height", KE_decay_height);
16  Real KE_decay_order = 1; pp.query("KE_decay_order", KE_decay_order);
17 
18  Real U_0 = zero; pp.query("U_0", U_0);
19  Real V_0 = zero; pp.query("V_0", V_0);
20  Real W_0 = zero; pp.query("W_0", W_0);
21 
22  // random initial perturbations (legacy code)
23  Real U_0_Pert_Mag = zero; pp.query("U_0_Pert_Mag", U_0_Pert_Mag);
24  Real V_0_Pert_Mag = zero; pp.query("V_0_Pert_Mag", V_0_Pert_Mag);
25  Real W_0_Pert_Mag = zero; pp.query("W_0_Pert_Mag", W_0_Pert_Mag);
26  Real T_0_Pert_Mag = zero; pp.query("T_0_Pert_Mag", T_0_Pert_Mag);
27  bool pert_rhotheta = true; pp.query("pert_rhotheta", pert_rhotheta);
28 
29  // divergence-free initial perturbations
30  Real pert_deltaU = zero; pp.query("pert_deltaU", pert_deltaU);
31  Real pert_deltaV = zero; pp.query("pert_deltaV", pert_deltaV);
32  Real pert_periods_U = amrex::Real(5.0); pp.query("pert_periods_U", pert_periods_U);
33  Real pert_periods_V = amrex::Real(5.0); pp.query("pert_periods_V", pert_periods_V);
34  Real pert_ref_height = amrex::Real(100.0); pp.query("pert_ref_height", pert_ref_height);
35 
36  // Captured by value in the kernel below, so copy them out of geomdata rather than
37  // keeping pointers into host storage
38  const GpuArray<Real,AMREX_SPACEDIM> prob_lo{AMREX_D_DECL(geomdata.ProbLo(0), geomdata.ProbLo(1), geomdata.ProbLo(2))};
39  const GpuArray<Real,AMREX_SPACEDIM> prob_hi{AMREX_D_DECL(geomdata.ProbHi(0), geomdata.ProbHi(1), geomdata.ProbHi(2))};
40 
41  if (KE_decay_height > 0 &&
42  state_pert.nComp() > RhoKE_comp) {
43  amrex::Print() << "Initial KE profile (order " << KE_decay_order
44  << ") will extend up to " << KE_decay_height
45  << std::endl;
46  }
47 
48  if (pert_ref_height > 0) {
49  if ((pert_deltaU != zero) || (pert_deltaV != zero)) {
50  amrex::Print() << "Adding divergence-free perturbations "
51  << pert_deltaU << " " << pert_deltaV
52  << std::endl;
53  }
54  if (U_0_Pert_Mag != zero) {
55  amrex::Print() << "Adding random x-velocity perturbations" << std::endl;
56  }
57  if (V_0_Pert_Mag != zero) {
58  amrex::Print() << "Adding random y-velocity perturbations" << std::endl;
59  }
60  if (T_0_Pert_Mag != zero) {
61  if (pert_rhotheta) {
62  amrex::Print() << "Adding random rho*theta perturbations" << std::endl;
63  } else {
64  amrex::Print() << "Adding random theta perturbations" << std::endl;
65  }
66  }
67  }
68 
69  ParallelForRNG(bx, [=,one_d=one] AMREX_GPU_DEVICE(int i, int j, int k, const amrex::RandomEngine& engine) noexcept
70  {
71  const Real* dx = geomdata.CellSize();
72  const Real x = prob_lo[0] + (i + myhalf) * dx[0];
73  const Real y = prob_lo[1] + (j + myhalf) * dx[1];
74  const Real z = z_cc(i,j,k);
75  const Real z_agl = z - erf_prob_heights::z_ground_cc(i,j,z_sfc_nd); // height above the ground
76 
77  // Define a point (xc,yc,zc) at the center of the domain
78  const Real xc = myhalf * (prob_lo[0] + prob_hi[0]);
79  const Real yc = myhalf * (prob_lo[1] + prob_hi[1]);
80  const Real zc = myhalf * (phys_z_lo + phys_z_hi);
81 
82  const Real r = std::sqrt((x-xc)*(x-xc) + (y-yc)*(y-yc) + (z-zc)*(z-zc));
83 
84  // Add temperature perturbations
85  if ((z_agl <= pert_ref_height) && (T_0_Pert_Mag != zero)) {
86  Real rand_double = amrex::Random(engine); // Between zero and one
87  state_pert(i, j, k, RhoTheta_comp) = (rand_double*two - one_d)*T_0_Pert_Mag;
88  if (!pert_rhotheta) {
89  // we're perturbing theta, not rho*theta
90  state_pert(i, j, k, RhoTheta_comp) *= r_hse(i,j,k);
91  }
92  }
93 
94  // Set scalar = A_0*exp(-10r^2), where r is distance from center of domain
95  state_pert(i, j, k, RhoScalar_comp) = A_0 * std::exp(-amrex::Real(10.)*r*r);
96 
97  // Set an initial value for SGS KE
98  //
99  // KE_decay_height is a depth of turbulence above the ground, so the profile
100  // is a function of height above the terrain surface, not of absolute z. Over
101  // terrain higher than KE_decay_height the latter would clamp the decay factor
102  // to its floor at the ground -- exactly backwards. On a flat mesh this is the
103  // height above geometry.prob_lo[2]. Under EB, z_cc is already measured
104  // from the EB surface, so the ground is at zero there (see z_sfc_nd). Matches
105  // the surface height used by SurfaceLayer::init_tke_from_ustar.
106  if (state_pert.nComp() > RhoKE_comp) {
107  // Deardorff
108  state_pert(i, j, k, RhoKE_comp) = r_hse(i,j,k) * KE_0;
109  if (KE_decay_height > 0) {
110  // scale initial SGS kinetic energy with height
111  state_pert(i, j, k, RhoKE_comp) *= max(
112  std::pow(1 - min(z_agl/KE_decay_height,one_d), KE_decay_order),
113  amrex::Real(1e-12));
114  }
115  }
116  });
#define RhoScalar_comp
Definition: ERF_IndexDefines.H:57
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:54
#define RhoKE_comp
Definition: ERF_IndexDefines.H:55
const Real zc
Definition: ERF_InitCustomPert_ABL.H:56
const Real yc
Definition: ERF_InitCustomPert_ABL.H:55
const Real xc
Definition: ERF_InitCustomPert_ABL.H:54
const Real dx
Definition: ERF_InitCustomPert_ABL.H:44
const GpuArray< Real, AMREX_SPACEDIM > prob_lo
Definition: ERF_InitCustomPert_TurbulentInflow.H:38
Real W_0_Pert_Mag
Definition: ERF_InitCustomPert_TurbulentInflow.H:25
Real T_0_Pert_Mag
Definition: ERF_InitCustomPert_TurbulentInflow.H:26
Real pert_ref_height
Definition: ERF_InitCustomPert_TurbulentInflow.H:34
Real KE_0
Definition: ERF_InitCustomPert_TurbulentInflow.H:13
Real rho_0
Definition: ERF_InitCustomPert_TurbulentInflow.H:9
const Real phys_z_hi
Definition: ERF_InitCustomPert_TurbulentInflow.H:5
ParmParse pp("prob")
Real U_0_Pert_Mag
Definition: ERF_InitCustomPert_TurbulentInflow.H:23
ParallelForRNG(bx, [=, one_d=one] AMREX_GPU_DEVICE(int i, int j, int k, const amrex::RandomEngine &engine) noexcept { const Real *dx=geomdata.CellSize();const Real x=prob_lo[0]+(i+myhalf) *dx[0];const Real y=prob_lo[1]+(j+myhalf) *dx[1];const Real z=z_cc(i, j, k);const Real z_agl=z - erf_prob_heights::z_ground_cc(i, j, z_sfc_nd);const Real xc=myhalf *(prob_lo[0]+prob_hi[0]);const Real yc=myhalf *(prob_lo[1]+prob_hi[1]);const Real zc=myhalf *(phys_z_lo+phys_z_hi);const Real r=std::sqrt((x-xc) *(x-xc)+(y-yc) *(y-yc)+(z-zc) *(z-zc));if((z_agl<=pert_ref_height) &&(T_0_Pert_Mag !=zero)) { Real rand_double=amrex::Random(engine);state_pert(i, j, k, RhoTheta_comp)=(rand_double *two - one_d) *T_0_Pert_Mag;if(!pert_rhotheta) { state_pert(i, j, k, RhoTheta_comp) *=r_hse(i, j, k);} } state_pert(i, j, k, RhoScalar_comp)=A_0 *std::exp(-amrex::Real(10.) *r *r);if(state_pert.nComp() > RhoKE_comp) { state_pert(i, j, k, RhoKE_comp)=r_hse(i, j, k) *KE_0;if(KE_decay_height > 0) { state_pert(i, j, k, RhoKE_comp) *=max(std::pow(1 - min(z_agl/KE_decay_height, one_d), KE_decay_order), amrex::Real(1e-12));} } })
Real pert_periods_V
Definition: ERF_InitCustomPert_TurbulentInflow.H:33
Real T_0
Definition: ERF_InitCustomPert_TurbulentInflow.H:10
Real pert_deltaV
Definition: ERF_InitCustomPert_TurbulentInflow.H:31
Real U_0
Definition: ERF_InitCustomPert_TurbulentInflow.H:18
Real KE_decay_order
Definition: ERF_InitCustomPert_TurbulentInflow.H:16
Real V_0
Definition: ERF_InitCustomPert_TurbulentInflow.H:19
Real pert_deltaU
Definition: ERF_InitCustomPert_TurbulentInflow.H:30
Real pert_periods_U
Definition: ERF_InitCustomPert_TurbulentInflow.H:32
Real KE_decay_height
Definition: ERF_InitCustomPert_TurbulentInflow.H:15
const GpuArray< Real, AMREX_SPACEDIM > prob_hi
Definition: ERF_InitCustomPert_TurbulentInflow.H:39
bool pert_rhotheta
Definition: ERF_InitCustomPert_TurbulentInflow.H:27
Real W_0
Definition: ERF_InitCustomPert_TurbulentInflow.H:20
Real A_0
Definition: ERF_InitCustomPert_TurbulentInflow.H:12
Real V_0_Pert_Mag
Definition: ERF_InitCustomPert_TurbulentInflow.H:24
const Real phys_z_lo
Definition: ERF_InitCustomPert_TurbulentInflow.H:4
constexpr amrex::Real two
Definition: ERF_NumericalConstants.H:38
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:37
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:36
constexpr amrex::Real myhalf
Definition: ERF_NumericalConstants.H:41
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real z_ground_cc(int i, int j, amrex::Array4< amrex::Real const > const &z_sfc_nd) noexcept
Definition: ERF_ProbHeights.H:49