Skip to content

Commit 87618d5

Browse files
authored
Merge pull request #611 from CliMA/aj/delete_pp_where_possible
Wip on deleting PP from microphysics interface
2 parents b65c4c5 + b8fbe43 commit 87618d5

13 files changed

+125
-179
lines changed

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "CloudMicrophysics"
22
uuid = "6a9e3e04-43cd-43ba-94b9-e8782df3c71b"
33
authors = ["Climate Modeling Alliance"]
4-
version = "0.25.0"
4+
version = "0.26.0"
55

66
[deps]
77
ClimaParams = "5c42b081-d73a-476f-9059-fd94b934656c"
@@ -32,5 +32,5 @@ MLJ = "0.20"
3232
QuadGK = "2.9"
3333
RootSolvers = "0.3, 0.4"
3434
SpecialFunctions = "1, 2"
35-
Thermodynamics = "0.12.13"
35+
Thermodynamics = "0.12.14"
3636
julia = "1.6"

docs/src/plots/Microphysics1M_plots.jl

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,9 @@ MK.set_theme!(MK.theme_minimal())
6464

6565
# autoconversion rate figure
6666
T = 273.15
67-
q_range = TDI.PP.(q_tot, 0.0, q_ice_range)
6867
fig = MK.Figure()
6968
ax = MK.Axis(fig[1, 1]; xlabel = "q_liq or q_ice [g/kg]", ylabel = "autoconversion rate [1/s]", limits)
70-
q_ice_to_q_sno_rate = T -> CM1.conv_q_ice_to_q_sno.(ice, aps, tps, q_range, q_rai, q_sno, ρ_air, T)
69+
q_ice_to_q_sno_rate = T -> CM1.conv_q_ice_to_q_sno.(ice, aps, tps, q_tot, FT(0), q_ice_range, q_rai, q_sno, ρ_air, T)
7170
MK.lines!(q_liq_range * 1e3, CM1.conv_q_liq_to_q_rai.(rain.acnv1M, q_liq_range), label = "Rain")
7271
MK.lines!(q_ice_range * 1e3, q_ice_to_q_sno_rate(T - 5), label = "Snow T = −5°C")
7372
MK.lines!(q_ice_range * 1e3, q_ice_to_q_sno_rate(T - 10), label = "Snow T = −10°C")
@@ -144,15 +143,27 @@ q_vap = 0.15 * q_sat
144143
q_ice = 0.0
145144
q_liq = q_tot - q_vap - q_ice
146145
q_sno = 0.0
147-
q = TDI.PP(q_tot, q_liq, q_ice)
148146
R = TDI.Rₘ(tps, q_tot, q_liq, q_ice)
149147
ρ = p / R / T
150148

151149
fig = MK.Figure()
152150
ax = MK.Axis(fig[1, 1]; xlabel = "q_rain [g/kg]", ylabel = "rain evaporation rate [1/s]")
153151
MK.xlims!(ax, 0, q_max * 1e3)
154152
MK.lines!(
155-
q_rain_range * 1e3, CM1.evaporation_sublimation.(rain, Blk1MVel.rain, aps, tps, Ref(q), q_rain_range, q_sno, ρ, T),
153+
q_rain_range * 1e3,
154+
CM1.evaporation_sublimation.(
155+
rain,
156+
Blk1MVel.rain,
157+
aps,
158+
tps,
159+
q_tot,
160+
q_liq .- q_rain_range,
161+
q_ice,
162+
q_rain_range,
163+
q_sno,
164+
ρ,
165+
T,
166+
),
156167
label = "ClimateMachine",
157168
)
158169
MK.lines!(q_rain_range * 1e3, rain_evap_empirical.(tps, q_rain_range, q_tot, q_liq, T, p, ρ), label = "empirical")
@@ -173,12 +184,25 @@ q_snow_range = range(1e-8, stop = 5e-3, length = 100)
173184
q_tot = 15e-3
174185
q_vap = 0.15 * q_sat
175186
q_liq = 0.0
187+
q_lcl = 0.0
176188
q_ice = q_tot - q_vap - q_liq
177189
q_rai = 0.0
178-
q = TDI.PP(q_tot, q_liq, q_ice)
179190
R = TDI.Rₘ(tps, q_tot, q_liq, q_ice)
180191
ρ = p / R / T
181-
rate = CM1.evaporation_sublimation.(snow, Blk1MVel.snow, aps, tps, Ref(q), q_rai, q_snow_range, ρ, T)
192+
rate =
193+
CM1.evaporation_sublimation.(
194+
snow,
195+
Blk1MVel.snow,
196+
aps,
197+
tps,
198+
q_tot,
199+
q_lcl,
200+
q_ice .- q_snow_range,
201+
q_rai,
202+
q_snow_range,
203+
ρ,
204+
T,
205+
)
182206
MK.lines!(q_snow_range * 1e3, rate, label = "T < 0°C")
183207

