Skip to content

Commit 329d1a1

Browse files
anastasia-popovatrontrytel
authored andcommitted
Add terminal velocities to P3 scheme
1 parent 5da62fb commit 329d1a1

9 files changed

+902
-153
lines changed

Project.toml

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ version = "0.18.0"
77
ClimaParams = "5c42b081-d73a-476f-9059-fd94b934656c"
88
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
99
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
10+
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
1011
RootSolvers = "7181ea78-2dcb-4de3-ab41-2b8ab5a31e74"
1112
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
1213
Thermodynamics = "b60c26fb-14c3-4610-9d3e-2d17fe7ff00c"
@@ -29,6 +30,7 @@ DocStringExtensions = "0.8, 0.9"
2930
EnsembleKalmanProcesses = "1.1.5"
3031
ForwardDiff = "0.10"
3132
MLJ = "0.20"
33+
QuadGK = "2.9.4"
3234
RootSolvers = "0.3, 0.4"
3335
SpecialFunctions = "1, 2"
3436
Thermodynamics = "0.12.4"

docs/Project.toml

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244"
99
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
1010
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
1111
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
12+
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
1213
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1314
RootSolvers = "7181ea78-2dcb-4de3-ab41-2b8ab5a31e74"
1415
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"

docs/src/API.md

-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ MicrophysicsFlexible.weighted_vt
6868
```@docs
6969
P3Scheme
7070
P3Scheme.thresholds
71-
P3Scheme.p3_mass
7271
P3Scheme.distribution_parameter_solver
7372
```
7473

docs/src/plots/P3SchemePlots.jl

+58-14
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,54 @@ FT = Float64
99
const PSP3 = CMP.ParametersP3
1010
p3 = CMP.ParametersP3(FT)
1111

