Predicted Particle Properties (P3): Usage

This page shows how to construct and use Breeze's P3 microphysics scheme, and works through visual examples of the particle properties and size distributions it tabulates. For the underlying physics, see Predicted Particle Properties (P3): Theory.

Quick Start

using Breeze# Create a P3 scheme with default parametersmicrophysics = PredictedParticlePropertiesMicrophysics()
PredictedParticlePropertiesMicrophysics
├── ρʷ: 1000.0 kg/m³
├── qmin: 1.0e-14 kg/kg
├── ice: IceParticles
├── rain: RainDrops
├── cloud: CloudDroplets
├── process_rates: ProcessRate
├── negative_moisture_correction: SpeciesBorrowing(vertical_borrowing = nothing)
├── aerosol: nothing (prescribed droplet number)
└── warm_rain_scheme: KhairoutdinovKogan2000
# Access ice propertiesmicrophysics.ice
IceParticles
├── ρᶠ: [50.0, 900.0] kg/m³
├── μmax: 20.0
├── IceFallSpeed(ρ₀=0.8258242446735904)
├── IceDeposition()
├── IceBulk(Dmax=0.02, Dmin=2.0e-6)
├── IceCollection(4 integrals)
├── IceLambdaLimiter(2 integrals)
└── IceRainCollection(2 integrals)
# Get prognostic field namesprognostic_field_names(microphysics)
(:ρqᶜˡ, :ρqʳ, :ρnʳ, :ρqⁱ, :ρnⁱ, :ρqᶠ, :ρbᶠ, :ρqʷⁱ)

Configuring the empirical warm-phase parameters

The cloud-width, rain fall-speed, and rain-ventilation relations are empirical fits. Their coefficients live in three small containers that the scheme constructor accepts, so they can be varied for calibration or sensitivity work. Custom values are threaded through the startup quadrature and through every runtime kernel — there is no second copy of the defaults anywhere in the rate calculations. See Empirical Warm-Phase Coefficients for what each scalar means.

The equations denote free parameters with readable subscripts, such as $\mathbb{C}_{\mathrm{vent},2}$. Julia lacks the corresponding Unicode subscript letters, so formula-local source identifiers use ℂᵛᵉⁿᵗ₂ instead (ℂ is entered as \bbC<TAB>). Configuration uses descriptive public keywords such as reynolds_coefficient; the theory table gives the one-to-one mapping. This keeps model configuration readable without hiding which quantities are intended for calibration.

using Breeze.Microphysics.PredictedParticleProperties:    CloudDroplets, CloudShape,    RainDrops, RainFallSpeed, RainVentilation# Cap the diagnosed cloud shape parameter below its default ceilingcloud_shape = CloudShape(Float64;    relative_dispersion_number_coefficient = 5.714e-10,    relative_dispersion_intercept = 0.2714,    minimum_shape_parameter = 2,    maximum_shape_parameter = 12)cloud = CloudDroplets(Float64; shape = cloud_shape)# A slightly slower large-drop plateau and a stronger Reynolds ventilation termfall_speed = RainFallSpeed(Float64;    branch_velocity_scales = (4579.5, 49.62, 17.32),    branch_mass_exponents = (2 / 3, 1 / 3, 1 / 6),    transition_diameters = (134.43e-6, 1511.64e-6, 3477.84e-6),    plateau_velocity = 8.8)ventilation = RainVentilation(Float64;    constant_coefficient = 0.78,    reynolds_coefficient = 0.35)rain = RainDrops(Float64; fall_speed, ventilation)tuned = P3Microphysics(Float64; cloud, rain)tuned.rain
RainDrops(fall_speed=RainFallSpeed(ℂᶠᵃˡˡ₁=(4579.5, 49.62, 17.32) m/s, ℂᶠᵃˡˡ₂=(0.667, 0.333, 0.167), ℂᶠᵃˡˡ₃=(134.43, 1511.64, 3477.84) μm, ℂᶠᵃˡˡ₄=8.8 m/s), ventilation=RainVentilation(ℂᵛᵉⁿᵗ₁=0.78, ℂᵛᵉⁿᵗ₂=0.35))

The containers survive lookup-table materialization, so the scheme the model steps with is the one that was configured:

(tuned.cloud.shape.maximum_shape_parameter, tuned.rain.fall_speed.plateau_velocity, tuned.rain.ventilation.reynolds_coefficient)
(12.0, 8.8, 0.35)

All values are SI or dimensionless. The velocity scales are in m s⁻¹ (the published fit is stated in cm s⁻¹), and the mass argument of the fall-speed law is the dimensionless ratio drop_mass / one_gram, numerically the drop mass in grams.

P3 Examples and Visualization

This section provides worked examples demonstrating P3 microphysics concepts through visualization and analysis.

