Skip to content

Latest commit

 

History

165 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NumericalRadiation.jl

☀️ Atmospheric radiative transfer and gas optics in Julia, compatible with ECMWF's ecRad/ecCKD data, for CPUs and GPUs. https://NumericalEarth.github.io/NumericalRadiation.jl/dev

GitHub tag (latest SemVer pre-release) Apache 2.0 license ColPrac: Contributor's Guide on Collaborative Practices for Community Packages

Stable documentation Development documentation

CI Documenter Code coverage

NumericalRadiation computes atmospheric radiative fluxes and heating rates. It ingests reference ecCKD CKD-definition files into typed, Adapt.jl-aware look-up tables, evaluates g-point optical properties through a staged runtime (optical_properties! → radiative_fluxes! → heating_rates!), and solves clear-sky and cloud-overlap two-stream column transport.

It also bundles two analytic-band per-column schemes for intermediate-complexity models:

  • Longwave — Williams (2026) Simple Spectral Model: a 41-wavenumber clear-sky two-stream Schwarzschild solver with analytic H₂O line, H₂O continuum and CO₂ absorption coefficients. Published in J. Adv. Model. Earth Syst., doi:10.1029/2025MS005405.
  • Shortwave — a one-band scheme after SPEEDY (Kucharski, Molteni & Bracco, Quart. J. Roy. Meteor. Soc., 2006), with transparent, constant, or Kucharski-style background-transmissivity options and a diagnostic cloud/stratocumulus model.

The analytic-band solvers are pure scalar ingredients that a host model can fuse into its own column loops or kernels; the NumericalRadiationSpeedyWeatherExt package extension wires them into SpeedyWeather.jl per column. The ecCKD path has the same scalar form for host kernels — see Host kernels (Breeze) below.

Contents

Installation instructions

NumericalRadiation is a registered Julia package. So to install it,

  1. Download Julia (version 1.10 or later).

  2. Launch Julia and type

julia> using Pkg

julia> Pkg.add("NumericalRadiation")

This installs the latest version that's compatible with your current environment. Check which NumericalRadiation you installed with

julia> Pkg.status("NumericalRadiation")

Running your first column

Bundle the grid, profile, surface, schemes, constants, and pre-allocated buffers into a single RadiativeTransferColumn and call the solvers with one argument:

using NumericalRadiation

Nz = 8
σ_half  = collect(range(0.0, 1.0, length=Nz + 1))
grid    = ColumnGrid(σ_half)

# Lapse-rate profile: top of atmosphere (k=1) cold, surface (k=Nz) warm.
profile = AtmosphereProfile(
    temperature      = collect(range(220.0, 295.0, length=Nz)),
    humidity         = fill(0.005, Nz),
    geopotential     = zeros(Nz),
    surface_pressure = 100_000.0,
    CO₂              = 280.0,
)

surface = SurfaceState(
    sea_surface_temperature  = 295.0,
    land_surface_temperature = 285.0,
    land_fraction            = 0.3,
    ocean_albedo             = 0.07,
    land_albedo              = 0.25,
    cos_zenith               = 0.5,
)

# Schemes, constants, and output buffers all wrap up here.
column = RadiativeTransferColumn(; grid, profile, surface)

solve_longwave!(column)
solve_shortwave!(column)

@show column.longwave_diagnostics.outgoing_longwave        # W m⁻²
@show column.longwave_diagnostics.surface_longwave_down    # W m⁻²
@show column.shortwave_diagnostics.surface_shortwave_down  # W m⁻²
@show column.temperature_tendency                           # K s⁻¹ per layer

For the low-level kernel form (what host extensions such as NumericalRadiationSpeedyWeatherExt call internally), solve_longwave! and solve_shortwave! accept the flattened (temperature_tendency, diagnostics, scheme, profile, grid, surface, constants, …) signature directly, and the constants argument is duck-typed — any struct or NamedTuple carrying gravity, heat_capacity, stefan_boltzmann, solar_constant properties works. The staged runtime reads the same kind of object from ColumnAtmosphere.constants (a PhysicalConstants by default, which also carries dry_air_molar_mass, water_molar_mass, dry_air_gas_constant, universal_gas_constant and avogadro_number), so no physical constant is hard-coded anywhere on the radiation path.

