1313 Diagnose horizontal covariances based on vertical gradients
1414 (i.e. taking turbulence production as the only term)
1515"""
16- function compute_covariance(Y, p, thermo_params, ᶜts )
16+ function compute_covariance(Y, p, thermo_params)
1717 coeff = CAP. diagnostic_covariance_coeff(p. params)
1818 turbconv_model = p. atmos. turbconv_model
1919 (; ᶜgradᵥ_q_tot, ᶜgradᵥ_θ_liq_ice) = p. precomputed
@@ -23,10 +23,20 @@ function compute_covariance(Y, p, thermo_params, ᶜts)
2323 if isnothing(turbconv_model)
2424 if p. atmos. call_cloud_diagnostics_per_stage isa
2525 CallCloudDiagnosticsPerStage
26- @. ᶜgradᵥ_q_tot =
27- ᶜgradᵥ(ᶠinterp(TD. total_specific_humidity(thermo_params, ᶜts)))
28- @. ᶜgradᵥ_θ_liq_ice =
29- ᶜgradᵥ(ᶠinterp(TD. liquid_ice_pottemp(thermo_params, ᶜts)))
26+ (; ᶜT, ᶜq_tot_safe, ᶜq_liq_rai, ᶜq_ice_sno) = p. precomputed
27+ @. ᶜgradᵥ_q_tot = ᶜgradᵥ(ᶠinterp(ᶜq_tot_safe))
28+ @. ᶜgradᵥ_θ_liq_ice = ᶜgradᵥ(
29+ ᶠinterp(
30+ TD. liquid_ice_pottemp(
31+ thermo_params,
32+ ᶜT,
33+ Y. c. ρ,
34+ ᶜq_tot_safe,
35+ ᶜq_liq_rai,
36+ ᶜq_ice_sno,
37+ ),
38+ ),
39+ )
3040 end
3141 end
3242 # Reminder that gradients need to be precomputed when using compute_gm_mixing_length
99109
100110"""
101111 function compute_cloud_fraction_quadrature_diagnostics(
102- thermo_params, SG_quad, ts , q′q′, θ′θ′, θ′q′
112+ thermo_params, SG_quad, p_c, q_mean, θ_mean , q′q′, θ′θ′, θ′q′
103113 )
104114
105115where:
106116 - thermo params - thermodynamics parameters
107117 - SG_quad is a struct containing information about Gaussian quadrature order,
108118 sampling point values and weights
109- - ts is the thermodynamic state
119+ - p_c is the air pressure
120+ - q_mean is the total specific humidity
121+ - θ_mean is the liquid-ice potential temperature
110122 - q′q′, θ′θ′, θ′q′ are the covariances of q_tot and liquid ice potential temperature
111123
112124The function imposes additional limits on the quadrature points
@@ -117,15 +129,13 @@ computed as a sum over quadrature points with weights.
117129function compute_cloud_fraction_quadrature_diagnostics(
118130 thermo_params,
119131 SG_quad:: SGSQuadrature ,
120- ts,
132+ p_c,
133+ q_mean,
134+ θ_mean,
121135 q′q′,
122136 θ′θ′,
123137 θ′q′,
124138)
125- # Grab mean pressure, liquid ice potential temperature and total specific humidity
126- p_c = TD. air_pressure(thermo_params, ts)
127- q_mean = TD. total_specific_humidity(thermo_params, ts)
128- θ_mean = TD. liquid_ice_pottemp(thermo_params, ts)
129139
130140 # Return physical values based on quadrature points and limited covarainces
131141 function get_x_hat(χ1, χ2)
@@ -158,7 +168,7 @@ function compute_cloud_fraction_quadrature_diagnostics(
158168
159169 function f(x1_hat, x2_hat)
160170 FT = eltype(thermo_params)
161- _ts = thermo_state (thermo_params; p = p_c, θ = x1_hat, q_tot = x2_hat)
171+ _ts = TD . PhaseEquil_pθq (thermo_params, p_c, x1_hat, x2_hat)
162172 hc = TD. has_condensate(thermo_params, _ts)
163173
164174 cf = hc ? FT(1 ) : FT(0 ) # cloud fraction
@@ -192,23 +202,22 @@ NVTX.@annotate function set_cloud_fraction!(
192202 moist_model:: Union{EquilMoistModel, NonEquilMoistModel} ,
193203 :: GridScaleCloud ,
194204)
195- (; ᶜts) = p. precomputed
196- thermo_params = CAP. thermodynamics_params(p. params)
205+ (; ᶜq_liq_rai, ᶜq_ice_sno) = p. precomputed
197206 FT = eltype(p. params)
198207
199208 if moist_model isa EquilMoistModel
200209 @. p. precomputed. cloud_diagnostics_tuple =
201210 make_cloud_fraction_named_tuple(
202- ifelse(TD. has_condensate(thermo_params, ᶜts ), FT(1 ), FT(0 )),
203- TD . PhasePartition(thermo_params, ᶜts) . liq ,
204- TD . PhasePartition(thermo_params, ᶜts) . ice ,
211+ ifelse(TD. has_condensate(ᶜq_liq_rai + ᶜq_ice_sno ), FT(1 ), FT(0 )),
212+ ᶜq_liq_rai ,
213+ ᶜq_ice_sno ,
205214 )
206215 else
207216 q_liq = @. lazy(specific(Y. c. ρq_liq, Y. c. ρ))
208217 q_ice = @. lazy(specific(Y. c. ρq_ice, Y. c. ρ))
209218 @. p. precomputed. cloud_diagnostics_tuple =
210219 make_cloud_fraction_named_tuple(
211- ifelse(TD. has_condensate(thermo_params, ᶜts ), FT(1 ), FT(0 )),
220+ ifelse(TD. has_condensate(ᶜq_liq_rai + ᶜq_ice_sno ), FT(1 ), FT(0 )),
212221 q_liq,
213222 q_ice,
214223 )
@@ -222,18 +231,40 @@ NVTX.@annotate function set_cloud_fraction!(
222231)
223232 thermo_params = CAP. thermodynamics_params(p. params)
224233 turbconv_model = p. atmos. turbconv_model
234+ (; ᶜp, ᶜT, ᶜq_tot_safe, ᶜq_liq_rai, ᶜq_ice_sno) = p. precomputed
225235
226- ᶜts = turbconv_model isa PrognosticEDMFX ? p. precomputed. ᶜts⁰ : p. precomputed. ᶜts
236+ # For PrognosticEDMFX, use environment state; otherwise use grid-scale
237+ if turbconv_model isa PrognosticEDMFX
238+ ᶜts⁰ = p. precomputed. ᶜts⁰
239+ ᶜp_env = @. lazy(TD. air_pressure(thermo_params, ᶜts⁰))
240+ ᶜq_mean = @. lazy(TD. total_specific_humidity(thermo_params, ᶜts⁰))
241+ ᶜθ_mean = @. lazy(TD. liquid_ice_pottemp(thermo_params, ᶜts⁰))
242+ else
243+ ᶜp_env = ᶜp
244+ ᶜq_mean = ᶜq_tot_safe
245+ ᶜθ_mean = @. lazy(
246+ TD. liquid_ice_pottemp(
247+ thermo_params,
248+ ᶜT,
249+ Y. c. ρ,
250+ ᶜq_tot_safe,
251+ ᶜq_liq_rai,
252+ ᶜq_ice_sno,
253+ ),
254+ )
255+ end
227256
228257 # Compute covariance based on the gradients of q_tot and theta_liq_ice
229- ᶜq′q′, ᶜθ′θ′, ᶜθ′q′ = compute_covariance(Y, p, thermo_params, ᶜts )
258+ ᶜq′q′, ᶜθ′θ′, ᶜθ′q′ = compute_covariance(Y, p, thermo_params)
230259
231260 # Compute SGS cloud fraction diagnostics based on environment quadrature points ...
232261 @. p. precomputed. cloud_diagnostics_tuple =
233262 compute_cloud_fraction_quadrature_diagnostics(
234263 thermo_params,
235264 qc. SG_quad,
236- ᶜts,
265+ ᶜp_env,
266+ ᶜq_mean,
267+ ᶜθ_mean,
237268 ᶜq′q′,
238269 ᶜθ′θ′,
239270 ᶜθ′q′,
@@ -247,18 +278,21 @@ NVTX.@annotate function set_cloud_fraction!(
247278 qc,
248279 thermo_params,
249280 turbconv_model,
250- ᶜts,
281+ ᶜp_env,
282+ ᶜq_mean,
283+ ᶜθ_mean,
251284 )
252285 end
253286
254287 # ... weight by environment area fraction if using PrognosticEDMFX (assumed 1 otherwise) ...
255288 if turbconv_model isa PrognosticEDMFX
256289 ᶜρa⁰ = @. lazy(ρa⁰(Y. c. ρ, Y. c. sgsʲs, p. atmos. turbconv_model))
290+ ᶜρ⁰ = @. lazy(TD. air_density(thermo_params, p. precomputed. ᶜts⁰))
257291 @. p. precomputed. cloud_diagnostics_tuple *= NamedTuple{(:cf, :q_liq, :q_ice)}(
258292 tuple(
259- draft_area(ᶜρa⁰, TD . air_density(thermo_params, ᶜts) ),
260- draft_area(ᶜρa⁰, TD . air_density(thermo_params, ᶜts) ),
261- draft_area(ᶜρa⁰, TD . air_density(thermo_params, ᶜts) ),
293+ draft_area(ᶜρa⁰, ᶜρ⁰ ),
294+ draft_area(ᶜρa⁰, ᶜρ⁰ ),
295+ draft_area(ᶜρa⁰, ᶜρ⁰ ),
262296 ),
263297 )
264298 end
@@ -294,7 +328,9 @@ function set_ml_cloud_fraction!(
294328 ml_cloud:: MLCloud ,
295329 thermo_params,
296330 turbconv_model,
297- ᶜts,
331+ ᶜp_env,
332+ ᶜq_mean,
333+ ᶜθ_mean,
298334)
299335 FT = eltype(p. params)
300336 ᶜmixing_length_field = p. scratch. ᶜtemp_scalar
@@ -325,8 +361,9 @@ function set_ml_cloud_fraction!(
325361 ᶜmixing_length_field,
326362 ᶜ∇q,
327363 ᶜ∇θ,
328- specific.(Y. c. ρq_tot, Y. c. ρ),
329- ᶜts,
364+ ᶜq_mean,
365+ ᶜp_env,
366+ ᶜθ_mean,
330367 thermo_params,
331368 )
332369end
@@ -337,20 +374,18 @@ function compute_ml_cloud_fraction(
337374 ᶜ∇q,
338375 ᶜ∇θ,
339376 q_tot,
340- ᶜts,
377+ p_c,
378+ θli,
341379 thermo_params,
342380)
343381 FT = eltype(thermo_params)
344- # Saturation state at current thermodynamic state
345- q_sat = TD. q_vap_saturation(thermo_params, ᶜts)
346-
347- # Liquid–ice potential temperature at current thermodynamic state
348- θli = TD. liquid_ice_pottemp(thermo_params, ᶜts)
349-
382+ # Saturation state at current thermodynamic state (via θ, p, q_tot)
383+ ts_current = TD. PhaseEquil_pθq(thermo_params, p_c, θli, q_tot)
384+ q_sat = TD. q_vap_saturation(thermo_params, ts_current)
350385
351386 # distance to saturation in temperature space
352387 Δθli, θli_sat, dqsatdθli =
353- saturation_distance(q_tot, q_sat, ᶜts , θli, thermo_params, FT(0.1 ))
388+ saturation_distance(q_tot, q_sat, p_c , θli, thermo_params, FT(0.1 ))
354389
355390 # form the pi groups
356391 π_1 = (q_sat - q_tot) / q_sat
@@ -359,17 +394,16 @@ function compute_ml_cloud_fraction(
359394 π_4 = (ᶜ∇θ * ᶜmixing_length_field) / θli_sat
360395
361396 return apply_cf_nn(nn_model, π_1, π_2, π_3, π_4)
362-
363397end
364398
365- function saturation_distance(q_tot, q_sat, ᶜts , θli, thermo_params, Δθli_fd)
399+ function saturation_distance(q_tot, q_sat, p_c , θli, thermo_params, Δθli_fd)
366400
367401 # Perturbed thermodynamic states for finite-difference
368402 ts_perturbed = TD. PhaseEquil_pθq(
369403 thermo_params,
370- ᶜts . p ,
371- θli . + Δθli_fd,
372- ᶜts . q_tot,
404+ p_c ,
405+ θli + Δθli_fd,
406+ q_tot,
373407 )
374408 q_sat_perturbed = TD. q_vap_saturation(thermo_params, ts_perturbed)
375409
0 commit comments