Every ice-side quantity below is read from the P3 lookup tables, which is exactly how the model evaluates them at runtime — see Integral Properties for the table layout. The ice-only block is indexed by $(\log_{10} \bar{m}, F^f, F^l, ρ^f)$, where $\bar{m} = (ρq^i + ρq^{wi})/ρn^i$ is the mean particle mass; the ice–rain collection block adds $\log λ^r$ as a fifth coordinate. The shape parameter $μ$ is a tabulated output of the ice-only block, not one of its coordinates.

The examples illustrate key concepts from the P3 papers:

Ice Particle Property Explorer

Let's explore how ice particle properties vary with mean mass and riming state.

using Breezeusing Breeze.Microphysics.PredictedParticlePropertiesusing CairoMakie# The default constructor reads the P3 ASCII lookup tables# (downloaded automatically on first use).p3 = PredictedParticlePropertiesMicrophysics()bulk = p3.ice.bulk# Mean particle mass axis, spanning most of the tabulated range.m̄ = 10 .^ range(-13, -3, length=200)log_m̄ = log10.(m̄)# Use dry ice for the plots below.Fˡ = 0.0

Mean Diameter versus Mean Mass

fig = Figure(size=(700, 500))ax = Axis(fig[1, 1],    xlabel = "Mean particle mass m̄ [kg]",    ylabel = "Mean maximum dimension D̄ [m]",    xscale = log10,    yscale = log10,    title = "Tabulated Mean Diameter vs Mean Mass")for (Fᶠ, ρᶠ, label) in [(0.0, 400.0, "Unrimed (Fᶠ = 0)"),                        (0.2, 400.0, "Light rime (Fᶠ = 0.2)"),                        (0.5, 500.0, "Moderate rime (Fᶠ = 0.5)"),                        (0.8, 700.0, "Heavy rime (Fᶠ = 0.8)")]    D̄ = [bulk.mean_diameter(lm, Fᶠ, Fˡ, ρᶠ) for lm in log_m̄]    lines!(ax, m̄, D̄, linewidth=2, label=label)endaxislegend(ax, position=:lt)fig
Example block output

Riming packs more mass into a particle of a given size, so through the aggregate-to-graupel range — roughly $\bar{m}$ from $10^{-8}$ to $10^{-6}$ kg — a rimed distribution has the smaller mean dimension, and the separation widens with size.

That ordering is not universal, and the plot shows where it breaks down. Below about $10^{-10}$ kg every curve collapses onto the solid-ice sphere, where morphology cannot matter. At the largest tabulated masses the unrimed curve flattens while the rimed ones keep growing, so the ordering reverses.

Bulk Density and the Riming Regimes

fig = Figure(size=(700, 400))ax = Axis(fig[1, 1],    xlabel = "Mean particle mass m̄ [kg]",    ylabel = "Mean bulk density ρ̄ [kg m⁻³]",    xscale = log10,    title = "Tabulated Mean Ice Density")for (Fᶠ, ρᶠ, label) in [(0.0, 400.0, "Fᶠ = 0"),                        (0.2, 400.0, "Fᶠ = 0.2"),                        (0.5, 500.0, "Fᶠ = 0.5"),                        (0.8, 700.0, "Fᶠ = 0.8")]    ρ̄ = [bulk.mean_density(lm, Fᶠ, Fˡ, ρᶠ) for lm in log_m̄]    lines!(ax, m̄, ρ̄, linewidth=2, label=label)endaxislegend(ax, position=:rt)fig
Example block output

Small particles are solid ice spheres at $ρ_i$. As the mean mass grows the distribution moves into the aggregate regime and the bulk density falls; riming fills the gaps, pushing the density back toward the graupel value.

Size Distribution Visualization

Effect of Mass Content

The table supplies the gamma-PSD slope $λ$ and shape $μ$ directly. The intercept follows from the number concentration, $N_0 = N λ^{μ+1} / Γ(μ+1)$.

using SpecialFunctions: loggamma# Reconstruct N'(D) from the tabulated (λ, μ) and a prescribed N.function tabulated_psd(p3, q, N, Fᶠ, ρᶠ; Fˡ = 0.0)    bulk = p3.ice.bulk    log_m̄ = log10(q / N)    λ = bulk.slope(log_m̄, Fᶠ, Fˡ, ρᶠ)    μ = bulk.shape(log_m̄, Fᶠ, Fˡ, ρᶠ)    log_N₀ = log(N) + (μ + 1) * log(λ) - loggamma(μ + 1)    return (; λ, μ, log_N₀)endfig = Figure(size=(700, 500))ax = Axis(fig[1, 1],    xlabel = "Diameter D [mm]",    ylabel = "N'(D) [m⁻⁴]",    yscale = log10,    title = "Ice Size Distributions for Different Mass Contents\n(N = 10⁵ m⁻³)")D_mm = range(0.01, 8, length=300)D_m = D_mm .* 1e-3N_ice = 1e5for (q, color, label) in [    (1e-5, :blue, "q = 0.01 g/m³"),    (5e-5, :green, "q = 0.05 g/m³"),    (1e-4, :orange, "q = 0.1 g/m³"),    (5e-4, :red, "q = 0.5 g/m³"),    (1e-3, :purple, "q = 1.0 g/m³")]    psd = tabulated_psd(p3, q, N_ice, 0.0, 400.0)    # Evaluate N'(D) = N₀ D^μ e^{-λD} through log N₀: the intercept itself carries units    # of m^-(4+μ) and reaches magnitudes that only Float64 can hold.    N_D = @. exp(psd.log_N₀ + psd.μ * log(D_m) - psd.λ * D_m)    lines!(ax, D_mm, N_D, color=color, linewidth=2, label=label)endaxislegend(ax, position=:rt)ylims!(ax, 1e2, 1e14)fig
Example block output

