Skip to content

Commit 7265c76

Browse files
committed
add supporting P3 collisions sub-parameterizations
dry freeze rate & local rime density
1 parent d054516 commit 7265c76

File tree

3 files changed

+199
-0
lines changed

3 files changed

+199
-0
lines changed

docs/src/API.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,27 @@ P3Scheme.D_m
167167
P3Scheme.ice_particle_terminal_velocity
168168
P3Scheme.ice_terminal_velocity_number_weighted
169169
P3Scheme.ice_terminal_velocity_mass_weighted
170+
```
171+
172+
### Processes
173+
174+
#### Heterogeneous ice nucleation
175+
```@docs
170176
P3Scheme.het_ice_nucleation
177+
```
178+
179+
#### Ice melting
180+
```@docs
171181
P3Scheme.ice_melt
172182
```
173183

184+
#### Collisions with liquid droplets
185+
Supporting methods:
186+
```@docs
187+
P3Scheme.compute_max_freeze_rate
188+
P3Scheme.compute_local_rime_density
189+
```
190+
174191
### Supporting integral methods
175192

176193
```@docs

src/P3_processes.jl

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,130 @@ function ice_melt(
9999
dLdt = min(dLdt, L_ice / dt)
100100
return (; dNdt, dLdt)
101101
end
102+
103+
"""
104+
compute_max_freeze_rate(state, aps, tps, velocity_params, ρₐ, Tₐ)
105+
106+
Returns a function `max_freeze_rate(Dᵢ)` that returns the maximum possible freezing rate [kg/s]
107+
for an ice particle of diameter `Dᵢ` [m]. Evaluates to 0 if T ≥ T_freeze.
108+
109+
# Arguments
110+
- `state`: [`P3State`](@ref)
111+
- `aps`: [`CMP.AirProperties`](@ref)
112+
- `tps`: `TDP.ThermodynamicsParameters`
113+
- `velocity_params`: The velocity parameterization, e.g. [`CMP.Chen2022VelType`](@ref)
114+
- `ρₐ`: air density [kg/m³]
115+
- `Tₐ`: air temperature [K]
116+
117+
This rate represents the thermodynamic upper limit to collisional freezing,
118+
which occurs when the heat transfer from the ice particle to the environment is
119+
balanced by the latent heat of fusion.
120+
121+
From Eq (A7) in Musil (1970), [Musil1970](@cite).
122+
"""
123+
function compute_max_freeze_rate(state, aps, tps, velocity_params, ρₐ, Tₐ)
124+
(; D_vapor, K_therm) = aps
125+
cp_l = TDP.cp_l(tps)
126+
T_frz = TDP.T_freeze(tps)
127+
Lᵥ = TD.latent_heat_vapor(tps, Tₐ)
128+
L_f = TD.latent_heat_fusion(tps, Tₐ)
129+
Tₛ = T_frz # the surface of the ice particle is assumed to be at the freezing temperature
130+
ΔT = Tₛ - Tₐ # temperature difference between the surface of the ice particle and the air
131+
Δρᵥ_sat = ρₐ * ( # saturation vapor density difference between the surface of the ice particle and the air
132+
TD.q_vap_saturation(tps, Tₛ, ρₐ, TD.PhaseNonEquil) -
133+
TD.q_vap_saturation(tps, Tₐ, ρₐ, TD.PhaseNonEquil)
134+
)
135+
v_term = ice_particle_terminal_velocity(state, velocity_params, ρₐ)
136+
F_v = CO.ventilation_factor(state.params.vent, aps, v_term)
137+
function max_freeze_rate(Dᵢ)
138+
Tₐ T_frz && return zero(Dᵢ) # No collisional freezing above the freezing temperature
139+
return 2 ** Dᵢ) * F_v(Dᵢ) * (K_therm * ΔT + Lᵥ * D_vapor * Δρᵥ_sat) / (L_f - cp_l * ΔT)
140+
end
141+
return max_freeze_rate
142+
end
143+
144+
"""
145+
compute_local_rime_density(state, velocity_params, ρₐ, T)
146+
147+
Provides a function `ρ′ᵣ(Dᵢ, Dₗ)` that computes the local rime density [kg/m³]
148+
for a given ice particle diameter `Dᵢ` [m] and liquid particle diameter `Dₗ` [m].
149+
150+
From Cober and List (1993).
151+
152+
# Arguments
153+
- `state`: a [`P3State`](@ref) object
154+
- `velocity_params`: The velocity parameterization, e.g. [`CMP.Chen2022VelType`](@ref)
155+
- `ρₐ`: air density [kg/m³]
156+
- `T`: temperature [K]
157+
158+
# Returns
159+
A function that computes the local rime density [kg/m³] using the equation:
160+
161+
```math
162+
ρ′_r = 51 + 114 R_i - 5.5 R_i^2
163+
```
164+
where
165+
```math
166+
R_i = ( D_{liq} ⋅ |v_{liq} - v_{ice}| ) / ( 2 T_{sfc} )
167+
```
168+
and ``T_{sfc}`` is the surface temperature [°C], ``D_{liq}`` is the liquid particle
169+
diameter [m], ``v_{liq/ice}`` is the particle terminal velocity [m/s].
170+
So the units of ``R_i`` are [m² s⁻¹ °C⁻¹]. The units of ``ρ′_r`` are [kg/m³].
171+
172+
They assume for simplicity that `T_sfc` equals `T`, the ambient air temperature.
173+
For real graupel, `T_sfc` is slightly higher than `T` due to latent heat release
174+
of freezing liquid particles onto the ice particle. MM13 found little sensitivity
175+
to "realistic" increases in `T_sfc`.
176+
177+
Implementation follows Cober and List (1993), Eq. 16 and 17.
178+
See also the P3 fortran code, microphy_p3.f90, Line 3315-3323,
179+
which extends the range of the calculation to Rᵢ ≤ 12, the upper limit of which
180+
then equals the solid bulk ice density, ``ρ^⭒ = 900 kg/m^3``.
181+
182+
Note that MM15 only uses this parameterization for collisions with cloud droplets.
183+
For rain drops, they use the solid bulk ice density, ``ρ^* = 900 kg/m^3``.
184+
We do not consider this distinction, and use this parameterization for all liquid particles.
185+
"""
186+
function compute_local_rime_density(state, velocity_params, ρₐ, T)
187+
(; T_freeze) = state.params
188+
T°C = T - T_freeze # Convert to °C
189+
190+
v_ice = ice_particle_terminal_velocity(state, velocity_params, ρₐ)
191+
v_liq = CO.particle_terminal_velocity(velocity_params.rain, ρₐ)
192+
function ρ′ᵣ(Dᵢ, Dₗ)
193+
v_term = abs(v_ice(Dᵢ) - v_liq(Dₗ))
194+
Rᵢ = (Dₗ * v_term) / (2 * T°C) # Eq. 16 in Cober and List (1993). Note: no `-` due to absolute value in v_term
195+
return ρ′ᵣ_P3(Rᵢ)
196+
end
197+
return ρ′ᵣ
198+
end
199+
200+
"""
201+
ρ′ᵣ_P3(Rᵢ)
202+
203+
Returns the local rime density [kg/m³] for a given Rᵢ [m² s⁻¹ °C⁻¹].
204+
205+
Based on Cober and List (1993), Eq. 16 and 17 (valid for 1 ≤ Rᵢ ≤ 8).
206+
For 8 < Rᵢ ≤ 12, linearly interpolate between ρ′ᵣ(8) ≡ 611 kg/m³ and ρ⭒ = 900 kg/m³.
207+
See also the P3 fortran code
208+
"""
209+
function ρ′ᵣ_P3(Rᵢ)
210+
# TODO: Externalize these parameters
211+
a, b, c = 51, 114, -11//2 # coeffs for Eq. 17 in Cober and List (1993), converted to [kg / m³]
212+
ρ⭒ = 900 # ρ^⭒: density of solid bulk ice
213+
214+
Rᵢ = clamp(Rᵢ, 1, 12) # P3 fortran code, microphy_p3.f90, Line 3315 clamps to 1 ≤ Rᵢ ≤ 12
215+
216+
ρ′ᵣ_CL93(Rᵢ) = a + b * Rᵢ + c * Rᵢ^2 # Eq. 17 in Cober and List (1993), in [kg / m³], valid for 1 ≤ Rᵢ ≤ 8
217+
ρ′ᵣ = if Rᵢ 8
218+
ρ′ᵣ_CL93(Rᵢ)
219+
else
220+
# following P3 fortran code, microphy_p3.f90, Line 3323
221+
# https://github.com/P3-microphysics/P3-microphysics/blob/main/src/microphy_p3.f90#L3323
222+
# for 8 < Rᵢ ≤ 12, linearly interpolate between ρ′ᵣ(8) ≡ 611 kg/m³ and ρ⭒ = 900 kg/m³
223+
ρ′ᵣ8 = ρ′ᵣ_CL93(8)
224+
f_ρ⭒ = (Rᵢ - 8) / (12 - 8)
225+
(1 - f_ρ⭒) * ρ′ᵣ8 + f_ρ⭒ * ρ⭒ # Linear interpolation beyond 8.
226+
end
227+
return float(ρ′ᵣ)
228+
end

