ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_MoistUtils.H
Go to the documentation of this file.
1 #ifndef ERF_MOISTUTILS_H_
2 #define ERF_MOISTUTILS_H_
3 
4 #include "ERF_EOS.H"
7 #include "ERF_Constants.H"
8 
9 // =============================================================================
10 // MOIST TURBULENCE FUNCTIONS
11 // =============================================================================
12 
13 /**
14  * Extract moisture variables and partition into liquid/ice phases
15  */
16 AMREX_GPU_DEVICE
17 AMREX_FORCE_INLINE
18 void GetMoistureVars (int i, int j, int k,
19  const amrex::Array4<amrex::Real const>& cell_data,
20  amrex::Real& qv,
21  amrex::Real& qc_liquid,
22  amrex::Real& qc_ice,
23  const MoistureComponentIndices& moisture_indices)
24 {
25  qv = zero; qc_liquid = zero; qc_ice = zero;
26 
27  // Water vapor
28  if (moisture_indices.qv >= 0) {
29  qv = cell_data(i,j,k,moisture_indices.qv)/cell_data(i,j,k,Rho_comp);
30  }
31 
32  // Cloud liquid water
33  if (moisture_indices.qc >= 0) {
34  qc_liquid = cell_data(i,j,k,moisture_indices.qc)/cell_data(i,j,k,Rho_comp);
35  }
36 
37  // Cloud ice (only if separate ice species exists)
38  if (moisture_indices.qi >= 0) {
39  qc_ice = cell_data(i,j,k,moisture_indices.qi)/cell_data(i,j,k,Rho_comp);
40  }
41  // No temperature-based partitioning - respect the microphysics scheme's decisions
42 
43  // Add precipitating species
44  if (moisture_indices.qr >= 0) { // Rain (always liquid)
45  qc_liquid += cell_data(i,j,k,moisture_indices.qr)/cell_data(i,j,k,Rho_comp);
46  }
47  if (moisture_indices.qs >= 0) { // Snow (always ice)
48  qc_ice += cell_data(i,j,k,moisture_indices.qs)/cell_data(i,j,k,Rho_comp);
49  }
50  if (moisture_indices.qg >= 0) { // Graupel (always ice)
51  qc_ice += cell_data(i,j,k,moisture_indices.qg)/cell_data(i,j,k,Rho_comp);
52  }
53 }
54 
55 /**
56  * Compute virtual potential temperature with moisture loading effects
57  */
58 AMREX_GPU_DEVICE
59 AMREX_FORCE_INLINE
61  const amrex::Real& qv,
62  const amrex::Real& qc_liquid,
63  const amrex::Real& qc_ice)
64 {
65  amrex::Real qc_total = qc_liquid + qc_ice;
66  return theta * (one + epsv * qv - qc_total);
67 }
68 
69 /**
70  * Wrapper around ComputeVirtualPotentialTemperature
71  */
72 AMREX_GPU_DEVICE
73 AMREX_FORCE_INLINE
74 amrex::Real GetThetav (const int& i, const int& j, const int& k,
75  const amrex::Array4<amrex::Real const>& cell_data,
76  const MoistureComponentIndices& moisture_indices)
77 {
78  amrex::Real theta = cell_data(i, j, k, RhoTheta_comp) / cell_data(i, j, k, Rho_comp);
79 
81  GetMoistureVars(i, j, k, cell_data, qv, qcl, qci, moisture_indices);
82 
84 }
85 
86 /**
87  * Compute liquid-water virtual potential temperature
88  * theta_vl = theta * (1 + 0.61*qv - ql - qi)
89  * where ql = qc (cloud liquid) and qi = qi (cloud ice)
90  * This accounts for condensate loading in the virtual temperature effect
91  */
92 AMREX_GPU_DEVICE
93 AMREX_FORCE_INLINE
94 amrex::Real GetThetavl (int i, int j, int k,
95  const amrex::Array4<amrex::Real const>& cell_data,
96  const MoistureComponentIndices& moisture_indices)
97 {
98  const amrex::Real rho = cell_data(i, j, k, Rho_comp);
99  const amrex::Real theta = cell_data(i, j, k, RhoTheta_comp) / rho;
100 
101  amrex::Real qv = zero, qc = zero, qi = zero;
102  if (moisture_indices.qv >= 0)
103  qv = cell_data(i, j, k, moisture_indices.qv) / rho;
104  if (moisture_indices.qc >= 0)
105  qc = cell_data(i, j, k, moisture_indices.qc) / rho;
106  if (moisture_indices.qi >= 0)
107  qi = cell_data(i, j, k, moisture_indices.qi) / rho;
108 
109  return theta * (one + epsv * qv - qc - qi);
110 }
111 
112 
113 /**
114  * Compute linearized liquid-water potential temperature
115  */
116 AMREX_GPU_DEVICE
117 AMREX_FORCE_INLINE
119  const amrex::Real& T,
120  const amrex::Real& qc_liquid)
121 {
122  return theta - (theta / T) * (L_v / Cp_d) * qc_liquid;
123 }
124 
125 /**
126  * Wrapper around ComputeLiquidWaterPotentialTemperature
127  */
128 AMREX_GPU_DEVICE
129 AMREX_FORCE_INLINE
130 amrex::Real GetThetal (const int& i, const int& j, const int& k,
131  const amrex::Array4<amrex::Real const>& cell_data,
132  const MoistureComponentIndices& moisture_indices)
133 {
134  amrex::Real qv, qcl, qci;
135  GetMoistureVars(i, j, k, cell_data, qv, qcl, qci, moisture_indices);
136 
137  amrex::Real theta = cell_data(i, j, k, RhoTheta_comp) / cell_data(i, j, k, Rho_comp);
138 
139  amrex::Real T = getTgivenRandRTh(cell_data(i, j, k, Rho_comp),
140  cell_data(i, j, k, RhoTheta_comp),
141  qv);
142 
144 }
145 
146 
147 /**
148  * Compute moist stratification accounting for conditional instability
149  */
150 AMREX_GPU_DEVICE
151 AMREX_FORCE_INLINE
152 amrex::Real ComputeMoistStratification (const int& i, const int& j, const int& k,
153  const amrex::Array4<amrex::Real const>& cell_data,
154  const amrex::Real& dzInv,
155  const amrex::Real& abs_g,
156  const amrex::Real& inv_theta0,
157  const MoistureComponentIndices& moisture_indices)
158 {
159  // Get moisture variables partitioned into phases
160  amrex::Real qv, qc_liquid, qc_ice;
161  GetMoistureVars(i, j, k, cell_data, qv, qc_liquid, qc_ice, moisture_indices);
162 
163  // Compute virtual potential temperature gradient
164  amrex::Real theta_v_upper = GetThetav(i, j, k+1, cell_data, moisture_indices);
165  amrex::Real theta_v_lower = GetThetav(i, j, k-1, cell_data, moisture_indices);
166 
167  amrex::Real dthetav_dz = myhalf * (theta_v_upper - theta_v_lower) * dzInv;
168  amrex::Real stratification = abs_g * dthetav_dz * inv_theta0;
169 
170  // Apply conditional instability correction
171  amrex::Real total_condensate = qc_liquid + qc_ice;
172  if (total_condensate > 1e-8) {
173  amrex::Real T_current = getTgivenRandRTh(cell_data(i,j,k,Rho_comp),
174  cell_data(i,j,k,RhoTheta_comp), qv);
175 
176  // Phase-weighted effective latent heat
177  amrex::Real liquid_fraction = qc_liquid / (total_condensate + amrex::Real(1e-12));
178  amrex::Real ice_fraction = one - liquid_fraction;
179  amrex::Real L_eff = liquid_fraction * L_v + ice_fraction * (L_v + lat_ice);
180 
181  // Phase-weighted saturation mixing ratio
182  amrex::Real qsat_liquid = zero, qsat_ice = zero;
183  amrex::Real pres_current = getPgivenRTh(cell_data(i,j,k,RhoTheta_comp), qv) * amrex::Real(0.01);
184 
185  erf_qsatw(T_current, pres_current, qsat_liquid);
186  erf_qsati(T_current, pres_current, qsat_ice);
187 
188  amrex::Real qsat_eff = liquid_fraction * qsat_liquid + ice_fraction * qsat_ice;
189 
190  // Moist adiabatic lapse rate correction
191  amrex::Real gamma_moist_factor = (one + L_eff*qsat_eff/(R_d*T_current)) /
192  (one + L_eff*L_eff*qsat_eff/(Cp_d*R_v*T_current*T_current));
193 
194  stratification *= gamma_moist_factor;
195  }
196 
197  return stratification;
198 }
199 
200 /**
201  * Compute stratification for Smagorinsky scheme (moist or dry)
202  */
203 AMREX_GPU_DEVICE
204 AMREX_FORCE_INLINE
205 amrex::Real ComputeStratificationForSmagorinsky (const int& i, const int& j, const int& k,
206  const amrex::Array4<amrex::Real const>& cell_data,
207  const amrex::Real& dzInv,
208  const amrex::Real& abs_g,
209  const amrex::Real& inv_theta0,
210  const bool& use_moisture,
211  const int& rho_qv_comp,
212  const MoistureComponentIndices& moisture_indices)
213 {
214  if (use_moisture && (rho_qv_comp >= 0)) {
215  // Moist stratification with virtual temperature and conditional instability
216  return ComputeMoistStratification(i, j, k, cell_data, dzInv, abs_g, inv_theta0, moisture_indices);
217  } else {
218  // Dry stratification (original approach)
219  amrex::Real theta_hi = cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp);
220  amrex::Real theta_lo = cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp);
221  amrex::Real dtheta_dz = myhalf * (theta_hi - theta_lo) * dzInv;
222  return abs_g * dtheta_dz * inv_theta0;
223  }
224 }
225 
226 #endif
constexpr amrex::Real epsv
Definition: ERF_Constants.H:40
constexpr amrex::Real R_v
Definition: ERF_Constants.H:35
constexpr amrex::Real Cp_d
Definition: ERF_Constants.H:36
constexpr amrex::Real R_d
Definition: ERF_Constants.H:34
constexpr amrex::Real L_v
Definition: ERF_Constants.H:51
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getTgivenRandRTh(const amrex::Real rho, const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:46
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:81
#define Rho_comp
Definition: ERF_IndexDefines.H:39
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:40
const bool use_moisture
Definition: ERF_InitCustomPert_ABL.H:71
Real theta_hi
Definition: ERF_InitCustomPert_AnelasticWallDiffusion.H:7
Real theta_lo
Definition: ERF_InitCustomPert_AnelasticWallDiffusion.H:6
Physical constants and tuning parameters used only by the moisture and cloud-physics code.
constexpr amrex::Real lat_ice
Definition: ERF_MicrophysicsConstants.H:114
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsatw(amrex::Real t, amrex::Real p, amrex::Real &qsatw)
Definition: ERF_MicrophysicsUtils.H:264
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsati(amrex::Real t, amrex::Real p, amrex::Real &qsati)
Definition: ERF_MicrophysicsUtils.H:254
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real ComputeLiquidWaterPotentialTemperature(const amrex::Real &theta, const amrex::Real &T, const amrex::Real &qc_liquid)
Definition: ERF_MoistUtils.H:118
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real ComputeMoistStratification(const int &i, const int &j, const int &k, const amrex::Array4< amrex::Real const > &cell_data, const amrex::Real &dzInv, const amrex::Real &abs_g, const amrex::Real &inv_theta0, const MoistureComponentIndices &moisture_indices)
Definition: ERF_MoistUtils.H:152
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real GetThetav(const int &i, const int &j, const int &k, const amrex::Array4< amrex::Real const > &cell_data, const MoistureComponentIndices &moisture_indices)
Definition: ERF_MoistUtils.H:74
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real GetThetavl(int i, int j, int k, const amrex::Array4< amrex::Real const > &cell_data, const MoistureComponentIndices &moisture_indices)
Definition: ERF_MoistUtils.H:94
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real ComputeVirtualPotentialTemperature(const amrex::Real &theta, const amrex::Real &qv, const amrex::Real &qc_liquid, const amrex::Real &qc_ice)
Definition: ERF_MoistUtils.H:60
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real ComputeStratificationForSmagorinsky(const int &i, const int &j, const int &k, const amrex::Array4< amrex::Real const > &cell_data, const amrex::Real &dzInv, const amrex::Real &abs_g, const amrex::Real &inv_theta0, const bool &use_moisture, const int &rho_qv_comp, const MoistureComponentIndices &moisture_indices)
Definition: ERF_MoistUtils.H:205
AMREX_GPU_DEVICE AMREX_FORCE_INLINE void GetMoistureVars(int i, int j, int k, const amrex::Array4< amrex::Real const > &cell_data, amrex::Real &qv, amrex::Real &qc_liquid, amrex::Real &qc_ice, const MoistureComponentIndices &moisture_indices)
Definition: ERF_MoistUtils.H:18
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real GetThetal(const int &i, const int &j, const int &k, const amrex::Array4< amrex::Real const > &cell_data, const MoistureComponentIndices &moisture_indices)
Definition: ERF_MoistUtils.H:130
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:30
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:29
constexpr amrex::Real myhalf
Definition: ERF_NumericalConstants.H:34
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ theta
Definition: ERF_SLM.H:19
@ qcl
Definition: ERF_Kessler.H:32
@ rho
Definition: ERF_Kessler.H:25
@ qv
Definition: ERF_Kessler.H:31
@ qci
Definition: ERF_Morrison.H:38
@ qc
Definition: ERF_SatAdj.H:42
@ qi
Definition: ERF_WDM6.H:28
@ T
Definition: ERF_IndexDefines.H:128
The moisture data carried by the active microphysics scheme.
Definition: ERF_DataStruct.H:223
int qs
snow
Definition: ERF_DataStruct.H:238
int qr
rain
Definition: ERF_DataStruct.H:237
int qi
cloud ice
Definition: ERF_DataStruct.H:236
int qv
water vapor
Definition: ERF_DataStruct.H:234
int qc
cloud liquid water
Definition: ERF_DataStruct.H:235
int qg
graupel
Definition: ERF_DataStruct.H:239