Skip to content

Commit 0423e17

Browse files
committed
use cloud fraction in buoyancy gradient
1 parent bdfa8c0 commit 0423e17

File tree

10 files changed

+69
-82
lines changed

10 files changed

+69
-82
lines changed

src/cache/cloud_fraction.jl

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ end
2222
Compute the grid scale cloud fraction based on sub-grid scale properties
2323
"""
2424
NVTX.@annotate function set_cloud_fraction!(Y, p, ::DryModel, _)
25-
(; turbconv_model) = p.atmos
2625
FT = eltype(p.params)
2726

2827
p.precomputed.cloud_diagnostics_tuple .=
@@ -35,23 +34,9 @@ NVTX.@annotate function set_cloud_fraction!(
3534
::GridScaleCloud,
3635
)
3736
(; params) = p
38-
(; turbconv_model) = p.atmos
3937
(; ᶜts, cloud_diagnostics_tuple) = p.precomputed
4038
thermo_params = CAP.thermodynamics_params(params)
4139

42-
if isnothing(turbconv_model)
43-
if p.atmos.call_cloud_diagnostics_per_stage isa
44-
CallCloudDiagnosticsPerStage
45-
(; ᶜgradᵥ_θ_virt, ᶜgradᵥ_q_tot, ᶜgradᵥ_θ_liq_ice) = p.precomputed
46-
thermo_params = CAP.thermodynamics_params(p.params)
47-
@. ᶜgradᵥ_θ_virt =
48-
ᶜgradᵥ(ᶠinterp(TD.virtual_pottemp(thermo_params, ᶜts)))
49-
@. ᶜgradᵥ_q_tot =
50-
ᶜgradᵥ(ᶠinterp(TD.total_specific_humidity(thermo_params, ᶜts)))
51-
@. ᶜgradᵥ_θ_liq_ice =
52-
ᶜgradᵥ(ᶠinterp(TD.liquid_ice_pottemp(thermo_params, ᶜts)))
53-
end
54-
end
5540
if moist_model isa EquilMoistModel
5641
@. cloud_diagnostics_tuple = make_named_tuple(
5742
ifelse(TD.has_condensate(thermo_params, ᶜts), 1, 0),
@@ -83,10 +68,8 @@ NVTX.@annotate function set_cloud_fraction!(
8368
if isnothing(turbconv_model)
8469
if p.atmos.call_cloud_diagnostics_per_stage isa
8570
CallCloudDiagnosticsPerStage
86-
(; ᶜgradᵥ_θ_virt, ᶜgradᵥ_q_tot, ᶜgradᵥ_θ_liq_ice) = p.precomputed
71+
(; ᶜgradᵥ_q_tot, ᶜgradᵥ_θ_liq_ice) = p.precomputed
8772
thermo_params = CAP.thermodynamics_params(p.params)
88-
@. ᶜgradᵥ_θ_virt =
89-
ᶜgradᵥ(ᶠinterp(TD.virtual_pottemp(thermo_params, ᶜts)))
9073
@. ᶜgradᵥ_q_tot =
9174
ᶜgradᵥ(ᶠinterp(TD.total_specific_humidity(thermo_params, ᶜts)))
9275
@. ᶜgradᵥ_θ_liq_ice =

src/cache/diagnostic_edmf_precomputed_quantities.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,10 +1366,10 @@ NVTX.@annotate function set_diagnostic_edmf_precomputed_quantities_env_closures!
13661366
thermo_params,
13671367
moisture_model,
13681368
ᶜts,
1369+
p.precomputed.cloud_diagnostics_tuple.cf,
13691370
C3,
1370-
p.precomputed.ᶜgradᵥ_θ_virt, # ∂θv∂z_unsat
1371-
p.precomputed.ᶜgradᵥ_q_tot, # ∂qt∂z_sat
1372-
p.precomputed.ᶜgradᵥ_θ_liq_ice, # ∂θl∂z_sat
1371+
p.precomputed.ᶜgradᵥ_q_tot,
1372+
p.precomputed.ᶜgradᵥ_θ_liq_ice,
13731373
ᶜlg,
13741374
)
13751375

src/cache/precomputed_quantities.jl

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ function precomputed_quantities(Y, atmos)
8585
TST = thermo_state_type(atmos.moisture_model, FT)
8686
SCT = SurfaceConditions.surface_conditions_type(atmos, FT)
8787
cspace = axes(Y.c)
88-
fspace = axes(Y.f)
8988
n = n_mass_flux_subdomains(atmos.turbconv_model)
9089
n_prog = n_prognostic_mass_flux_subdomains(atmos.turbconv_model)
9190
@assert !(atmos.turbconv_model isa PrognosticEDMFX) || n_prog == 1
@@ -98,6 +97,8 @@ function precomputed_quantities(Y, atmos)
9897
)
9998
cloud_diagnostics_tuple =
10099
similar(Y.c, @NamedTuple{cf::FT, q_liq::FT, q_ice::FT})
100+
# Cloud fraction is used to calculate buoyancy gradient, so we initialize it to 0 here.
101+
@. cloud_diagnostics_tuple.cf = FT(0)
101102
surface_precip_fluxes = (;
102103
surface_rain_flux = zeros(axes(Fields.level(Y.f, half))),
103104
surface_snow_flux = zeros(axes(Fields.level(Y.f, half))),
@@ -200,7 +201,6 @@ function precomputed_quantities(Y, atmos)
200201
ᶜentrʲs = similar(Y.c, NTuple{n, FT}),
201202
ᶜdetrʲs = similar(Y.c, NTuple{n, FT}),
202203
ᶜturb_entrʲs = similar(Y.c, NTuple{n, FT}),
203-
ᶜgradᵥ_θ_virt = Fields.Field(C3{FT}, cspace),
204204
ᶜgradᵥ_q_tot = Fields.Field(C3{FT}, cspace),
205205
ᶜgradᵥ_θ_liq_ice = Fields.Field(C3{FT}, cspace),
206206
ᶠnh_pressure₃_buoyʲs = similar(Y.f, NTuple{n, C3{FT}}),
@@ -212,7 +212,6 @@ function precomputed_quantities(Y, atmos)
212212
(; ρatke_flux = similar(Fields.level(Y.f, half), C3{FT}),) : (;)
213213

214214
sgs_quantities = (;
215-
ᶜgradᵥ_θ_virt = Fields.Field(C3{FT}, cspace),
216215
ᶜgradᵥ_q_tot = Fields.Field(C3{FT}, cspace),
217216
ᶜgradᵥ_θ_liq_ice = Fields.Field(C3{FT}, cspace),
218217
)
@@ -548,8 +547,6 @@ NVTX.@annotate function set_explicit_precomputed_quantities_part1!(Y, p, t)
548547
end
549548

550549
if turbconv_model isa AbstractEDMF
551-
@. p.precomputed.ᶜgradᵥ_θ_virt =
552-
ᶜgradᵥ(ᶠinterp(TD.virtual_pottemp(thermo_params, ᶜts)))
553550
@. p.precomputed.ᶜgradᵥ_q_tot =
554551
ᶜgradᵥ(ᶠinterp(TD.total_specific_humidity(thermo_params, ᶜts)))
555552
@. p.precomputed.ᶜgradᵥ_θ_liq_ice =
@@ -568,6 +565,15 @@ NVTX.@annotate function set_explicit_precomputed_quantities_part2!(Y, p, t)
568565
(; turbconv_model, moisture_model, cloud_model) = p.atmos
569566
(; call_cloud_diagnostics_per_stage) = p.atmos
570567

568+
# The buoyancy gradient depends on the cloud fraction, and the cloud fraction
569+
# depends on the mixing length, which depends on the buoyancy gradient.
570+
# We break this circular dependency by using cloud fraction from the previous time step in the
571+
# buoyancy gradient calculation. This breaks reproducible restart in general,
572+
# but we support reproducible restart with grid-scale cloud by recalculating the cloud fraction here.
573+
if p.atmos.cloud_model isa GridScaleCloud
574+
set_cloud_fraction!(Y, p, p.atmos.moisture_model, p.atmos.cloud_model)
575+
end
576+
571577
if turbconv_model isa PrognosticEDMFX
572578
set_prognostic_edmf_precomputed_quantities_explicit_closures!(Y, p, t)
573579
set_prognostic_edmf_precomputed_quantities_precipitation!(

src/cache/prognostic_edmf_precomputed_quantities.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,14 +299,15 @@ NVTX.@annotate function set_prognostic_edmf_precomputed_quantities_explicit_clos
299299
)
300300
end
301301

302-
(; ᶜgradᵥ_θ_virt, ᶜgradᵥ_q_tot, ᶜgradᵥ_θ_liq_ice) = p.precomputed
302+
(; ᶜgradᵥ_q_tot, ᶜgradᵥ_θ_liq_ice, cloud_diagnostics_tuple) =
303+
p.precomputed
303304
@. ᶜlinear_buoygrad = buoyancy_gradients( # TODO - do we need to modify buoyancy gradients based on NonEq + 1M tracers?
304305
BuoyGradMean(),
305306
thermo_params,
306307
moisture_model,
307308
ᶜts,
309+
cloud_diagnostics_tuple.cf,
308310
C3,
309-
ᶜgradᵥ_θ_virt,
310311
ᶜgradᵥ_q_tot,
311312
ᶜgradᵥ_θ_liq_ice,
312313
ᶜlg,

src/callbacks/callbacks.jl

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,16 +106,12 @@ function external_driven_single_column!(integrator)
106106
evaluate!(ᶜls_subsidence, wa, t)
107107
end
108108

109-
110-
111109
NVTX.@annotate function cloud_fraction_model_callback!(integrator)
112110
Y = integrator.u
113111
p = integrator.p
114-
(; ᶜts, ᶜgradᵥ_θ_virt, ᶜgradᵥ_q_tot, ᶜgradᵥ_θ_liq_ice) = p.precomputed
112+
(; ᶜts, ᶜgradᵥ_q_tot, ᶜgradᵥ_θ_liq_ice) = p.precomputed
115113
thermo_params = CAP.thermodynamics_params(p.params)
116114
if isnothing(p.atmos.turbconv_model)
117-
@. ᶜgradᵥ_θ_virt =
118-
ᶜgradᵥ(ᶠinterp(TD.virtual_pottemp(thermo_params, ᶜts)))
119115
@. ᶜgradᵥ_q_tot =
120116
ᶜgradᵥ(ᶠinterp(TD.total_specific_humidity(thermo_params, ᶜts)))
121117
@. ᶜgradᵥ_θ_liq_ice =

src/prognostic_equations/eddy_diffusion_closures.jl

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ import ClimaCore.Fields as Fields
1515
# Arguments for the first method (most commonly called):
1616
ts::TD.ThermodynamicState,
1717
::Type{C3}, # Covariant3 vector type, for projecting gradients
18-
∂θv∂z_unsat::AbstractField, # Vertical gradient of virtual potential temperature in unsaturated part
19-
∂qt∂z_sat::AbstractField, # Vertical gradient of total specific humidity in saturated part
20-
∂θli∂z_sat::AbstractField, # Vertical gradient of liquid-ice potential temperature in saturated part
18+
∂qt∂z::AbstractField, # Vertical gradient of total specific humidity
19+
∂θli∂z::AbstractField, # Vertical gradient of liquid-ice potential temperature
2120
local_geometry::Fields.LocalGeometry,
2221
# Argument for the second method (internal use with precomputed EnvBuoyGradVars):
2322
# bg_model::EnvBuoyGradVars
@@ -50,9 +49,8 @@ Arguments:
5049
- `moisture_model`: Moisture model (e.g., `EquilMoistModel`, `NonEquilMoistModel`).
5150
- `ts`: Center-level thermodynamic state of the environment.
5251
- `C3`: The `ClimaCore.Geometry.Covariant3Vector` type, used for projecting input vertical gradients.
53-
- `∂θv∂z_unsat`: Field of vertical gradients of virtual potential temperature in the unsaturated part.
54-
- `∂qt∂z_sat`: Field of vertical gradients of total specific humidity in the saturated part.
55-
- `∂θli∂z_sat`: Field of vertical gradients of liquid-ice potential temperature in the saturated part.
52+
- `∂qt∂z`: Field of vertical gradients of total specific humidity.
53+
- `∂θli∂z`: Field of vertical gradients of liquid-ice potential temperature.
5654
- `local_geometry`: Field of local geometry at cell centers, used for gradient projection.
5755
The second method takes a precomputed `EnvBuoyGradVars` object instead of `ts` and gradient fields.
5856
@@ -66,10 +64,10 @@ function buoyancy_gradients(
6664
thermo_params,
6765
moisture_model,
6866
ts,
67+
cf,
6968
::Type{C3},
70-
∂θv∂z_unsat,
71-
∂qt∂z_sat,
72-
∂θli∂z_sat,
69+
∂qt∂z,
70+
∂θli∂z,
7371
ᶜlg,
7472
) where {C3}
7573
return buoyancy_gradients(
@@ -78,11 +76,11 @@ function buoyancy_gradients(
7876
moisture_model,
7977
EnvBuoyGradVars(
8078
ts,
79+
cf,
8180
projected_vector_buoy_grad_vars(
8281
C3,
83-
∂θv∂z_unsat,
84-
∂qt∂z_sat,
85-
∂θli∂z_sat,
82+
∂qt∂z,
83+
∂θli∂z,
8684
ᶜlg,
8785
),
8886
),
@@ -99,36 +97,36 @@ function buoyancy_gradients(
9997

10098
g = TDP.grav(thermo_params)
10199
Rv_over_Rd = TDP.Rv_over_Rd(thermo_params)
102-
R_d = TDP.R_d(thermo_params)
103100
R_v = TDP.R_v(thermo_params)
104101

105102
ts = bg_model.ts
106-
p = TD.air_pressure(thermo_params, ts)
107-
Π = TD.exner_given_pressure(thermo_params, p)
108-
∂b∂θv = g * (R_d * TD.air_density(thermo_params, ts) / p) * Π
103+
g_over_θv = g / TD.virtual_pottemp(thermo_params, ts)
109104

110-
t_sat = TD.air_temperature(thermo_params, ts)
105+
T = TD.air_temperature(thermo_params, ts)
111106
λ = TD.liquid_fraction(thermo_params, ts)
112107
lh =
113-
λ * TD.latent_heat_vapor(thermo_params, t_sat) +
114-
(1 - λ) * TD.latent_heat_sublim(thermo_params, t_sat)
108+
λ * TD.latent_heat_vapor(thermo_params, T) +
109+
(1 - λ) * TD.latent_heat_sublim(thermo_params, T)
115110
cp_m = TD.cp_m(thermo_params, ts)
116-
qv_sat = TD.vapor_specific_humidity(thermo_params, ts)
117-
qt_sat = TD.total_specific_humidity(thermo_params, ts)
111+
q_sat = TD.q_vap_saturation(thermo_params, ts)
112+
q_tot = TD.total_specific_humidity(thermo_params, ts)
113+
θ = TD.dry_pottemp(thermo_params, ts)
114+
∂b∂θli_unsat = g_over_θv * (1 + (Rv_over_Rd - 1) * q_tot)
115+
∂b∂qt_unsat = g_over_θv * (Rv_over_Rd - 1) * θ
118116
∂b∂θli_sat = (
119-
∂b∂θv *
120-
(1 + Rv_over_Rd * (1 + lh / R_v / t_sat) * qv_sat - qt_sat) /
121-
(1 + lh * lh / cp_m / R_v / t_sat / t_sat * qv_sat)
117+
g_over_θv *
118+
(1 + Rv_over_Rd * (1 + lh / R_v / T) * q_sat - q_tot) /
119+
(1 + lh^2 / cp_m / R_v / T^2 * q_sat)
122120
)
123121
∂b∂qt_sat =
124-
(lh / cp_m / t_sat * ∂b∂θli_sat - ∂b∂θv) *
125-
TD.dry_pottemp(thermo_params, ts)
122+
(lh / cp_m / T * ∂b∂θli_sat - g_over_θv) * θ
126123

127124
∂b∂z = buoyancy_gradient_chain_rule(
128125
ebgc,
129126
bg_model,
130127
thermo_params,
131-
∂b∂θv,
128+
∂b∂θli_unsat,
129+
∂b∂qt_unsat,
132130
∂b∂θli_sat,
133131
∂b∂qt_sat,
134132
)
@@ -140,7 +138,6 @@ end
140138
closure::AbstractEnvBuoyGradClosure,
141139
bg_model::EnvBuoyGradVars,
142140
thermo_params,
143-
∂b∂θv::FT,
144141
∂b∂θli_sat::FT,
145142
∂b∂qt_sat::FT,
146143
) where {FT}
@@ -165,7 +162,6 @@ Arguments:
165162
- `closure`: The environmental buoyancy gradient closure type.
166163
- `bg_model`: Precomputed environmental buoyancy gradient variables (`EnvBuoyGradVars`).
167164
- `thermo_params`: Thermodynamic parameters from `CLIMAParameters`.
168-
- `∂b∂θv`: Partial derivative of buoyancy w.r.t. virtual potential temperature (unsaturated part).
169165
- `∂b∂θli_sat`: Partial derivative of buoyancy w.r.t. liquid-ice potential temperature (saturated part).
170166
- `∂b∂qt_sat`: Partial derivative of buoyancy w.r.t. total specific humidity (saturated part).
171167
@@ -176,18 +172,21 @@ function buoyancy_gradient_chain_rule(
176172
::AbstractEnvBuoyGradClosure,
177173
bg_model::EnvBuoyGradVars,
178174
thermo_params,
179-
∂b∂θv,
175+
∂b∂θli_unsat,
176+
∂b∂qt_unsat,
180177
∂b∂θli_sat,
181178
∂b∂qt_sat,
182179
)
183-
en_cld_frac = ifelse(TD.has_condensate(thermo_params, bg_model.ts), 1, 0)
180+
#en_cld_frac = ifelse(TD.has_condensate(thermo_params, bg_model.ts), 1, 0)
184181

185-
∂b∂z_θl_sat = ∂b∂θli_sat * bg_model.∂θli∂z_sat
186-
∂b∂z_qt_sat = ∂b∂qt_sat * bg_model.∂qt∂z_sat
182+
∂b∂z_θli_unsat = ∂b∂θli_unsat * bg_model.∂θli∂z
183+
∂b∂z_qt_unsat = ∂b∂qt_unsat * bg_model.∂qt∂z
184+
∂b∂z_unsat = ∂b∂z_θli_unsat + ∂b∂z_qt_unsat
185+
∂b∂z_θl_sat = ∂b∂θli_sat * bg_model.∂θli∂z
186+
∂b∂z_qt_sat = ∂b∂qt_sat * bg_model.∂qt∂z
187187
∂b∂z_sat = ∂b∂z_θl_sat + ∂b∂z_qt_sat
188-
∂b∂z_unsat = ∂b∂θv * bg_model.∂θv∂z_unsat
189188

190-
∂b∂z = (1 - en_cld_frac) * ∂b∂z_unsat + en_cld_frac * ∂b∂z_sat
189+
∂b∂z = (1 - bg_model.cf) * ∂b∂z_unsat + bg_model.cf * ∂b∂z_sat
191190

192191
return ∂b∂z
193192
end

src/prognostic_equations/gm_sgs_closures.jl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,18 @@ NVTX.@annotate function compute_gm_mixing_length(Y, p)
6767

6868
ᶜdz = Fields.Δz_field(axes(Y.c))
6969
ᶜlg = Fields.local_geometry_field(Y.c)
70-
(; ᶜts, ᶠu³, ᶜlinear_buoygrad, ᶜstrain_rate_norm) = p.precomputed
70+
(; ᶜts, ᶠu³, ᶜlinear_buoygrad, ᶜstrain_rate_norm, cloud_diagnostics_tuple) =
71+
p.precomputed
7172

7273
@. ᶜlinear_buoygrad = buoyancy_gradients(
7374
BuoyGradMean(),
7475
thermo_params,
7576
p.atmos.moisture_model,
7677
ᶜts,
78+
cloud_diagnostics_tuple.cf,
7779
C3,
78-
p.precomputed.ᶜgradᵥ_θ_virt, # ∂θv∂z_unsat
79-
p.precomputed.ᶜgradᵥ_q_tot, # ∂qt∂z_sat
80-
p.precomputed.ᶜgradᵥ_θ_liq_ice, # ∂θl∂z_sat
80+
p.precomputed.ᶜgradᵥ_q_tot,
81+
p.precomputed.ᶜgradᵥ_θ_liq_ice,
8182
ᶜlg,
8283
)
8384

src/solver/types.jl

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -376,17 +376,18 @@ Variables used in the environmental buoyancy gradient computation.
376376
"""
377377
Base.@kwdef struct EnvBuoyGradVars{FT, TS}
378378
ts::TS
379-
∂θv∂z_unsat::FT
380-
∂qt∂z_sat::FT
381-
∂θli∂z_sat::FT
379+
cf::FT
380+
∂qt∂z::FT
381+
∂θli∂z::FT
382382
end
383383