test/p3_tests.jl

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,58 @@ function test_p3_melting(FT)
561561
end
562562
end
563563

564+
function test_p3_bulk_liquid_ice_collisions(FT)
565+
params = CMP.ParametersP3(FT)
566+
vel_params = CMP.Chen2022VelType(FT)
567+
aps = CMP.AirProperties(FT)
568+
tps = TD.Parameters.ThermodynamicsParameters(FT)
569+
570+
(; T_freeze) = params
571+
572+
ρₐ = FT(1.2)
573+
qᵢ = FT(1e-4)
574+
Lᵢ = qᵢ * ρₐ
575+
Nᵢ = FT(2e5) * ρₐ
576+
F_rim = FT(0.8)
577+
ρ_rim = FT(800)
578+
579+
state = P3.get_state(params; F_rim, ρ_rim, L_ice = Lᵢ, N_ice = Nᵢ)
580+
logλ = P3.get_distribution_logλ(state)
581+
= exp(-logλ)
582+
583+
@testset "maximum dry freezing rate" begin
584+
# Below freezing, max freeze rate is non-zero (check against reference value)
585+
Tₐ = T_freeze - 1//10
586+
max_rate = P3.compute_max_freeze_rate(state, aps, tps, vel_params, ρₐ, Tₐ)
587+
@test max_rate(D̄) FT(8.819134467143614e-13) rtol = 1e-4
588+
589+
# At freezing, max freeze rate is zero
590+
Tₐ = T_freeze
591+
max_rate = P3.compute_max_freeze_rate(state, aps, tps, vel_params, ρₐ, Tₐ)
592+
@test iszero(max_rate(D̄))
593+
594+
# Above freezing, max freeze rate is zero
595+
Tₐ = T_freeze + 1//10
596+
max_rate = P3.compute_max_freeze_rate(state, aps, tps, vel_params, ρₐ, Tₐ)
597+
@test iszero(max_rate(D̄))
598+
end
599+
600+
@testset "local rime density" begin
601+
Tₐ = T_freeze - 1//10
602+
ρ′ᵣ = P3.compute_local_rime_density(state, vel_params, ρₐ, Tₐ)
603+
@test ρ′ᵣ(D̄, D̄) FT(159.5) rtol = 1e-6
604+
605+
a, b, c = 51, 114, -11//2 # coeffs for Eq. 17 in Cober and List (1993), converted to [kg / m³]
606+
ρ′ᵣ_CL93(Rᵢ) = a + b * Rᵢ + c * Rᵢ^2 # Eq. 17 in Cober and List (1993), in [kg / m³], valid for 1 ≤ Rᵢ ≤ 8
607+
ρ⭒ = FT(900) # ρ^⭒: density of solid bulk ice
608+
609+
@test P3.ρ′ᵣ_P3(FT(1)) == ρ′ᵣ_CL93(FT(1))
610+
@test P3.ρ′ᵣ_P3(FT(8)) == ρ′ᵣ_CL93(FT(8))
611+
@test P3.ρ′ᵣ_P3(FT(12)) == ρ⭒
612+
end
613+
614+
end
615+
564616

565617
TT.@testset "P3 tests ($FT)" for FT in (Float64, Float32)
566618
# state creation
@@ -578,5 +630,8 @@ TT.@testset "P3 tests ($FT)" for FT in (Float64, Float32)
578630
# processes
579631
test_p3_het_freezing(FT)
580632
test_p3_melting(FT)
633+
634+
# bulk liquid-ice collisions and related processes
635+
test_p3_bulk_liquid_ice_collisions(FT)
581636
end
582637
nothing

0 commit comments

Comments
 (0)