Single-column analytical radiation

This page drives the analytical longwave and shortwave solvers together on a single column and plots their heating-rate profiles. It serves as a template for integrating NumericalRadiation into a single-column model or for debugging a new band parameterization.

Lapse-rate column, daytime + doubled CO₂

using NumericalRadiation
using CairoMakie

Nz = 32
σᵢ = collect(range(0, 1, length=Nz + 1))   # interface sigma coordinate
grid = ColumnGrid(σᵢ)

base_profile = AtmosphereProfile(
    temperature      = collect(range(220, 295, length=Nz)),
    humidity         = fill(0.008, Nz),
    geopotential     = zeros(Nz),
    surface_pressure = 100_000,
)
FT = Float64
surface = SurfaceState(FT; sea_surface_temperature = 295,
                       land_surface_temperature = NaN,
                       land_fraction = 0,
                       ocean_albedo = 0.07,
                       land_albedo  = 0.07,
                       cos_zenith   = 0.5)
constants = PhysicalConstants(FT)
thermo    = ThermodynamicConstants(FT)

longwave  = AnalyticBandLongwave(FT)
shortwave = NumericalRadiation.OneBandShortwave(FT)

function solve_column(carbon_dioxide_ppmv)
    profile = AtmosphereProfile(
        temperature      = base_profile.temperature,
        humidity         = base_profile.humidity,
        geopotential     = base_profile.geopotential,
        surface_pressure = base_profile.surface_pressure,
        CO₂              = carbon_dioxide_ppmv,
    )
    Ṫˡʷ = zeros(Nz)
    Ṫˢʷ = zeros(Nz)
    longwave_diagnostics  = LongwaveDiagnostics(FT)
    shortwave_diagnostics = ShortwaveDiagnostics(FT, Nz)
    transmissivity = similar(profile.temperature)

    solve_longwave!(Ṫˡʷ, longwave_diagnostics, longwave, profile, grid, surface, constants)
    solve_shortwave!(Ṫˢʷ, shortwave_diagnostics, shortwave, profile, grid,
                     surface, constants, thermo;
                     transmissivity_scratch = transmissivity)
    return (; Ṫˡʷ, Ṫˢʷ, longwave_diagnostics, shortwave_diagnostics)
end

baseline = solve_column(280)
doubled  = solve_column(560)

fig = Figure(size=(920, 460))
ax_longwave = Axis(fig[1, 1]; xlabel="LW heating rate [K day⁻¹]", ylabel="σ", yreversed=true, title="Longwave")
ax_shortwave = Axis(fig[1, 2]; xlabel = "SW heating rate [K day⁻¹]",
                    ylabel = "σ", yreversed = true, title = "Shortwave")
ax_net = Axis(fig[1, 3]; xlabel="Net heating rate [K day⁻¹]", ylabel="σ", yreversed=true, title="Net (LW + SW)")

for (result, label, color) in ((baseline, "280 ppmv", :dodgerblue), (doubled, "560 ppmv", :crimson))
    lines!(ax_longwave, result.Ṫˡʷ .* 86_400, grid.σ_full; label, color, linewidth=2)
    lines!(ax_shortwave, result.Ṫˢʷ .* 86_400, grid.σ_full; label, color, linewidth=2)
    lines!(ax_net, (result.Ṫˡʷ .+ result.Ṫˢʷ) .* 86_400, grid.σ_full; label, color, linewidth=2)
end
Legend(fig[2, 1:3], ax_longwave; orientation=:horizontal, framevisible=false)

The longwave panel shows the characteristic cooling-to-space signature with stronger cooling where water vapour is most abundant. The shortwave panel shows the ozone bump near the top of the model and the warming contribution from water-vapour near-IR absorption in the lower troposphere. Doubling CO₂ reduces outgoing longwave (more negative LW heating is damped) and leaves the shortwave essentially unchanged.

TOA energy budget

Print the fluxes for each experiment:

for (label, result) in (("280 ppmv", baseline), ("560 ppmv", doubled))
    @info(label,
          olr = result.longwave_diagnostics.outgoing_longwave,
          surface_lw_down = result.longwave_diagnostics.surface_longwave_down,
          toa_sw_up = result.shortwave_diagnostics.outgoing_shortwave,
          surface_sw_down = result.shortwave_diagnostics.surface_shortwave_down)
end
┌ Info: 280 ppmv
│   olr = 217.65902626281527
│   surface_lw_down = 348.33360995188474
│   toa_sw_up = 82.02504015011455
└   surface_sw_down = 213.51439326531658
┌ Info: 560 ppmv
│   olr = 215.769400645381
│   surface_lw_down = 350.11440371247846
│   toa_sw_up = 82.02504015011455
└   surface_sw_down = 213.51439326531658