Higher mass content (at fixed number) shifts the distribution toward larger particles.

Shape Parameter Effect

fig = Figure(size=(700, 500))ax = Axis(fig[1, 1],    xlabel = "Diameter D [mm]",    ylabel = "N'(D) / N₀",    title = "Effect of Shape Parameter μ on Distribution Shape\n(λ = 2000 m⁻¹)")D_mm = range(0.01, 3, length=200)D_m = D_mm .* 1e-3λ = 2000.0for μ in [0, 1, 2, 4, 6]    N_norm = @. D_m^μ * exp(-λ * D_m)    N_norm ./= maximum(N_norm)  # Normalize to peak    lines!(ax, D_mm, N_norm, linewidth=2, label="μ = $μ")endaxislegend(ax, position=:rt)fig
Example block output

Higher $μ$ produces a narrower distribution with a more pronounced mode.

Slope Parameter versus Mean Mass

fig = Figure(size=(700, 500))ax = Axis(fig[1, 1],    xlabel = "Mean particle mass m̄ = q/N [kg]",    ylabel = "λ [m⁻¹]",    xscale = log10,    yscale = log10,    title = "Tabulated Slope Parameter vs Mean Particle Mass")for (Fᶠ, ρᶠ, label) in [(0.0, 400.0, "Unrimed"), (0.5, 500.0, "Rimed (Fᶠ = 0.5)")]    λs = [bulk.slope(lm, Fᶠ, Fˡ, ρᶠ) for lm in log_m̄]    lines!(ax, m̄, λs, linewidth=2, label=label)endaxislegend(ax, position=:rt)fig
Example block output

At the same mean mass, rimed particles carry a larger $λ$ (smaller characteristic size), because their higher mass-per-particle is reached with smaller particles.

Summary Visualization

fig = Figure(size=(900, 600))# Mean diameter (top left)ax1 = Axis(fig[1, 1],    xlabel = "m̄ [kg]", ylabel = "D̄ [mm]",    xscale = log10, yscale = log10,    title = "Mean Diameter vs Mean Mass")for (Fᶠ, ρᶠ, label) in [(0.0, 400.0, "Fᶠ=0"), (0.5, 500.0, "Fᶠ=0.5")]    D̄ = [bulk.mean_diameter(lm, Fᶠ, Fˡ, ρᶠ) * 1e3 for lm in log_m̄]    lines!(ax1, m̄, D̄, label=label)endaxislegend(ax1, position=:lt)# Size distribution (top right)ax2 = Axis(fig[1, 2],    xlabel = "D [mm]", ylabel = "N'(D) [m⁻⁴]",    yscale = log10, title = "Size Distribution")D_mm = range(0.1, 5, length=100)D_m = D_mm .* 1e-3for q in [1e-5, 1e-4, 1e-3]    psd = tabulated_psd(p3, q, 1e5, 0.0, 400.0)    N_D = @. exp(psd.log_N₀ + psd.μ * log(D_m) - psd.λ * D_m)    lines!(ax2, D_mm, N_D, label="q=$(q*1e3) g/m³")endylims!(ax2, 1e3, 1e13)axislegend(ax2, position=:rt)# μ-λ relationship (bottom)ax4 = Axis(fig[2, 1:2],    xlabel = "λ [m⁻¹]", ylabel = "μ",    xscale = log10, title = "μ-λ Relationship")for (Fᶠ, ρᶠ, label, color) in [(0.0, 400.0, "Fᶠ = 0", :blue),                               (0.5, 500.0, "Fᶠ = 0.5", :orange)]    λs = [bulk.slope(lm, Fᶠ, Fˡ, ρᶠ) for lm in log_m̄]    μs = [bulk.shape(lm, Fᶠ, Fˡ, ρᶠ) for lm in log_m̄]    lines!(ax4, λs, μs, linewidth=2, color=color, label=label)endaxislegend(ax4, position=:rt)fig
Example block output

This figure summarizes the key relationships in P3:

  1. Top left: Mean dimension grows with mean mass, and shrinks with riming through the aggregate-to-graupel range (with the caveats noted above)
  2. Top right: Size distribution shifts with mass content
  3. Bottom: Shape parameter μ increases with λ up to a maximum