184208
# example values 2
@@ -190,12 +214,25 @@ q_snow_range = range(1e-8, stop = 5e-3, length = 100)
190214
q_tot = 15e-3
191215
q_vap = 0.15 * q_sat
192216
q_liq = 0.0
217+
q_lcl = 0.0
193218
q_ice = q_tot - q_vap - q_liq
194219
q_rai = 0.0
195-
q = TDI.PP(q_tot, q_liq, q_ice)
196220
R = TDI.Rₘ(tps, q_tot, q_liq, q_ice)
197221
ρ = p / R / T
198-
rate = CM1.evaporation_sublimation.(snow, Blk1MVel.snow, aps, tps, Ref(q), q_rai, q_snow_range, ρ, T)
222+
rate =
223+
CM1.evaporation_sublimation.(
224+
snow,
225+
Blk1MVel.snow,
226+
aps,
227+
tps,
228+
q_tot,
229+
q_lcl,
230+
q_ice .- q_snow_range,
231+
q_rai,
232+
q_snow_range,
233+
ρ,
234+
T,
235+
)
199236
MK.lines!(q_snow_range * 1e3, rate, label = "T > 0°C")
200237

201238
MK.axislegend(ax; position = :rt)

src/Microphysics0M.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ module Microphysics0M
1111

1212
import CloudMicrophysics.Parameters as CMP
1313

14-
# Only needed for the wrapper for calling remove_precipitation with
15-
# TD.PhasePartition as an argument. Can be dropped if we drop this pattern.
14+
# Needed for the wrapper for calling the 0-moment remove_precipitation
15+
# with TD.PhasePartition in ClimaAtmos
1616
import CloudMicrophysics.ThermodynamicsInterface as TDI
1717

