ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_InitCustomPert_RICO.H
Go to the documentation of this file.
1  // On a mesh other than ConstantDz, heights come from z_cc and the vertical levels,
2  // not from geomdata's prob_lo[2], prob_hi[2] and CellSize(2)
3  const bool use_z_phys = use_physical_z();
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("prob");
8 
9  Real A_0 = one; pp_prob.query("A_0", A_0);
10  Real KE_0 = amrex::Real(0.1); pp_prob.query("KE_0", KE_0);
11 
12  // sinusoidal perturbations for regression tests
13  Real pert_deltaT = zero; pp_prob.query("pert_deltaT", pert_deltaT);
14  Real pert_deltaQV = zero; pp_prob.query("pert_deltaQV", pert_deltaQV);
15  // The periods default to 5, as pert_periods_U/V do: a zero period would make
16  // cos(cval*(x-xc)) identically one, a uniform bias rather than a zero-mean wave
17  Real pert_periods_T = amrex::Real(5.0); pp_prob.query("pert_periods_T", pert_periods_T);
18  Real pert_periods_QV = amrex::Real(5.0); pp_prob.query("pert_periods_QV", pert_periods_QV);
19 
20  Real T_0_Pert_Mag = zero; pp_prob.query("T_0_Pert_Mag", T_0_Pert_Mag);
21  Real qv_0_Pert_Mag = zero; pp_prob.query("qv_0_Pert_Mag", qv_0_Pert_Mag);
22 
23  Real wbar_sub_max = -amrex::Real(0.65); pp_prob.query("wbar_sub_max", wbar_sub_max);
24 
25  Real pert_ref_height = amrex::Real(100.0); pp_prob.query("pert_ref_height", pert_ref_height);
26 
27  bool custom_TKE = false; pp_prob.query("custom_TKE", custom_TKE);
28 
29  const Real prob_lo_x = geomdata.ProbLo()[0];
30  const Real prob_hi_x = geomdata.ProbHi()[0];
31 
34 
37 
38  const bool use_moisture = (sc.moisture_type != MoistureType::None);
39 
40  const Real rdOcp = sc.rdOcp;
41 
42  ParallelForRNG(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k, const RandomEngine& engine) noexcept
43  {
44  // Geometry
45  const Real* prob_lo = geomdata.ProbLo();
46  const Real* prob_hi = geomdata.ProbHi();
47  const Real* dx = geomdata.CellSize();
48  const Real x = prob_lo[0] + (i + myhalf) * dx[0];
49  const Real y = prob_lo[1] + (j + myhalf) * dx[1];
50  const Real z = use_z_phys ? z_cc(i,j,k) : prob_lo[2] + (k + myhalf) * dx[2];
51  const Real z_agl = z - erf_prob_heights::z_ground_cc(i,j,z_sfc_nd); // height above the ground
52 
53  // Define a point (xc,yc,zc) at the center of the domain
54  const Real xc = myhalf * (prob_lo[0] + prob_hi[0]);
55  const Real yc = myhalf * (prob_lo[1] + prob_hi[1]);
56  const Real zc = myhalf * (phys_z_lo + phys_z_hi);
57 
58  const Real r = std::sqrt((x-xc)*(x-xc) + (y-yc)*(y-yc) + (z-zc)*(z-zc));
59  // Temperature and qv perturbations: the random ones (T_0_Pert_Mag, qv_0_Pert_Mag)
60  // and the sinusoidal ones for regression tests (pert_deltaT, pert_deltaQV) are
61  // summed, then applied once (ERF_MoistPerturbation.H), as in the GATE setup, so
62  // that turning on one does not discard the other. The temperature perturbation
63  // at fixed pressure ends up as a density perturbation (rho*theta is held), and
64  // qv becomes qv + dqv on the new density, so a temperature perturbation alone
65  // leaves qv, and the pressure, as they were
66  const bool rand_T = (z_agl <= pert_ref_height) && (T_0_Pert_Mag != zero);
67  const bool rand_qv = use_moisture && (z_agl <= pert_ref_height) && (qv_0_Pert_Mag != zero);
68  const bool sin_T = (pert_deltaT != zero);
69  const bool sin_qv = use_moisture && (pert_deltaQV != zero);
70 
71  // The random numbers are drawn in the same order as when each was applied on its own
72  Real dT = zero;
73  Real dqv = zero;
74  if (rand_T) {
75  Real rand_double = amrex::Random(engine); // Between zero and one
76  dT += (rand_double*two - one)*T_0_Pert_Mag;
77  }
78  if (rand_qv) {
79  Real rand_double = amrex::Random(engine); // Between zero and one
80  dqv += (rand_double*two - one)*qv_0_Pert_Mag;
81  }
82  if (sin_T || sin_qv) {
83  const Real zl = z_agl / pert_ref_height;
84  const Real damp = std::exp(-myhalf * zl * zl);
85  if (sin_T) { dT += tfac * damp * z_agl * std::cos(cval * (x - xc)); }
86  if (sin_qv) { dqv += qvfac * damp * z_agl * std::cos(dval * (x - xc)); }
87  }
88 
89  if (rand_T || sin_T || rand_qv || sin_qv) {
90  Real drho, drhoqv;
92  state(i,j,k,Rho_comp), state(i,j,k,RhoTheta_comp),
93  use_moisture ? state(i,j,k,RhoQ1_comp) : zero, dT, dqv,
94  rand_T || sin_T, use_moisture, rdOcp, drho, drhoqv);
95  if (rand_T || sin_T) {
96  state_pert(i, j, k, Rho_comp) = drho;
97  // Note we do not perturb this
98  state_pert(i, j, k, RhoTheta_comp) = zero;
99  }
100  if (use_moisture) { state_pert(i, j, k, RhoQ1_comp) = drhoqv; }
101  }
102 
103  // Set scalar = A_0*exp(-10r^2), where r is distance from center of domain
104  state_pert(i, j, k, RhoScalar_comp) = A_0 * std::exp(-amrex::Real(10.)*r*r);
105 
106  // Set an initial value for KE
107  if (custom_TKE) {
108  state_pert(i, j, k, RhoKE_comp) = (one - z/phys_z_hi) * r_hse(i,j,k);
109  } else {
110  state_pert(i, j, k, RhoKE_comp) = KE_0;
111  }
112 
113  if (use_moisture) {
114  // The density change above would change qc with it; rescale rho*qc so the
115  // cloud-water mixing ratio is held, as in Aaron Lattanzi's #4772 for BOMEX
116  state_pert(i, j, k, RhoQ2_comp) = state_pert(i,j,k,Rho_comp)
117  * state(i,j,k,RhoQ2_comp) / state(i,j,k,Rho_comp);
118  }
119  });
#define RhoScalar_comp
Definition: ERF_IndexDefines.H:57
#define Rho_comp
Definition: ERF_IndexDefines.H:53
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:54
#define RhoQ2_comp
Definition: ERF_IndexDefines.H:67
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:66
#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_CloudChamber.H:33
const amrex::Real * prob_hi
Definition: ERF_InitCustomPert_DataAssimilation_ISV.H:17
const bool use_z_phys
Definition: ERF_InitCustomPert_RICO.H:3
Real pert_periods_QV
Definition: ERF_InitCustomPert_RICO.H:18
Real T_0_Pert_Mag
Definition: ERF_InitCustomPert_RICO.H:20
Real pert_ref_height
Definition: ERF_InitCustomPert_RICO.H:25
const bool use_moisture
Definition: ERF_InitCustomPert_RICO.H:38
Real KE_0
Definition: ERF_InitCustomPert_RICO.H:10
Real dval
Definition: ERF_InitCustomPert_RICO.H:33
const Real rdOcp
Definition: ERF_InitCustomPert_RICO.H:40
const Real phys_z_hi
Definition: ERF_InitCustomPert_RICO.H:5
ParmParse pp_prob("prob")
const Real prob_lo_x
Definition: ERF_InitCustomPert_RICO.H:29
Real tfac
Definition: ERF_InitCustomPert_RICO.H:35
const Real prob_hi_x
Definition: ERF_InitCustomPert_RICO.H:30
Real wbar_sub_max
Definition: ERF_InitCustomPert_RICO.H:23
Real pert_deltaQV
Definition: ERF_InitCustomPert_RICO.H:14
Real pert_periods_T
Definition: ERF_InitCustomPert_RICO.H:17
Real qvfac
Definition: ERF_InitCustomPert_RICO.H:36
ParallelForRNG(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k, const RandomEngine &engine) noexcept { const Real *prob_lo=geomdata.ProbLo();const Real *prob_hi=geomdata.ProbHi();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=use_z_phys ? z_cc(i, j, k) :prob_lo[2]+(k+myhalf) *dx[2];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));const bool rand_T=(z_agl<=pert_ref_height) &&(T_0_Pert_Mag !=zero);const bool rand_qv=use_moisture &&(z_agl<=pert_ref_height) &&(qv_0_Pert_Mag !=zero);const bool sin_T=(pert_deltaT !=zero);const bool sin_qv=use_moisture &&(pert_deltaQV !=zero);Real dT=zero;Real dqv=zero;if(rand_T) { Real rand_double=amrex::Random(engine);dT+=(rand_double *two - one) *T_0_Pert_Mag;} if(rand_qv) { Real rand_double=amrex::Random(engine);dqv+=(rand_double *two - one) *qv_0_Pert_Mag;} if(sin_T||sin_qv) { const Real zl=z_agl/pert_ref_height;const Real damp=std::exp(-myhalf *zl *zl);if(sin_T) { dT+=tfac *damp *z_agl *std::cos(cval *(x - xc));} if(sin_qv) { dqv+=qvfac *damp *z_agl *std::cos(dval *(x - xc));} } if(rand_T||sin_T||rand_qv||sin_qv) { Real drho, drhoqv;erf_moist_perturbation::perturb_temperature_and_vapour(state(i, j, k, Rho_comp), state(i, j, k, RhoTheta_comp), use_moisture ? state(i, j, k, RhoQ1_comp) :zero, dT, dqv, rand_T||sin_T, use_moisture, rdOcp, drho, drhoqv);if(rand_T||sin_T) { state_pert(i, j, k, Rho_comp)=drho;state_pert(i, j, k, RhoTheta_comp)=zero;} if(use_moisture) { state_pert(i, j, k, RhoQ1_comp)=drhoqv;} } state_pert(i, j, k, RhoScalar_comp)=A_0 *std::exp(-amrex::Real(10.) *r *r);if(custom_TKE) { state_pert(i, j, k, RhoKE_comp)=(one - z/phys_z_hi) *r_hse(i, j, k);} else { state_pert(i, j, k, RhoKE_comp)=KE_0;} if(use_moisture) { state_pert(i, j, k, RhoQ2_comp)=state_pert(i, j, k, Rho_comp) *state(i, j, k, RhoQ2_comp)/state(i, j, k, Rho_comp);} })
Real A_0
Definition: ERF_InitCustomPert_RICO.H:9
Real qv_0_Pert_Mag
Definition: ERF_InitCustomPert_RICO.H:21
Real pert_deltaT
Definition: ERF_InitCustomPert_RICO.H:13
Real cval
Definition: ERF_InitCustomPert_RICO.H:32
bool custom_TKE
Definition: ERF_InitCustomPert_RICO.H:27
const Real phys_z_lo
Definition: ERF_InitCustomPert_RICO.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
constexpr amrex::Real PI
Definition: ERF_NumericalConstants.H:46
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ None
Definition: ERF_LSM_Types.H:6
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void perturb_temperature_and_vapour(const amrex::Real rho, const amrex::Real rhotheta, const amrex::Real rhoqv, const amrex::Real dT, const amrex::Real dqv, const bool perturb_T, const bool moist, const amrex::Real rdOcp, amrex::Real &drho, amrex::Real &drhoqv) noexcept
Definition: ERF_MoistPerturbation.H:39
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