All floating-point types default to Float64. To run in Float32 (useful for GPU kernels), pass the type as the first positional argument to the scheme constructors and readers: AnalyticBandLongwave(Float32), OneBandShortwave(Float32), read_reference_ecckd_gas_optics(Float32, "32x32"), SpectralCloudOptics(Float32, table, mapping; effective_radius), etc.

With SpeedyWeather.jl

The NumericalRadiationSpeedyWeatherExt extension defines a SpeedyAnalyticBandLongwave scheme that subtypes SpeedyWeather.AbstractLongwave and can be passed directly to PrimitiveWetModel:

using SpeedyWeather, NumericalRadiation
const SpeedyExt = Base.get_extension(NumericalRadiation, :NumericalRadiationSpeedyWeatherExt)

spectral_grid = SpectralGrid(trunc=31, nlayers=8)
longwave      = SpeedyExt.SpeedyAnalyticBandLongwave(spectral_grid)
model         = PrimitiveWetModel(spectral_grid; longwave_radiation=longwave)

Host kernels (Breeze)

The ecCKD gas optics and the clear-sky solvers are also exposed as scalar, per-layer, per-g-point functions that a host model calls inside its own column kernels without allocating: gas_optics_stencil brackets a layer on the coefficient tables once, longwave_optical_depth, shortwave_optical_depth, rayleigh_optical_depth and longwave_source evaluate one g point at a time from a NamedTuple of scalar gas amounts, and streaming_longwave_fluxes! / streaming_shortwave_fluxes! sweep one column through layer-optics functors with caller-owned scratch (a TabulatedSurfaceEmission surface source and a ShortwaveColumnScratch). SpectralCloudOptics adds per-g-point cloud optics to the same loop. The array methods (optical_properties!, radiative_fluxes!) are loops over these functions, so the two paths agree bit for bit — the longwave path and every shortwave g point that scatters; a shortwave g point with no scattering at all takes a closed-form Beer–Lambert branch in the array solver that treats the surface-reflected flux as a slant beam rather than diffuse, see the streaming column API page. Every function is @inline, allocation-free and Adapt.jl-aware, so the loop runs unchanged on GPU. This is the API the NumericalRadiation extension of Breeze.jl (in progress) is built on; the streaming column API page walks through the loop on a two-layer column.

Schemes at a glance

Scheme Purpose References
AnalyticBandLongwave 41-band clear-sky LW Williams (2026); Armstrong (1968); Mlawer et al. (1997)
NumericalRadiation.TransparentShortwave (unexported) Zero-atmosphere SW; surface-albedo only —
OneBandShortwave SPEEDY moist SW (diagnostic clouds + background transmissivity) Kucharski, Molteni & Bracco (2006)
NumericalRadiation.OneBandGreyShortwave (unexported) SPEEDY dry SW (no clouds, constant transmissivity) Kucharski, Molteni & Bracco (2006)
DiagnosticClouds Cloud cover from RH + precipitation; stratocumulus from DSE stability SPEEDY §B4
BackgroundShortwaveTransmissivity Dry-air + aerosol + WV + cloud absorptivities, pressure-weighted SPEEDY §B4
ConstantShortwaveTransmissivity Single-value column transmissivity —

Getting help

  • The documentation has a quickstart, the physics and numerics behind each scheme, and a library of every user-facing object and function.
  • Issues and pull requests record problems we've found, how we solved them, and what we're working on.
  • The NumericalEarth slack is a good place to ask questions.

Running the tests

julia> using Pkg

julia> Pkg.test("NumericalRadiation")

Validation platform

The development and validation harness — accuracy gates, reference manifests, frozen evidence, and the training pipeline — lives on the validation-platform branch; this branch carries only the package.

License

Apache 2.0. See LICENSE.

About

☀️ Radiative transfer modeling for stand-alone, SpeedyWeather.jl, and Breeze.jl applications, based on ecCKD and ecRad

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages