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