12+
"""
13+
mass_(p3, D, ρ, F_r)
14+
15+
- p3 - a struct with P3 scheme parameters
16+
- D - maximum particle dimension [m]
17+
- ρ - bulk ice density (ρ_i for small ice, ρ_g for graupel) [kg/m3]
18+
- F_r - rime mass fraction [q_rim/q_i]
19+
20+
Returns mass as a function of size for differen particle regimes [kg]
21+
"""
22+
# for spherical ice (small ice or completely rimed ice)
23+
mass_s(D::FT, ρ::FT) where {FT <: Real} = FT(π) / 6 * ρ * D^3
24+
# for large nonspherical ice (used for unrimed and dense types)
25+
mass_nl(p3::PSP3, D::FT) where {FT <: Real} = P3.α_va_si(p3) * D^p3.β_va
26+
# for partially rimed ice
27+
mass_r(p3::PSP3, D::FT, F_r::FT) where {FT <: Real} =
28+
P3.α_va_si(p3) / (1 - F_r) * D^p3.β_va
29+
30+
"""
31+
p3_mass(p3, D, F_r, th)
32+
33+
- p3 - a struct with P3 scheme parameters
34+
- D - maximum particle dimension
35+
- F_r - rime mass fraction (q_rim/q_i)
36+
- th - P3Scheme nonlinear solve output tuple (D_cr, D_gr, ρ_g, ρ_d)
37+
38+
Returns mass(D) regime, used to create figures for the docs page.
39+
"""
40+
function p3_mass(
41+
p3::PSP3,
42+
D::FT,
43+
F_r::FT,
44+
th = (; D_cr = FT(0), D_gr = FT(0), ρ_g = FT(0), ρ_d = FT(0)),
45+
) where {FT <: Real}
46+
D_th = P3.D_th_helper(p3)
47+
if D_th > D
48+
return mass_s(D, p3.ρ_i) # small spherical ice
49+
elseif F_r == 0
50+
return mass_nl(p3, D) # large nonspherical unrimed ice
51+
elseif th.D_gr > D >= D_th
52+
return mass_nl(p3, D) # dense nonspherical ice
53+
elseif th.D_cr > D >= th.D_gr
54+
return mass_s(D, th.ρ_g) # graupel
55+
elseif D >= th.D_cr
56+
return mass_r(p3, D, F_r) # partially rimed ice
57+
end
58+
end
59+
1260
"""
1361
A_(p3, D)
1462
@@ -43,17 +91,13 @@ function area(
4391
# Area regime:
4492
if P3.D_th_helper(p3) > D
4593
return A_s(D) # small spherical ice
46-
end
47-
if F_r == 0
94+
elseif F_r == 0
4895
return A_ns(p3, D) # large nonspherical unrimed ice
49-
end
50-
if th.D_gr > D >= P3.D_th_helper(p3)
96+
elseif th.D_gr > D >= P3.D_th_helper(p3)
5197
return A_ns(p3, D) # dense nonspherical ice
52-
end
53-
if th.D_cr > D >= th.D_gr
98+
elseif th.D_cr > D >= th.D_gr
5499
return A_s(D) # graupel
55-
end
56-
if D >= th.D_cr
100+
elseif D >= th.D_cr
57101
return A_r(p3, F_r, D) # partially rimed ice
58102
end
59103

@@ -99,9 +143,9 @@ function p3_relations_plot()
99143
sol4_5 = P3.thresholds(p3, 400.0, 0.5)
100144
sol4_8 = P3.thresholds(p3, 400.0, 0.8)
101145
# m(D)
102-
fig1_0 = CMK.lines!(ax1, D_range * 1e3, [P3.p3_mass(p3, D, 0.0 ) for D in D_range], color = cl[1], linewidth = lw)
103-
fig1_5 = CMK.lines!(ax1, D_range * 1e3, [P3.p3_mass(p3, D, 0.5, sol4_5) for D in D_range], color = cl[2], linewidth = lw)
104-
fig1_8 = CMK.lines!(ax1, D_range * 1e3, [P3.p3_mass(p3, D, 0.8, sol4_8) for D in D_range], color = cl[3], linewidth = lw)
146+
fig1_0 = CMK.lines!(ax1, D_range * 1e3, [p3_mass(p3, D, 0.0 ) for D in D_range], color = cl[1], linewidth = lw)
147+
fig1_5 = CMK.lines!(ax1, D_range * 1e3, [p3_mass(p3, D, 0.5, sol4_5) for D in D_range], color = cl[2], linewidth = lw)
148+
fig1_8 = CMK.lines!(ax1, D_range * 1e3, [p3_mass(p3, D, 0.8, sol4_8) for D in D_range], color = cl[3], linewidth = lw)
105149
# a(D)
106150
fig2_0 = CMK.lines!(ax2, D_range * 1e3, [area(p3, D, 0.0 ) for D in D_range], color = cl[1], linewidth = lw)
107151
fig2_5 = CMK.lines!(ax2, D_range * 1e3, [area(p3, D, 0.5, sol4_5) for D in D_range], color = cl[2], linewidth = lw)
@@ -120,9 +164,9 @@ function p3_relations_plot()
120164
sol_4 = P3.thresholds(p3, 400.0, 0.95)
121165
sol_8 = P3.thresholds(p3, 800.0, 0.95)
122166
# m(D)
123-
fig3_200 = CMK.lines!(ax3, D_range * 1e3, [P3.p3_mass(p3, D, 0.95, sol_2) for D in D_range], color = cl[1], linewidth = lw)
124-
fig3_400 = CMK.lines!(ax3, D_range * 1e3, [P3.p3_mass(p3, D, 0.95, sol_4) for D in D_range], color = cl[2], linewidth = lw)
125-
fig3_800 = CMK.lines!(ax3, D_range * 1e3, [P3.p3_mass(p3, D, 0.95, sol_8) for D in D_range], color = cl[3], linewidth = lw)
167+
fig3_200 = CMK.lines!(ax3, D_range * 1e3, [p3_mass(p3, D, 0.95, sol_2) for D in D_range], color = cl[1], linewidth = lw)
168+
fig3_400 = CMK.lines!(ax3, D_range * 1e3, [p3_mass(p3, D, 0.95, sol_4) for D in D_range], color = cl[2], linewidth = lw)
169+
fig3_800 = CMK.lines!(ax3, D_range * 1e3, [p3_mass(p3, D, 0.95, sol_8) for D in D_range], color = cl[3], linewidth = lw)
126170
# a(D)
127171
fig3_200 = CMK.lines!(ax4, D_range * 1e3, [area(p3, D, 0.5, sol_2) for D in D_range], color = cl[1], linewidth = lw)
128172
fig3_400 = CMK.lines!(ax4, D_range * 1e3, [area(p3, D, 0.5, sol_4) for D in D_range], color = cl[2], linewidth = lw)
+255
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
import CLIMAParameters
2+
import CloudMicrophysics as CM
3+
import CloudMicrophysics.P3Scheme as P3
4+
import CloudMicrophysics.Parameters as CMP
5+
import CairoMakie as Plt
6+
7+
const PSP3 = CMP.ParametersP3
8+
9+
FT = Float64
10+
11+
p3 = CMP.ParametersP3(FT)
12+
13+
function get_values(
14+
p3::PSP3,
15+
Chen2022::CMP.Chen2022VelTypeSnowIce,
16+
q::FT,
17+
N::FT,
18+
ρ_a::FT,
19+
x_resolution::Int,
20+
y_resolution::Int,
21+
) where {FT}
22+
F_rs = range(FT(0), stop = FT(1 - eps(FT)), length = x_resolution)
23+
ρ_rs = range(FT(25), stop = FT(975), length = y_resolution)
24+
25+
V_m = zeros(x_resolution, y_resolution)
26+
D_m = zeros(x_resolution, y_resolution)
27+
28+
for i in 1:x_resolution
29+
for j in 1:y_resolution
30+
F_r = F_rs[i]
31+
ρ_r = ρ_rs[j]
32+
33+
V_m[i, j] =
34+
P3.terminal_velocity_mass(p3, Chen2022, q, N, ρ_r, F_r, ρ_a)
35+
# get D_m in mm for plots
36+
D_m[i, j] = 1e3 * P3.D_m(p3, q, N, ρ_r, F_r)
37+
end
38+
end
39+
return (; F_rs, ρ_rs, V_m, D_m)
40+
end
41+
42+
function figure_2()
43+
Chen2022 = CMP.Chen2022VelType(FT)
44+
# density of air in kg/m^3
45+
ρ_a = FT(1.2) #FT(1.293)
46+
47+
f = Plt.Figure()
48+
xres = 100
49+
yres = 100
50+
min = FT(0)
51+
max = FT(10)
52+
53+
# small D_m
54+
q_s = FT(0.0008)
55+
N_s = FT(1e6)
56+
57+
# medium D_m
58+
q_m = FT(0.22)
59+
N_m = FT(1e6)
60+
61+
# large D_m
62+
q_l = FT(0.7)
63+
N_l = FT(1e6)
64+
65+
# get V_m and D_m
66+
(F_rs, ρ_rs, V_ms, D_ms) =
67+
get_values(p3, Chen2022.snow_ice, q_s, N_s, ρ_a, xres, yres)
68+
(F_rm, ρ_rm, V_mm, D_mm) =
69+
get_values(p3, Chen2022.snow_ice, q_m, N_m, ρ_a, xres, yres)
70+
(F_rl, ρ_rl, V_ml, D_ml) =
71+
get_values(p3, Chen2022.snow_ice, q_l, N_l, ρ_a, xres, yres)
72+
73+
ax1 = Plt.Axis(
74+
f[1, 1],
75+
xlabel = "F_r",
76+
ylabel = "ρ_r",
77+
title = "Small Dₘ",
78+
width = 350,
79+
height = 350,
80+
limits = (0, 1.0, 25, 975),
81+
xticks = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0],
82+
yticks = [200, 400, 600, 800],
83+
)
84+
85+
Plt.contourf!(
86+
F_rs,
87+
ρ_rs,
88+
V_ms,
89+
colormap = Plt.reverse(Plt.cgrad(:Spectral)),
90+
)
91+
Plt.contour!(F_rs, ρ_rs, D_ms, color = :black, labels = true, levels = 3)
92+
Plt.Colorbar(
93+
f[2, 1],
94+
limits = (
95+
minimum(v for v in V_ms if !isnan(v)),
96+
maximum(v for v in V_ms if !isnan(v)),
97+
),
98+
colormap = Plt.reverse(Plt.cgrad(:Spectral)),
99+
flipaxis = true,
100+
vertical = false,
101+
)
102+
103+
ax2 = Plt.Axis(
104+
f[1, 2],
105+
xlabel = "F_r",
106+
ylabel = "ρ_r",
107+
title = "Medium Dₘ",
108+
width = 350,
109+
height = 350,
110+
limits = (0, 1.0, 25, 975),
111+
xticks = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0],
112+
yticks = [200, 400, 600, 800],
113+
)
114+
115+
Plt.contourf!(
116+
F_rm,
117+
ρ_rm,
118+
V_mm,
119+
colormap = Plt.reverse(Plt.cgrad(:Spectral)),
120+
)
121+
Plt.contour!(F_rm, ρ_rm, D_mm, color = :black, labels = true, levels = 3)
122+
Plt.Colorbar(
123+
f[2, 2],
124+
limits = (
125+
minimum(v for v in V_mm if !isnan(v)),
126+
maximum(v for v in V_mm if !isnan(v)),
127+
),
128+
colormap = Plt.reverse(Plt.cgrad(:Spectral)),
129+
flipaxis = true,
130+
vertical = false,
131+
)
132+
133+
ax3 = Plt.Axis(
134+
f[1, 3],
135+
xlabel = "F_r",
136+
ylabel = "ρ_r",
137+
title = "Large Dₘ",
138+
width = 350,
139+
height = 350,
140+
limits = (0, 1.0, 25, 975),
141+
xticks = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0],
142+
yticks = [200, 400, 600, 800],
143+
)
144+
145+
Plt.contourf!(
146+
F_rl,
147+
ρ_rl,
148+
V_ml,
149+
colormap = Plt.reverse(Plt.cgrad(:Spectral)),
150+
)
151+
Plt.contour!(F_rl, ρ_rl, D_ml, color = :black, labels = true, levels = 3)
152+
Plt.Colorbar(
153+
f[2, 3],
154+
limits = (
155+
minimum(v for v in V_ml if !isnan(v)),
156+
maximum(v for v in V_ml if !isnan(v)),
157+
),
158+
colormap = Plt.reverse(Plt.cgrad(:Spectral)),
159+
flipaxis = true,
160+
vertical = false,
161+
)
162+
163+
Plt.linkxaxes!(ax1, ax2)
164+
Plt.linkxaxes!(ax2, ax3)
165+
Plt.linkyaxes!(ax1, ax2)
166+
Plt.linkyaxes!(ax2, ax3)
167+
168+
# Plot D_m as second row of comparisons
169+
170+
ax4 = Plt.Axis(
171+
f[3, 1],
172+
height = 350,
173+
width = 350,
174+
xlabel = "F_r",
175+
ylabel = "ρ_r",
176+
title = "Small Dₘ vs F_r and ρ_r",
177+
)
178+
Plt.contourf!(
179+
F_rs,
180+
ρ_rs,
181+
D_ms,
182+
colormap = Plt.reverse(Plt.cgrad(:Spectral)),
183+
)
184+
Plt.Colorbar(
185+
f[4, 1],
186+
limits = (
187+
minimum(d for d in D_ms if !isnan(d)),
188+
maximum(d for d in D_ms if !isnan(d)),
189+
),
190+
colormap = Plt.reverse(Plt.cgrad(:Spectral)),
191+
flipaxis = true,
192+
vertical = false,
193+
)
194+
ax5 = Plt.Axis(
195+
f[3, 2],
196+
height = 350,
197+
width = 350,
198+
xlabel = "F_r",
199+
ylabel = "ρ_r",
200+
title = "Medium Dₘ vs F_r and ρ_r",
201+
)
202+
Plt.contourf!(
203+
F_rm,
204+
ρ_rm,
205+
D_mm,
206+
colormap = Plt.reverse(Plt.cgrad(:Spectral)),
207+
)
208+
Plt.Colorbar(
209+
f[4, 2],
210+
limits = (
211+
minimum(d for d in D_mm if !isnan(d)),
212+
maximum(d for d in D_mm if !isnan(d)),
213+
),
214+
colormap = Plt.reverse(Plt.cgrad(:Spectral)),
215+
flipaxis = true,
216+
vertical = false,
217+
)
218+
ax6 = Plt.Axis(
219+
f[3, 3],
220+
height = 350,
221+
width = 350,
222+
xlabel = "F_r",
223+
ylabel = "ρ_r",
224+
title = "Large Dₘ vs F_r and ρ_r",
225+
)
226+
Plt.contourf!(
227+
F_rl,
228+
ρ_rl,
229+
D_ml,
230+
colormap = Plt.reverse(Plt.cgrad(:Spectral)),
231+
)
232+
Plt.Colorbar(
233+
f[4, 3],
234+
limits = (
235+
minimum(d for d in D_ml if !isnan(d)),
236+
maximum(d for d in D_ml if !isnan(d)),
237+
),
238+
colormap = Plt.reverse(Plt.cgrad(:Spectral)),
239+
flipaxis = true,
240+
vertical = false,
241+
)
242+
243+
Plt.linkxaxes!(ax1, ax4)
244+
Plt.linkxaxes!(ax4, ax5)
245+
Plt.linkxaxes!(ax5, ax6)
246+
Plt.linkyaxes!(ax1, ax4)
247+
Plt.linkyaxes!(ax4, ax5)
248+
Plt.linkyaxes!(ax5, ax6)
249+
250+
Plt.resize_to_layout!(f)
251+
Plt.save("MorrisonandMilbrandtFig2.svg", f)
252+
end
253+
254+
# Terminal Velocity figure
255+
figure_2()

0 commit comments

Comments
 (0)