AtmosphereModel microphysics interface
This document describes the interface for embedding microphysical processes into AtmosphereModel. The interface consists of eight functions that must be implemented for any microphysics scheme to work with AtmosphereModel.
Overview
The microphysics interface consists of seven functions, each of which must be implemented to complete a microphysics implementation in AtmosphereModel:
Breeze.AtmosphereModels.prognostic_field_names- Defines the names of the prognostic microphysical fields
Breeze.AtmosphereModels.materialize_microphysical_fields- "Materializes" or generates, given the model
gridandboundary_conditions, aNamedTupleof microphysical fields. - The
NamedTupleof microphysical fields must include prognostic fields, but can also include additional diagnostic fields. - Note,
boundary_conditionscan only be supplied to prognostic fields.
- "Materializes" or generates, given the model
Breeze.AtmosphereModels.update_microphysical_fields!- Update the diagnostic microphysics fields. This should not touch the prognostic fields.
Breeze.AtmosphereModels.maybe_adjust_thermodynamic_state- Possibly adjust the thermodynamic state according to some constraint, such as saturation adjustment.
Breeze.AtmosphereModels.compute_moisture_fractions- Given the model state, return a
MoistureMassFractionsobject
- Given the model state, return a
Breeze.AtmosphereModels.microphysical_velocities- Build the differential velocity field that microphysical tracers experience in addition to the bulk velocity (for example, the terminal velocity of falling hydrometeors)
Breeze.AtmosphereModels.microphysical_tendency- Add additional tendency terms to the microphysical tracer equations representing for example, condensation, evaporation, or autoconversion of cloud liquid and ice content to snow or rain.
Example implementation
To illustrate the development of a new microphysics scheme, we implement a simple microphysics scheme that represents droplet and ice particle nucleation with constant-rate relaxation of specific humidity to saturation.
using Breeze
struct ExplicitMicrophysics{FT}
vapor_to_liquid :: FT
vapor_to_ice :: FT
endPrognostic field names and materializing prognostic + diagnostic fields
This scheme is fully prognostic, which means we must carry around vapor, liquid and ice density as prognostic variables,
import Breeze.AtmosphereModels: prognostic_field_names
prognostic_field_names(::ExplicitMicrophysics) = (:ρqᵛ, :ρqˡ, :ρqⁱ)prognostic_field_names (generic function with 11 methods)The names of prognostic fields defined by prognostic_field_names are crucial to the user interface, because users can interact them and set! their initial conditions. The names of variables should be carefully chosen to be concise, mathematical forms that are consistent with Breeze conventions.
When we materialize the microphysics fields, we must include all of the prognostic fields in addition to diagnostic fields (this behavior may change in the future):
import Breeze.AtmosphereModels: materialize_microphysical_fields
function materialize_microphysical_fields(::ExplicitMicrophysics, grid, boundary_conditions)
ρqᵛ = CenterField(grid, boundary_conditions=boundary_Conditions.ρqᵛ)
ρqˡ = CenterField(grid, boundary_conditions=boundary_Conditions.ρqˡ)
ρqⁱ = CenterField(grid, boundary_conditions=boundary_Conditions.ρqⁱ)
qᵛ = CenterField(grid)
return (; ρqˡ, ρqⁱ, ρqᵛ, qᵛ)
endmaterialize_microphysical_fields (generic function with 7 methods)The tendencies for
import Breeze.AtmosphereModels: microphysical_tendency
using Breeze.Thermodynamics:
PlanarLiquidSurface,
PlanarIceSurface
@inline function microphysical_tendency(i, j, k, grid, em::ExplicitMicrophysics, ::Val{:ρqˡ}, ρ, μ, 𝒰, constants)
ρⁱʲᵏ = @inbounds ρ[i, j, k]
T = temperature(𝒰, constants)
q⁺ˡ = saturation_specific_humidity(T, ρⁱʲᵏ, constants, PlanarLiquidSurface())
τᵛˡ = em.vapor_to_liquid
return @inbounds ρⁱʲᵏ * (μ.qᵛ[i, j, k] - q⁺ˡ) / τᵛˡ
end
@inline function microphysical_tendency(i, j, k, grid,
em::ExplicitMicrophysics, ::Val{:ρqⁱ}, ρ, μ, 𝒰, constants)
ρⁱʲᵏ = @inbounds ρ[i, j, k]
T = temperature(𝒰, constants)
q⁺ⁱ = saturation_specific_humidity(T, ρⁱʲᵏ, constants, PlanarIceSurface())
τᵛⁱ = em.vapor_to_ice
qᵛ = @inbounds μ.qᵛ[i, j, k]
return ρⁱʲᵏ * (qᵛ - q⁺ⁱ) / τᵛⁱ
end
@inline function microphysical_tendency(i, j, k, grid,
em::ExplicitMicrophysics, ::Val{:ρqᵛ}, ρ, μ, 𝒰, constants)
Sᵛˡ = microphysical_tendency(i, j, k, grid, em, Val(:ρvˡ), ρ, μ, 𝒰, constants)
Sᵛⁱ = microphysical_tendency(i, j, k, grid, em, Val(:ρvⁱ), ρ, μ, 𝒰, constants)
return - Sᵛˡ - Sᵛⁱ
endmicrophysical_tendency (generic function with 12 methods)Note we have included the diagnostic field qᵛ (the vapor mass fraction, aka "specific humidity") in addition to the three prognostic fields representing vapor, liquid and ice density.
Prognostic field names and materializing prognostic + diagnostic fields
import Breeze.AtmosphereModels:
update_microphysical_fields!,
compute_moisture_fraction
@inline update_microphysical_fields!(μ, em::ExplicitMicrophysics, i, j, k, grid, ρ, state, constants) =
@inbounds μ.qᵛ[i, j, k] = state.moisture_mass_fractions.vapor
@inline function compute_moisture_fractions(i, j, k, grid,
::ExplicitMicrophysics, ρ, qᵗ, microphysical_fields)
@inbounds begin
qᵛ = microphysical_fields.qᵛ[i, j, k]
qˡ = microphysical_fields.ρqˡ[i, j, k] / ρ
qⁱ = microphysical_fields.ρqⁱ[i, j, k] / ρ
end
return MoistureMassFractions(qᵛ, qˡ, qⁱ)
endcompute_moisture_fractions (generic function with 1 method)This is a fully prognostic scheme, so there is no adjustment,
import Breeze.AtmosphereModels: maybe_adjust_thermodynamic_state
@inline maybe_adjust_thermodynamic_state(state, ::ExplicitMicrophysics, μ, qᵗ, constants) = statemaybe_adjust_thermodynamic_state (generic function with 6 methods)