1818
export remove_precipitation
@@ -47,6 +47,9 @@ remove_precipitation(
4747
###
4848
### Wrappers for calling with TD.PhasePartition
4949
###
50+
### For now leaving the PhasePartition wrapper because I'm not sure how to get
51+
### rid of equilibrium thermo state in the Atmos model.
52+
###
5053
remove_precipitation(params::CMP.Parameters0M, q::TDI.TD.PhasePartition) =
5154
remove_precipitation(params, q.liq, q.ice)
5255
remove_precipitation(params::CMP.Parameters0M, q::TDI.TD.PhasePartition, q_vap_sat) =

src/Microphysics1M.jl

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -646,24 +646,4 @@ function snow_melt(
646646
return snow_melt_rate
647647
end
648648

649-
###
650-
### Wrappers for calling with TD.PhasePartition
651-
###
652-
653-
conv_q_ice_to_q_sno(
654-
ice_params::CMP.CloudIce, aps::CMP.AirProperties, tps::TDI.PS,
655-
q::TDI.TD.PhasePartition, q_rai, q_sno, ρ, T,
656-
) = conv_q_ice_to_q_sno(ice_params, aps, tps, TDI.q_(q, q_rai, q_sno)..., q_rai, q_sno, ρ, T)
657-
658-
evaporation_sublimation(
659-
rain_params::CMP.Rain, vel::CMP.Blk1MVelTypeRain, aps::CMP.AirProperties, tps::TDI.PS,
660-
q::TDI.TD.PhasePartition, q_rai, q_sno, ρ, T,
661-
) = evaporation_sublimation(rain_params, vel, aps, tps, TDI.q_(q, q_rai, q_sno)..., q_rai, q_sno, ρ, T)
662-
663-
evaporation_sublimation(
664-
snow_params::CMP.Snow, vel::CMP.Blk1MVelTypeSnow, aps::CMP.AirProperties, tps::TDI.PS,
665-
q::TDI.TD.PhasePartition, q_rai, q_sno, ρ, T,
666-
) = evaporation_sublimation(snow_params, vel, aps, tps, TDI.q_(q, q_rai, q_sno)..., q_rai, q_sno, ρ, T)
667-
668-
669649
end #module Microphysics1M.jl

src/Microphysics2M.jl

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -932,14 +932,4 @@ function accretion((; accr)::CMP.TC1980{FT}, q_liq, q_rai) where {FT}
932932
return A * q_liq * q_rai
933933
end
934934

935-
###
936-
### Wrappers for calling with TD.PhasePartition
937-
###
938-
939-
rain_evaporation(
940-
sb_params::CMP.SB2006, air_params::CMP.AirProperties, tps::TDI.PS,
941-
q::TDI.TD.PhasePartition,
942-
q_rai, q_sno, ρ, N_rai, T,
943-
) = rain_evaporation(sb_params, air_params, tps, q.tot, q.liq, q.ice, q_rai, q_sno, ρ, N_rai, T)
944-
945935
end # module

src/MicrophysicsNonEq.jl

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -170,18 +170,4 @@ function terminal_velocity(
170170
return fall_w
171171
end
172172

173-
###
174-
### Wrappers fro calling with TD.PhasePartition
175-
###
176-
conv_q_vap_to_q_liq_ice_MM2015(
177-
prs::CMP.CloudLiquid, tps::TDI.PS, q::TDI.TD.PhasePartition, q_rai, q_sno, ρ, T,
178-
#) = conv_q_vap_to_q_liq_ice_MM2015(prs, tps, TDI.q_(q, q_rai, q_sno)..., ρ, T)
179-
) = conv_q_vap_to_q_liq_ice_MM2015(prs, tps, q.tot, q.liq - q_rai, q.ice - q_sno, q_rai, q_sno..., ρ, T)
180-
181-
conv_q_vap_to_q_liq_ice_MM2015(
182-
prs::CMP.CloudIce, tps::TDI.PS, q::TDI.TD.PhasePartition, q_rai, q_sno, ρ, T,
183-
) = conv_q_vap_to_q_liq_ice_MM2015(prs, tps, q.tot, q.liq - q_rai, q.ice - q_sno, q_rai, q_sno..., ρ, T)
184-
#) = conv_q_vap_to_q_liq_ice_MM2015(prs, tps, TDI.q_(q, q_rai, q_sno)..., ρ, T)
185-
186-
187173
end #module MicrophysicsNonEq.jl

src/ThermodynamicsInterface.jl

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,29 @@ module ThermodynamicsInterface
22

33
import Thermodynamics as TD
44
const PS = TD.Parameters.ThermodynamicsParameters
5-
const PP = TD.PhasePartition
6-
7-
8-
# Constants
5+
const PP = TD.PhasePartition # Still used in Atmos EquilMoist model rain formation
96

7+
###
8+
### Constants
9+
###
1010
grav(tps::PS) = TD.Parameters.grav(tps) # Needed in parcel model
1111

12-
13-
# Constants for moist air
14-
1512
Rᵥ(tps::PS) = TD.Parameters.R_v(tps)
1613
Rd(tps::PS) = TD.Parameters.R_d(tps)
1714
Rd_over_Rv(tps::PS) = 1 / TD.Parameters.molmass_ratio(tps)
18-
# Gas constant for mois air
19-
Rₘ(tps::PS, qₜ, qₗ, qᵢ) = TD.gas_constant_air(tps, PP(qₜ, qₗ, qᵢ)) #TODO - PP
15+
16+
# Gas constant for moist air
17+
Rₘ(tps::PS, qₜ, qₗ, qᵢ) = TD.gas_constant_air(tps, qₜ, qₗ, qᵢ)
2018

2119
Lᵥ(tps::PS, T) = TD.latent_heat_vapor(tps, T)
2220
Lₛ(tps::PS, T) = TD.latent_heat_sublim(tps, T)
2321
Lf(tps::PS, T) = TD.latent_heat_fusion(tps, T)
2422

2523
cpₘ(tps::PS, qₜ, qₗ, qᵢ) = TD.cp_m(tps, qₜ, qₗ, qᵢ)
2624

27-
# Supersaturations
28-
29-
saturation_vapor_pressure_over_liquid(tps::PS, T) =
30-
TD.saturation_vapor_pressure(tps, T, TD.Liquid())
31-
saturation_vapor_pressure_over_ice(tps::PS, T) =
32-
TD.saturation_vapor_pressure(tps, T, TD.Ice())
33-
34-
# (only used in tests)
35-
saturation_vapor_specific_content_over_liquid(tps::PS, T, ρ) =
36-
TD.q_vap_saturation_generic(tps, T, ρ, TD.Liquid())
37-
saturation_vapor_specific_content_over_ice(tps::PS, T, ρ) =
38-
TD.q_vap_saturation_generic(tps, T, ρ, TD.Ice())
39-
40-
supersaturation_over_liquid(tps::PS, qₜ, qₗ, qᵢ, ρ, T) =
41-
TD.supersaturation(tps, PP(qₜ, qₗ, qᵢ), ρ, T, TD.Liquid()) # TODO - PP
42-
supersaturation_over_ice(tps::PS, qₜ, qₗ, qᵢ, ρ, T) =
43-
TD.supersaturation(tps, PP(qₜ, qₗ, qᵢ), ρ, T, TD.Ice()) # TODO - PP
44-
45-
46-
# Utility functions
25+
###
26+
### Utility functions
27+
###
4728

4829
# Get vapor specific content from total water, total liquid water and total ice
4930
# water specific contents.
@@ -53,17 +34,41 @@ q_vap(q_tot, q_liq, q_ice) = q_tot - q_liq - q_ice
5334
q_vap(q_tot, q_liq, q_ice, q_rai, q_sno) = q_tot - q_liq - q_ice - q_rai - q_sno
5435

5536
# Get specific content from partial pressure
56-
p2q(tps::PS, T, ρ, p) = TD.q_vap_saturation_from_density(tps, T, ρ, p)
37+
p2q(tps::PS, T, ρ, pᵥ) = TD.q_vap_saturation_from_density(tps, T, ρ, pᵥ)
5738

39+
# Get partial pressure from specific content
40+
q2p(tps::PS, T, ρ, qᵥ) = qᵥ * ρ * Rᵥ(tps) * T
5841

5942
# Get air density from temperature, pressure and water content
6043
# (only used in tests)
6144
air_density(tps::PS, T, p, q_tot, q_liq, q_ice) =
6245
TD.air_density(tps, T, p, PP(q_tot, q_liq, q_ice))
6346

64-
# Get a tuple containing total water, cloud liquid water and cloud ice specific
65-
# contents from TD.PhasePartition and rain and snow specific contents.
66-
# Assumes that q::PhasePartition = (q_tot, q_cloud_liq + q_rai, q_cloud_ice + q_sno)
67-
q_(q::PP, q_rai, q_sno) = (q.tot, q.liq - q_rai, q.ice - q_sno)
47+
###
48+
### Supersaturations
49+
###
50+
saturation_vapor_pressure_over_liquid(tps::PS, T) =
51+
TD.saturation_vapor_pressure(tps, T, TD.Liquid())
52+
saturation_vapor_pressure_over_ice(tps::PS, T) =
53+
TD.saturation_vapor_pressure(tps, T, TD.Ice())
54+
55+
# (only used in tests)
56+
saturation_vapor_specific_content_over_liquid(tps::PS, T, ρ) =
57+
TD.q_vap_saturation_generic(tps, T, ρ, TD.Liquid())
58+
saturation_vapor_specific_content_over_ice(tps::PS, T, ρ) =
59+
TD.q_vap_saturation_generic(tps, T, ρ, TD.Ice())
60+
61+
function supersaturation_over_liquid(tps::PS, qₜ, qₗ, qᵢ, ρ, T)
62+
pᵥ_sat = saturation_vapor_pressure_over_liquid(tps, T)
63+
qᵥ = q_vap(qₜ, qₗ, qᵢ)
64+
pᵥ = q2p(tps, T, ρ, qᵥ)
65+
return pᵥ / pᵥ_sat - 1
66+
end
67+
function supersaturation_over_ice(tps::PS, qₜ, qₗ, qᵢ, ρ, T)
68+
pᵥ_sat = saturation_vapor_pressure_over_ice(tps, T)
69+
qᵥ = q_vap(qₜ, qₗ, qᵢ)
70+
pᵥ = q2p(tps, T, ρ, qᵥ)
71+
return pᵥ / pᵥ_sat - 1
72+
end
6873

6974
end

test/aerosol_activation_emulators.jl

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,9 @@ function test_emulator(
300300
w = FT(0.5) # vertical velocity m/s
301301
p_vs = TDI.saturation_vapor_pressure_over_liquid(tps, T)
302302
q_vs = 1 / (1 - 1 / TDI.Rd_over_Rv(tps) * (p_vs - p) / p_vs)
303-
q = TDI.TD.PhasePartition(q_vs)
303+
q_tot = q_vs
304+
q_liq = FT(0)
305+
q_ice = FT(0)
304306

305307
# Aerosol size distribution
306308
salt = CMP.Seasalt(FT)
@@ -323,14 +325,14 @@ function test_emulator(
323325
machine_name = machine_name,
324326
)
325327

326-
TT.@test AA.N_activated_per_mode(mach, ap, ad, aip, tps, T, p, w, q)[1]
327-
AA.N_activated_per_mode(ap, ad, aip, tps, T, p, w, q)[1] rtol =
328+
TT.@test AA.N_activated_per_mode(mach, ap, ad, aip, tps, T, p, w, q_tot, q_liq, q_ice)[1]
329+
AA.N_activated_per_mode(ap, ad, aip, tps, T, p, w, q_tot, q_liq, q_ice)[1] rtol =
328330
rtols[1]
329-
TT.@test AA.N_activated_per_mode(mach, ap, ad, aip, tps, T, p, w, q)[2]
330-
AA.N_activated_per_mode(ap, ad, aip, tps, T, p, w, q)[2] rtol =
331+
TT.@test AA.N_activated_per_mode(mach, ap, ad, aip, tps, T, p, w, q_tot, q_liq, q_ice)[2]
332+
AA.N_activated_per_mode(ap, ad, aip, tps, T, p, w, q_tot, q_liq, q_ice)[2] rtol =
331333
rtols[2]
332-
TT.@test AA.total_N_activated(mach, ap, ad, aip, tps, T, p, w, q)
333-
AA.total_N_activated(ap, ad, aip, tps, T, p, w, q) rtol = rtols[2]
334+
TT.@test AA.total_N_activated(mach, ap, ad, aip, tps, T, p, w, q_tot, q_liq, q_ice)
335+
AA.total_N_activated(ap, ad, aip, tps, T, p, w, q_tot, q_liq, q_ice) rtol = rtols[2]
334336

335337
end
336338

test/gpu_tests.jl

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,6 @@ end
117117

118118
@inbounds begin
119119
output[1, i] = CMN.conv_q_vap_to_q_liq_ice_MM2015(
120-
liquid,
121-
tps,
122-
TDI.TD.PhasePartition(qᵥ_sl[i]),
123-
FT(0),
124-
FT(0),
125-
ρ[i],
126-
T[i],
127-
)
128-
output[2, i] = CMN.conv_q_vap_to_q_liq_ice_MM2015(
129120
liquid,
130121
tps,
131122
qᵥ_sl[i],
@@ -136,7 +127,7 @@ end
136127
ρ[i],
137128
T[i],
138129
)
139-
output[3, i] = CMN.conv_q_vap_to_q_liq_ice(ice, qᵢ_s[i], qᵢ[i])
130+
output[2, i] = CMN.conv_q_vap_to_q_liq_ice(ice, qᵢ_s[i], qᵢ[i])
140131
end
141132
end
142133

@@ -343,7 +334,6 @@ end
343334
i = @index(Group, Linear)
344335

345336
@inbounds begin
346-
q = TDI.TD.PhasePartition(FT(qt[i]), FT(ql[i]), FT(0))
347337

348338
output[1, i] =
349339
CM2.autoconversion_and_liquid_self_collection(
@@ -857,7 +847,7 @@ function test_gpu(FT)
857847
end
858848

859849
TT.@testset "non-equilibrium microphysics kernels" begin
860-
dims = (3, 1)
850+
dims = (2, 1)
861851
(; output, ndrange) = setup_output(dims, FT)
862852

863853
ρ = ArrayType([FT(0.8)])
@@ -871,8 +861,7 @@ function test_gpu(FT)
871861

872862
# test that nonequilibrium cloud formation is callable and returns a reasonable value
873863
TT.@test Array(output)[1] FT(3.763783850665844e-5)
874-
TT.@test Array(output)[2] FT(3.763783850665844e-5)
875-
TT.@test Array(output)[3] FT(-1e-4)
864+
TT.@test Array(output)[2] FT(-1e-4)
876865
end
877866

878867
TT.@testset "Chen 2022 terminal velocity kernels" begin

0 commit comments

Comments
 (0)