Skip to content

Commit 9594689

Browse files
committed
wip p3 collisions
1 parent 944d99e commit 9594689

File tree

8 files changed

+211
-10
lines changed

8 files changed

+211
-10
lines changed

src/Common/equation_types.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export Precipitation0M
1818
export Precipitation1M
1919
export Precipitation2M
2020
export PrecipitationP3
21+
export IcePrecipitationP3
22+
export Precipitation2M_P3
2123
export CloudyPrecip
2224

2325
abstract type AbstractStyle end
@@ -59,3 +61,12 @@ struct PrecipitationP3{P3, CH, PT, B} <: AbstractPrecipitationStyle
5961
p3_boundary_condition::B
6062
end
6163
struct CloudyPrecip <: AbstractPrecipitationStyle end
64+
# New P3 structs
65+
struct IcePrecipitationP3{P3, ST} <: AbstractPrecipitationStyle
66+
params::P3
67+
sedimentation::ST
68+
end
69+
struct Precipitation2M_P3{LP, IP} <: AbstractPrecipitationStyle
70+
liq_precip::LP # The rain scheme. For now: Precipitation2M
71+
ice_precip::IP # The ice scheme. For now: IcePrecipitationP3
72+
end

src/Common/helper_functions.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ function get_precipitation_type(
8686
Chen2022 = CMP.Chen2022VelType(FT)
8787
sb2006 = CMP.SB2006(toml_dict)
8888
precip = PrecipitationP3(p3_params, Chen2022, sb2006, boundary)
89+
elseif precipitation_choice == "Precipitation2M_P3"
90+
@assert sedimentation_choice == "Chen2022"
91+
@assert rain_formation_choice == "SB2006"
92+
params = CMP.ParametersP3(toml_dict; slope_law = :constant)
93+
liq_sedimentation = CMP.Chen2022VelTypeRain(toml_dict)
94+
ice_sedimentation = CMP.Chen2022VelType(toml_dict)
95+
liq_precip = Precipitation2M(CMP.SB2006(toml_dict), liq_sedimentation)
96+
ice_precip = IcePrecipitationP3(params, ice_sedimentation)
97+
precip = Precipitation2M_P3(liq_precip, ice_precip)
8998
else
9099
error("Invalid precipitation choice: $precipitation_choice")
91100
end

src/Common/initial_condition.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ function initial_condition_1d(
162162
ρq_ice,
163163
ρq_rai,
164164
ρq_sno,
165+
ρq_rim,
165166
ρq_vap,
166167
q_tot,
167168
q_liq,
@@ -175,6 +176,10 @@ function initial_condition_1d(
175176
N_rai,
176177
N_aer,
177178
zero,
179+
# P3 variables
180+
F_rim = FT(0),
181+
ρ_rim = FT(0),
182+
logλ = FT(0),
178183
)
179184
end
180185

src/Common/ode_utils.jl

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ function initialise_state(::MoistureP3, ::PrecipitationP3, initial_profiles)
4747
:N_liq, :N_rai, :N_ice, :N_aer, :q_vap, :ρq_vap, :q_rai,
4848
)}.(initial_profiles)
4949
end
50+
function initialise_state(::NonEquilibriumMoisture, ::Precipitation2M_P3, initial_profiles)
51+
warm_state = NamedTuple{(:ρq_tot, :ρq_liq, :ρq_rai, :N_liq, :N_rai, :N_aer)}.(initial_profiles)
52+
cold_state = NamedTuple{(:ρq_ice, :N_ice, :ρq_rim, :B_rim)}.(initial_profiles)
53+
tmp = NamedTuple{(:ρq_sno,)}.(initial_profiles) # only needed to use existing `Precipitation2M` code, should always be zero.
54+
return merge.(warm_state, cold_state, tmp)
55+
end
5056
function initialise_state(::CloudyMoisture, ::CloudyPrecip, initial_profiles)
5157
return NamedTuple{(:ρq_vap, :N_aer, :moments)}.(initial_profiles)
5258
end
@@ -115,11 +121,21 @@ function initialise_aux(
115121
velocities = zero_nt(NamedTuple{(:term_vel_rai, :term_vel_sno)})
116122
precip_sources = zero_nt(NamedTuple{(:q_tot, :q_liq, :q_ice, :q_rai, :q_sno)})
117123
activation_sources = nothing
118-
elseif precip isa Precipitation2M
124+
elseif precip isa Precipitation2M || precip isa Precipitation2M_P3
119125
microph_variables = merge.(microph_variables, NamedTuple{(:q_rai, :q_sno, :N_liq, :N_rai, :N_aer)}.(ip))
120126
velocities = zero_nt(NamedTuple{(:term_vel_N_rai, :term_vel_rai)})
121127
precip_sources = zero_nt(NamedTuple{(:q_tot, :q_liq, :q_rai, :N_aer, :N_liq, :N_rai)})
122128
activation_sources = zero_nt(NamedTuple{(:N_aer, :N_liq)})
129+
if precip isa Precipitation2M_P3
130+
# NOTE: `q_sno` from above is not used in the P3 code, but is needed to use existing `Precipitation2M` code.
131+
ice_microph_variables = NamedTuple{(:F_rim, :ρ_rim, :logλ)}.(ip) # variables needed to be precomputed
132+
ice_output_variables = NamedTuple{(:N_ice, :ρq_rim, :B_rim)}.(ip) # variables for netCDF output
133+
microph_variables = merge.(microph_variables, ice_microph_variables, ice_output_variables)
134+
ice_velocities = zero_nt(NamedTuple{(:term_vel_N_ice, :term_vel_q_ice)})
135+
velocities = merge.(velocities, ice_velocities) # precompute ice terminal velocities
136+
ice_precip_sources = zero_nt(NamedTuple{(:q_ice, :q_rim, :N_ice, :B_rim)})
137+
precip_sources = merge.(precip_sources, ice_precip_sources)
138+
end
123139
elseif precip isa PrecipitationP3
124140
microph_variables =
125141
NamedTuple{(

src/Common/tendency.jl

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ end
131131
@. θ_dry = TD.dry_pottemp(thermo_params, T, ρ_dry)
132132
@. θ_liq_ice = TD.liquid_ice_pottemp(thermo_params, ts)
133133
end
134+
@inline function precompute_aux_thermo!(ms::NonEquilibriumMoisture, ps::Precipitation2M_P3, Y, aux)
135+
precompute_aux_thermo!(ms, ps.liq_precip, Y, aux)
136+
# precompute_aux_thermo!(ms, ps.ice_precip, Y, aux) # no additional `IcePrecipitationP3` thermo state
137+
end
134138
function separate_liq_rai(FT, moments, pdists, cloudy_params, ρd)
135139
tmp = CL.ParticleDistributions.get_standard_N_q(pdists, cloudy_params.size_threshold / cloudy_params.norms[2])
136140
moments_like = ntuple(length(moments)) do k
@@ -190,7 +194,7 @@ end
190194
@. term_vel_rai = CM1.terminal_velocity(ps.rain, ps.sedimentation.rain, ρ, q_rai)
191195
@. term_vel_sno = CM1.terminal_velocity(ps.snow, ps.sedimentation.snow, ρ, q_sno)
192196
end
193-
@inline function precompute_aux_precip!(ps::Precipitation2M, Y, aux)
197+
@inline function precompute_aux_precip!(ps::Precipitation2M, Y, aux) # called by `make_rhs_function`
194198

195199
FT = eltype(Y.ρq_rai)
196200
sb2006 = ps.rain_formation
@@ -207,6 +211,42 @@ end
207211
@. term_vel_N_rai = getindex(CM2.rain_terminal_velocity(sb2006, vel_scheme, q_rai, ρ, N_rai), 1)
208212
@. term_vel_rai = getindex(CM2.rain_terminal_velocity(sb2006, vel_scheme, q_rai, ρ, N_rai), 2)
209213
end
214+
@inline function precompute_aux_precip!(ps::IcePrecipitationP3, Y, aux)
215+
# State, `Y`, includes: ρq_ice, ρq_rim, N_ice, B_rim
216+
217+
# update state variables
218+
(; sedimentation, params) = ps
219+
(; ρq_ice, ρq_rim, N_ice, B_rim) = Y
220+
(; ρ) = aux.thermo_variables
221+
(; F_rim, ρ_rim, logλ) = aux.microph_variables
222+
(; term_vel_N_ice, term_vel_q_ice) = aux.velocities
223+
224+
# Calculate derived rime quantities
225+
# @. F_rim = ifelse(Y.ρq_ice < eps(FT), FT(0), Y.ρq_rim / Y.ρq_ice)
226+
# @. ρ_rim = ifelse(Y.B_rim < eps(FT), FT(0), Y.ρq_rim / Y.B_rim)
227+
228+
@. F_rim = ifelse(isnan(ρq_rim / ρq_ice), zero(ρq_rim), ρq_rim / ρq_ice)
229+
@. ρ_rim = ifelse(isnan(ρq_rim / B_rim), zero(ρq_rim), ρq_rim / B_rim)
230+
# Calculate distribution parameters
231+
@. logλ = CMP3.get_distribution_logλ(CMP3.P3State(params, ρq_ice, N_ice, F_rim, ρ_rim))
232+
233+
# Calculate terminal velocities
234+
use_aspect_ratio = true
235+
@. term_vel_N_ice = CMP3.ice_terminal_velocity_number_weighted(
236+
sedimentation, ρ, CMP3.P3State(params, ρq_ice, N_ice, F_rim, ρ_rim), logλ; use_aspect_ratio
237+
)
238+
@. term_vel_q_ice = CMP3.ice_terminal_velocity_mass_weighted(
239+
sedimentation, ρ, CMP3.P3State(params, ρq_ice, N_ice, F_rim, ρ_rim), logλ; use_aspect_ratio
240+
)
241+
# args = (ps.sedimentation, ρ, ps.params, ρq_ice, N_ice, F_rim, ρ_rim, logλ)
242+
# @. term_vel_N_ice = CMP3.ice_terminal_velocity_number_weighted(args...; use_aspect_ratio)
243+
# @. term_vel_q_ice = CMP3.ice_terminal_velocity_mass_weighted(args...; use_aspect_ratio)
244+
245+
end
246+
function precompute_aux_precip!(ps::Precipitation2M_P3, Y, aux)
247+
precompute_aux_precip!(ps.liq_precip, Y, aux)
248+
precompute_aux_precip!(ps.ice_precip, Y, aux)
249+
end
210250
@inline function precompute_aux_precip!(ps::PrecipitationP3, Y, aux)
211251

212252
# update state variables
@@ -373,6 +413,10 @@ end
373413

374414
@. aux.cloud_sources = to_sources(S_q_liq, S_q_ice)
375415
end
416+
@inline function precompute_aux_moisture_sources!(ms::NonEquilibriumMoisture, ps::Precipitation2M_P3, aux)
417+
precompute_aux_moisture_sources!(ms, ps.liq_precip, aux)
418+
# precompute_aux_moisture_sources!(ms, ps.ice_precip, aux) # no additional `IcePrecipitationP3` thermo state
419+
end
376420

377421
@inline function precompute_aux_precip_sources!(ps::AbstractPrecipitationStyle, aux)
378422
error("precompute_aux not implemented for a given $ps")
@@ -646,6 +690,13 @@ end
646690
end
647691
end
648692

693+
@inline function precompute_aux_precip_sources!(ps::IcePrecipitationP3, Y, aux)
694+
695+
# TODO: So far, implemented directly in precip_sources_tendency!
696+
697+
return nothing
698+
end
699+
649700
@inline function precompute_aux_precip_sources!(ps::PrecipitationP3, aux)
650701
# TODO [P3]
651702
return nothing
@@ -736,7 +787,7 @@ end
736787
@inline function cloud_sources_tendency!(::EquilibriumMoisture, ::AbstractPrecipitationStyle, dY, Y, aux, t) end
737788
@inline function cloud_sources_tendency!(ms::NonEquilibriumMoisture, ps::AbstractPrecipitationStyle, dY, Y, aux, t)
738789

739-
precompute_aux_moisture_sources!(ms, ps, aux)
790+
precompute_aux_moisture_sources!(ms, ps, aux) # defined in `Common/tendency.jl`
740791

741792
@. dY.ρq_liq += aux.thermo_variables.ρ * aux.cloud_sources.q_liq
742793
@. dY.ρq_ice += aux.thermo_variables.ρ * aux.cloud_sources.q_ice
@@ -806,6 +857,42 @@ end
806857
@inline function precip_sources_tendency!(ms::MoistureP3, ps::PrecipitationP3, dY, Y, aux, t)
807858
return dY
808859
end
860+
@inline function precip_sources_tendency!(ms::AbstractMoistureStyle, ps::Precipitation2M_P3, dY, Y, aux, t)
861+
precip_sources_tendency!(ms, ps.liq_precip, dY, Y, aux, t)
862+
# TODO [P3]
863+
# precompute_aux_precip_sources!(ps, Y, aux)
864+
865+
#=
866+
function bulk_liquid_ice_collision_sources(
867+
params, logλ, L_ice, F_rim, ρ_rim,
868+
psd_c, psd_r, L_c, N_c, L_r, N_r,
869+
aps, tps, vel, ρₐ, T,
870+
)
871+
=#
872+
(; ρ, ts) = aux.thermo_variables
873+
(; ρq_liq, ρq_rai, ρq_ice, N_liq, N_rai, N_ice) = Y
874+
(; air_params, thermo_params) = aux
875+
(; logλ, F_rim, ρ_rim) = aux.microph_variables
876+
(; pdf_c, pdf_r) = ps.liq_precip.rain_formation
877+
(; ice_precip) = ps
878+
879+
coll_src = @. CMP3.bulk_liquid_ice_collision_sources(
880+
ice_precip.params, logλ, ρq_ice, N_ice, F_rim, ρ_rim,
881+
pdf_c, pdf_r, ρq_liq, N_liq, ρq_rai, N_rai,
882+
air_params, thermo_params, (ice_precip.sedimentation,),
883+
ρ, TD.air_temperature(thermo_params, ts),
884+
)
885+
886+
@. dY.ρq_liq += ρ * coll_src.∂ₜq_c
887+
@. dY.ρq_rai += ρ * coll_src.∂ₜq_r
888+
@. dY.N_liq += coll_src.∂ₜN_c
889+
@. dY.N_rai += coll_src.∂ₜN_r
890+
@. dY.ρq_rim += coll_src.∂ₜL_rim
891+
@. dY.ρq_ice += coll_src.∂ₜL_ice
892+
@. dY.B_rim += coll_src.∂ₜB_rim
893+
894+
return dY
895+
end
809896
@inline function precip_sources_tendency!(ms::CloudyMoisture, ps::CloudyPrecip, dY, Y, aux, t)
810897

811898
precompute_aux_precip_sources!(ps, aux)

src/K1DModel/ode_utils.jl

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,56 @@ end
2828
"""
2929
function make_rhs_function(ms::CO.AbstractMoistureStyle, ps::CO.AbstractPrecipitationStyle)
3030
function rhs!(dY, Y, aux, t)
31-
3231
CO.zero_tendencies!(dY)
3332

33+
# defined in `K1DModel/tendency.jl`
34+
# calc: aux.prescribed_velocity.ρw
3435
precompute_aux_prescribed_velocity!(aux, t)
36+
# defined in `Common/tendency.jl`
37+
# For NonEquilibriumMoisture:
38+
# calc: aux.thermo_variables.{ts, ρ, p, θ_dry, θ_liq_ice}
39+
# calc: aux.microph_variables.{q_tot, q_liq, q_ice}
3540
CO.precompute_aux_thermo!(ms, ps, Y, aux)
36-
CO.precompute_aux_precip!(ps, Y, aux)
37-
38-
precompute_aux_activation!(ps, dY, Y, aux, t)
39-
41+
# defined in `Common/tendency.jl`
42+
# For Precipitation2M:
43+
# calc: aux.microph_variables.{q_rai, q_sno, N_rai, N_liq} <-- NOTE: You can assume `q_sno = ρq_sno = 0`
44+
# calc: aux.velocities.{term_vel_rai, term_vel_N_rai}
45+
# For IcePrecipitationP3:
46+
# calc: aux.microph_variables.{ρq_ice, ρq_rim, N_ice, B_rim} <-- maybe not needed
47+
# calc: aux.velocities.{term_vel_ice, term_vel_N_ice}
48+
CO.precompute_aux_precip!(ps, Y, aux) # <-- calls fn for Precipitation2M
49+
50+
# defined in `K1DModel/tendency.jl`
51+
# calc: aux.activation_sources.{N_aer, N_liq}
52+
precompute_aux_activation!(ps, dY, Y, aux, t) # <-- calls fn for Precipitation2M
53+
54+
# defined in `Common/tendency.jl`
55+
# calls: `precompute_aux_moisture_sources` (defined in `Common/tendency.jl`)
56+
# calc: aux.cloud_sources.{q_liq, q_ice}
57+
# increments: dY.{ρq_liq, ρq_ice} += ρ * aux.cloud_sources.{q_...}
4058
CO.cloud_sources_tendency!(ms, ps, dY, Y, aux, t)
41-
CO.precip_sources_tendency!(ms, ps, dY, Y, aux, t)
59+
# defined in `Common/tendency.jl`
60+
# For Precipitation2M:
61+
# calls: `precompute_aux_precip_sources` (defined in `Common/tendency.jl`)
62+
# calc: aux.precip_sources.{q_tot, q_liq, q_rai, N_liq, N_rai, N_aer}
63+
# increments: dY.{ρq_tot, ρq_rai, ρq_liq, N_liq, N_rai, N_aer}
64+
# += aux.precip_sources.{...}
65+
# and/or += aux.activation_sources.{N_liq, N_aer}
66+
# For Precipitation2M_P3:
67+
# calls: `precompute_aux_precip_sources` (defined in `Common/tendency.jl`)
68+
# TODO: write collisions
69+
CO.precip_sources_tendency!(ms, ps, dY, Y, aux, t) # <-- calls fn for Precipitation2M + write code
4270

4371
for eq_style in [ms, ps]
72+
# defined in `K1DModel/tendency.jl`
73+
# For Precipitation2M:
74+
# increments: dY.{ρq_rai, N_liq, N_rai, N_aer} += ... * aux.velocities.{term_vel_N_rai, term_vel_rai}
75+
# For NonEquilibriumMoisture:
76+
# increments: dY.{ρq_tot, ρq_liq, ρq_ice} += {aux.prescribed_velocity} * {Y.ρq_...}
77+
# For Precipitation2M_P3
78+
# - delegates to `Precipitation2M` (see above) and `IcePrecipitationP3`
79+
# For IcePrecipitationP3:
80+
# increments: dY.{N_ice, B_rim, ρq_rim} += ... * aux.velocities.{term_vel_N_ice, term_vel_q_ice}
4481
advection_tendency!(eq_style, dY, Y, aux, t)
4582
end
4683

src/K1DModel/tendency.jl

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,10 @@ end
176176
end
177177
end
178178

179+
@inline function precompute_aux_activation!(ps::CO.Precipitation2M_P3, dY, Y, aux, t)
180+
precompute_aux_activation!(ps.liq_precip, dY, Y, aux, t)
181+
end
182+
179183
"""
180184
Prescribed momentum flux as a function of time
181185
"""
@@ -404,6 +408,38 @@ end
404408

405409
return dY
406410
end
411+
@inline function advection_tendency!(::CO.IcePrecipitationP3, dY, Y, aux, t)
412+
FT = eltype(Y.ρq_tot)
413+
# Apply advection tendency to N_ice, B_rim, ρq_rim
414+
(; ρw) = aux.prescribed_velocity
415+
(; ρ) = aux.thermo_variables
416+
(; term_vel_N_ice, term_vel_q_ice) = aux.velocities
417+
418+
If = CC.Operators.InterpolateC2F()
419+
wvec = CC.Geometry.WVector
420+
extrapolate = CC.Operators.Extrapolate()
421+
zero_bc = CC.Operators.SetValue(wvec(FT(0)))
422+
423+
∇_N = CC.Operators.DivergenceF2C(bottom = extrapolate, top = zero_bc)
424+
∇_q = CC.Operators.DivergenceF2C(bottom = zero_bc, top = extrapolate)
425+
426+
@. dY.N_ice += -∇_N((ρw / If(ρ) - wvec(If(term_vel_N_ice))) * If(Y.N_ice))
427+
@. dY.B_rim += -∇_q((ρw / If(ρ) - wvec(If(term_vel_q_ice))) * If(Y.B_rim))
428+
@. dY.ρq_rim += -∇_q((ρw / If(ρ) - wvec(If(term_vel_q_ice))) * If(Y.ρq_rim))
429+
430+
fcc = CC.Operators.FluxCorrectionC2C(bottom = extrapolate, top = extrapolate)
431+
@. dY.N_ice += fcc(ρw / If(ρ) - wvec(If(term_vel_N_ice)), Y.N_ice)
432+
@. dY.B_rim += fcc(ρw / If(ρ) - wvec(If(term_vel_q_ice)), Y.B_rim)
433+
@. dY.ρq_rim += fcc(ρw / If(ρ) - wvec(If(term_vel_q_ice)), Y.ρq_rim)
434+
435+
return dY
436+
end
437+
438+
@inline function advection_tendency!(ps::CO.Precipitation2M_P3, dY, Y, aux, t)
439+
advection_tendency!(ps.liq_precip, dY, Y, aux, t)
440+
advection_tendency!(ps.ice_precip, dY, Y, aux, t)
441+
return dY
442+
end
407443

408444
@inline function advection_tendency!(::CO.PrecipitationP3, dY, Y, aux, t)
409445
FT = eltype(Y.ρq_tot)

test/experiments/KiD_driver/run_KiD_simulation.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ function run_KiD_simulation(::Type{FT}, opts) where {FT}
2424

2525
# Decide the output folder name based on options
2626
folder = "Output_$(moisture_choice)_$(precipitation_choice)"
27-
if precipitation_choice in ["Precipitation1M", "Precipitation2M"]
27+
if precipitation_choice in ["Precipitation1M", "Precipitation2M", "Precipitation2M_P3"]
2828
folder *= "_$(rain_formation_choice)"
2929
sedimentation_choice == "Chen2022" && (folder *= "_Chen2022")
3030
elseif precipitation_choice == "CloudyPrecip"

0 commit comments

Comments
 (0)