384384
function EnvBuoyGradVars(
385385
ts::TD.ThermodynamicState,
386-
∂θv∂z_unsat_∂qt∂z_sat_∂θli∂z_sat,
386+
cf,
387+
∂qt∂z_∂θli∂z,
387388
)
388-
(; ∂θv∂z_unsat, ∂qt∂z_sat, ∂θli∂z_sat) =θv∂z_unsat_∂qt∂z_sat_∂θli∂z_sat
389-
return EnvBuoyGradVars(ts, ∂θv∂z_unsat, ∂qt∂z_sat, ∂θli∂z_sat)
389+
(; ∂qt∂z, ∂θli∂z) = ∂qt∂z_∂θli∂z
390+
return EnvBuoyGradVars(ts, cf, ∂qt∂z, ∂θli∂z)
390391
end
391392

392393
Base.eltype(::EnvBuoyGradVars{FT}) where {FT} = FT

src/utils/utilities.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,12 +279,11 @@ The type should correspond to a vector with only one component, i.e., a basis ve
279279
projected_vector_data(::Type{V}, vector, local_geometry) where {V} =
280280
V(vector, local_geometry)[1] / unit_basis_vector_data(V, local_geometry)
281281

282-
function projected_vector_buoy_grad_vars(::Type{V}, v1, v2, v3, lg) where {V}
282+
function projected_vector_buoy_grad_vars(::Type{V}, v1, v2, lg) where {V}
283283
ubvd = unit_basis_vector_data(V, lg)
284284
return (;
285-
∂θv∂z_unsat = V(v1, lg)[1] / ubvd,
286-
∂qt∂z_sat = V(v2, lg)[1] / ubvd,
287-
∂θli∂z_sat = V(v3, lg)[1] / ubvd,
285+
∂qt∂z = V(v1, lg)[1] / ubvd,
286+
∂θli∂z = V(v2, lg)[1] / ubvd,
288287
)
289288
end
290289

test/restart.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,7 @@ else
456456
"output_dir" => joinpath(amip_output_loc, amip_job_id),
457457
"dt_cloud_fraction" => "1secs",
458458
"rad" => "allskywithclear",
459+
"cloud_model" => "grid_scale",
459460
"toml" => [
460461
joinpath(@__DIR__, "../toml/longrun_aquaplanet_diagedmf.toml"),
461462
],

0 commit comments

Comments
 (0)