API Reference

GREBClimate.DATA_DEP_NAMEConstant

Name of the DataDep, and the folder name the dataset is cached under inside DataDeps' storage (~/.julia/scratchspaces/<uuid>/datadeps/ by default).

source
GREBClimate.DATA_RELEASE_TAGConstant

Release tag and asset name for the published dataset bundle.

The bundle is built from a validated greb_input_data/ tree with tools/package_dataset.jl, which also prints the SHA256 below.

source
GREBClimate.DATA_SHA256Constant

SHA256 of DATA_ARCHIVE_NAME, 370563584 bytes.

Reproducible: tools/package_dataset.jl builds the archive with sorted entries, zeroed owner/group, pinned entry timestamps and gzip -n, so the archive depends only on the dataset's contents. Regenerating the .jld2 tree from the raw .bin files and repackaging reproduces this exact hash.

(The timestamp pin matters: without it tar stored each file's mtime, so a regenerated-but-byte-identical dataset produced a different archive.)

source
GREBClimate.nghostConstant
nghost

Periodic ghost cells held at each end of the longitude axis by the circulation buffers, so wrap-around is a unit-stride read instead of a gather.

A ghosted column stores A[i, k] at row i + nghost, with each end mirroring the other:

row    1 … 3  │  4 … 99         │  100 … 102
holds  94…96  │  1 … 96 (real)  │  1 … 3

So A[j-1, k] is just P[j+2, k]. The lon_jm1..lon_jp3 index arrays this replaced cost ~12 gather instructions per inner loop.

nghost is the zonal stencils' reach, so it is 3 and they spell their offsets out literally (jj+6); widening the stencil means widening both.

Also called halo cells (the usual term in climate models) or guard cells. The literature covers the distributed-memory use, where ghosts cache a neighbouring MPI rank and are refreshed by a "halo exchange" - Kjolstad & Snir, "The Ghost Cell Pattern" (ParaPLoP 2010). Here there is one process and the neighbour is the opposite edge of the same array, so ghost cells buy vectorisable addressing, not avoided communication.

source
GREBClimate.nstep_yrConstant
nstep_yr

Time steps per year (ndays_yr * ndt_days = 730). Together with xdim and ydim this fixes the shape of every field the model steps.

julia> (xdim, ydim, nstep_yr)
(96, 48, 730)
source
GREBClimate.CirculationWorkspaceType
CirculationWorkspace

Pre-allocated buffers for diffusion, advection, and circulation calculations. Reused across all time steps to eliminate allocations.

source
GREBClimate.ClimateFieldsType
ClimateFields

Loaded climatology, derived grid fields, flux corrections, and the regional-CO2 mask/solar table - everything load_greb_jld2! fills in and every physics function reads. One instance per greb_model! run; never shared as global state.

ClimateFields() builds an all-zero instance and leaves loaded = false; load_greb_jld2! sets loaded = true once real climatology is in place. greb_model! refuses to run unloaded fields unless explicitly told to via allow_uninitialized=true - an all-zero climatology produces a physically meaningless world pinned at the 40 K floor (~-233 °C) rather than an error, so the flag exists to keep that path opt-in.

source
GREBClimate.ModelStateType
ModelState

Per-run mutable state that isn't climatology: the runtime solar-forcing multiplier (SWradiation! reads it) and the surface-temperature accumulator behind the annual progress line (diagnostics! reads/writes it). One instance per greb_model! run.

This is scratch space for the printed summary, not an output path - Tsmn is averaged, printed and zeroed within a single diagnostics! call, so it never holds a readable annual mean once the call returns. Model output is the Vector{MonthlyRecord} that greb_model! returns.

source
GREBClimate.MonthlyRecordType
MonthlyRecord

One monthly-mean output record: a NamedTuple with fields Ts, Ta, To, q, albedo, ice, precip, evap, qcrcl, sw, lw, qlat, qsens, each an (xdim, ydim) Matrix{Float32}. Produced by output!; greb_model!'s ctrl/scnr results are Vector{MonthlyRecord}.

source
GREBClimate.PhysicsConfigType
PhysicsConfig

All model switches and parameters: mean-climate/CO₂-response toggles, circulation components, hydrology parameters, external-forcing flags, and the current experiment type. Passed explicitly to every physics function; build one with create_experiment_config rather than the bare keyword constructor for anything beyond :full_model.

source
GREBClimate.RunSpecType
RunSpec

Run durations (in years) for greb_model!: flux (flux-correction spin-up), ctrl (control run), scnr (scenario run). A keyword struct instead of three bare positional ints, whose order was easy to swap by mistake.

julia> RunSpec(ctrl = 10, scnr = 30)
RunSpec(0, 10, 30)

julia> RunSpec().ctrl, RunSpec().scnr
(1, 1)
source
GREBClimate.LWradiation!Method
LWradiation!(Ts, Ta, q, CO2, fields::ClimateFields, timestate, cfg::PhysicsConfig, ws::CirculationWorkspace)

Computes atmospheric emissivity from CO₂/water-vapor/cloud columns, then surface/upward/downward longwave flux. If cfg.log_atmos_dmc is false, only LW_down is zeroed - LW_up is snapshotted beforehand and keeps its full value (decouples surface from atmospheric downwelling feedback without touching the atmosphere's own emission term). Returns (LW_surf, LW_up, LW_down, em).

source
GREBClimate.SWradiation!Method
SWradiation!(Ts, fields::ClimateFields, state::ModelState, timestate, cfg::PhysicsConfig, ws::CirculationWorkspace)

Computes ice cover, surface/atmospheric/combined albedo, and net shortwave flux from Ts and the current cloud climatology. Returns (SW, albedo, ice_cover).

source
GREBClimate._cached_datadep_pathMethod
_cached_datadep_path() -> String or nothing

Path to the already-downloaded dataset cache, or nothing if it is absent.

DataDeps offers no public "is this already here?" query - datadep"..." and resolve both fetch when the data is missing, which is the opposite of what is wanted here. try_determine_load_path is the internal function that answers it without touching the network. It is wrapped in a try so that if a future DataDeps release renames or removes it, this degrades to "not cached" (and the normal download path still works) rather than erroring.

source
GREBClimate.advection!Method
advection!(T1, h_scl, fields::ClimateFields, ws::CirculationWorkspace, timestate, cfg::PhysicsConfig)

Meridional + zonal advection of T1 (temperature or humidity), writing the tendency into ws.dX_adv. Gated by cfg.log_hadv/cfg.log_vadv depending on h_scl.

source
GREBClimate.apply_dynamic_co2_mask!Method
apply_dynamic_co2_mask!(cfg::PhysicsConfig, fields::ClimateFields, icmn_ctrl)

Sets fields.co2_part for the two regional-CO₂ experiments whose mask depends on the control run's ice climatology (:regional_co2_ocean, :regional_co2_land_ice). A no-op for every other experiment - the static regional masks are set by init_model!.

source
GREBClimate.circulation!Method
circulation!(X_in, h_scl, dX_out, fields::ClimateFields, ws::CirculationWorkspace, timestate, cfg::PhysicsConfig)

Sub-steps X_in through ntime iterations of diffusion!, advection!, and convergence! (each gated by the relevant cfg.log_* switch), writing the total change into dX_out. The sub-step loop is a genuine sequential recurrence and is not parallelized.

source
GREBClimate.convergence!Method
convergence!(T1, fields::ClimateFields, timestate, ws::CirculationWorkspace)

Moisture flux convergence from T1 (specific humidity, [kg/kg]) and the current fields.omegaclim (vertical velocity), writing the tendency into ws.dX_conv. Implements Eq. 18 from Stassen et al. (2019).

source
GREBClimate.create_experiment_configMethod
create_experiment_config(experiment::Symbol; co2_path="", orbital_index=0,
    earth_sun_distance_pct=0.0, log_clouds_dmc=nothing, log_ocean_dmc=nothing,
    log_atmos_dmc=nothing, log_co2_dmc=nothing, log_hydro_dmc=nothing,
    log_qflux_dmc=nothing, log_topo_drsp=nothing, log_clouds_drsp=nothing,
    log_humid_drsp=nothing, log_ocean_drsp=nothing, log_hydro_drsp=nothing,
    log_ice=nothing, log_hdif=nothing, log_hadv=nothing, log_vdif=nothing,
    log_vadv=nothing) -> PhysicsConfig

Create a pre-configured PhysicsConfig for any experiment the model dispatches on. Errors on an unknown symbol, listing the valid ones.

The 16 log_* keywords are used only by :decon_mean_climate/:decon_2xco2; passing one for any other experiment warns and is ignored, rather than being silently dropped. co2_path applies only to :custom_co2, orbital_index to the paleo/orbital experiments, and earth_sun_distance_pct to :earth_sun_distance.

Only :constant_topo, :co2_double, :co2_quadruple, :paleo_231kyr and the three forced-boundary experiments carry a static override; every other entry is experiment = sym alone, because forcing sets the scenario CO₂ per timestep and co2_concentration seeds the control run.

Experiments

  • :full_model - All processes active (default)
  • :constant_topo - Constant topography (logtopodrsp = false), 2×CO₂ scenario
  • :co2_double/:co2_quadruple/:co2_10x/:co2_half/:co2_zero - CO₂ scaling
  • :co2_sine_wave/:co2_step - time-varying CO₂
  • :a1b_scenario - A1B CO₂ ramp (control baseline 280 ppm)
  • :solar_plus27 - +27 W/m² solar constant
  • :solar_cycle_11yr - 11-year solar cycle
  • :paleo_231kyr - Paleoclimate (200 ppm CO₂)
  • :paleo_solar_modern_co2/:modern_solar_paleo_co2 - crossed paleo/modern forcing
  • :obliquity/:eccentricity - orbital forcing, orbital_index selects the table row
  • :earth_sun_distance - solar constant scaled by earth_sun_distance_pct
  • :elnino/:lanina - ERA-Interim ENSO conditions
  • :rcp26/:rcp45/:rcp60/:rcp85 - IPCC RCP climate change scenarios
  • :ssp119/:ssp126/:ssp245/:ssp460/:ssp585 - IPCC SSP scenarios
  • :historical_co2 - Observed CO₂ 1850-2017 (year starts at 1850, not 1950)
  • :custom_co2 - user-supplied CO₂ trajectory, co2_path keyword gives the "year CO2" text file path (see load_custom_co2_scenario)
  • :sst_plus1 - ocean surface warmed 1 K, CO₂ held at control
  • :regional_co2_nh/:regional_co2_sh/:regional_co2_tropics/:regional_co2_extratropics - 2×CO₂ over a latitude band (static mask, set by init_model!)
  • :regional_co2_ocean/:regional_co2_land_ice - 2×CO₂ over ocean or land/ice (mask derived from the control run's ice cover, see apply_dynamic_co2_mask!)
  • :regional_co2_winter/:regional_co2_summer - 2×CO₂ in one boreal season
  • :decon_mean_climate - deconstruct-mean-state experiment
  • :decon_2xco2 - deconstruct-2×CO₂-response experiment

Examples

julia> cfg = create_experiment_config(:co2_double);

julia> cfg.experiment, cfg.co2_concentration
(:co2_double, 680.0f0)

julia> create_experiment_config(:constant_topo).log_topo_drsp
false
source
GREBClimate.deep_ocean!Method
deep_ocean!(Ts, To, fields::ClimateFields, timestate, cfg::PhysicsConfig, ws::CirculationWorkspace)

Computes surface/deep-ocean coupling tendencies (dT_ocean, dTo) from mixed-layer-depth entrainment/detrainment and turbulent mixing, active only where the point is ocean and above the sea-ice threshold. Returns zeros if cfg.log_ocean_dmc/cfg.log_ocean_drsp disable ocean coupling.

source
GREBClimate.diagnostics!Method
diagnostics!(it, year, CO2, surf::SurfaceState, tend, fields, state, timestate)

Accumulates the current timestep into state's annual-mean buffers; at the last timestep of the year, averages them, prints the annual summary line (global mean + two sample points), and resets the accumulators for the next year. tend is the NamedTuple tendencies! returns.

source
GREBClimate.diffusion!Method
diffusion!(T1, h_scl, fields::ClimateFields, ws::CirculationWorkspace, timestate)

Meridional + zonal diffusion of T1 (temperature or humidity), writing the tendency into ws.dX_diff. h_scl (z_air or z_vapor) selects the topographic weighting field.

source
GREBClimate.forcingMethod
forcing(it, year, cfg::PhysicsConfig, fields::ClimateFields, icmn_ctrl; nstep_yr=nstep_yr)

Returns (CO2, sw_solar_forcing) for the current timestep, computed according to cfg.experiment. Pure - the regional_co2_* masks are built once per run by apply_dynamic_co2_mask!, not here. :full_model short-circuits before the experiment dispatch chain. The :rcp26/:rcp45/:rcp60/ :custom_co2/:ssp*/:historical_co2 experiments look year up in cfg.co2_scenario.

source
GREBClimate.greb_data_dirFunction
greb_data_dir(path = nothing; allow_download = true) -> String or nothing

Return the directory holding the JLD2 input dataset, resolving in this order:

  1. path, if given and non-empty.
  2. ENV["GREB_DATA"], if set.
  3. greb_input_data/ next to the package, if it exists.
  4. An already-downloaded GREB-input-data DataDep, if its cache is present.
  5. The GREB-input-data DataDep - downloading it on first use, after asking.

Pass allow_download = false to stop after step 4 and return nothing when no dataset is available locally. Test suites and benchmarks use this so that running them can never pull 353 MB over the network as a side effect.

The result is a plain path, suitable for load_greb_jld2! and greb_model!'s jld2_dir:

dir    = greb_data_dir()
fields = load_greb_jld2!(dir; dataset = :ncep)
result = greb_model!(RunSpec(), cfg; jld2_dir = dir, fields = fields)
source
GREBClimate.greb_model!Method
greb_model!(run::RunSpec, cfg::PhysicsConfig; jld2_dir="", fields=ClimateFields(),
            allow_uninitialized=false)

Run a GREB flux-correction spin-up (run.flux years), control run (run.ctrl years), and scenario run (run.scnr years) for cfg.

fields holds the loaded climatology/grid/flux-correction state (see ClimateFields, built by load_greb_jld2!). Pass the same fields instance across multiple calls to reuse already-loaded climatology instead of reloading it - that's the only case where co2_part/sw_solar mutations from one run could otherwise leak into the next; this function resets/restores them per-run regardless.

source
GREBClimate.hydro!Method
hydro!(Ts, q, fields::ClimateFields, timestate, cfg::PhysicsConfig, ws::CirculationWorkspace)

Computes latent heat flux and evaporation/rain tendencies. cfg.log_eva (-1/0/1/2) selects the wind-gust/coefficient parameterization used for evaporation; cfg.log_rain (via cfg.c_q/c_rq/c_omega/c_omegastd, set by set_hydrology_parameters!) controls the rain regression. Returns (Q_lat, Q_lat_air, dq_eva, dq_rain).

source
GREBClimate.init_model!Method
init_model!(cfg::PhysicsConfig, fields::ClimateFields)

One-time per-run setup: derives cfg's hydrology parameters, resets the regional-CO₂ mask, applies CO₂-response climatology overrides (log_clouds_drsp/log_humid_drsp/log_ocean_drsp), and computes the control-run initial state. Returns (Ts_ini, Ta_ini, To_ini, q_ini, CO2_ctrl).

source
GREBClimate.load_cc_anomaly_jld2!Method
load_cc_anomaly_jld2!(jld2_dir::String, fields::ClimateFields, cfg::PhysicsConfig)

Loads the CMIP5 RCP8.5 ensemble-mean climate-change anomaly fields into fields.Tclim_anom_cc/uclim_anom_cc/vclim_anom_cc/omegaclim_anom_cc/ wsclim_anom_cc, gated per-field by cfg.log_tsurf_ext/log_hwind_ext/ log_omega_ext. Errors on a missing file rather than defaulting to zero, since this data is the :rcp85 experiment's forcing.

source
GREBClimate.load_co2_scenario_jld2Method
load_co2_scenario_jld2(jld2_dir::String, scenario::Symbol) -> Dict{Int,Float32}

Loads a year => CO2 (ppm-equivalent) lookup table for an IPCC scenario (e.g. :ssp585, :rcp85) from the combined scenario/ipcc_scenarios.jld2.

source
GREBClimate.load_custom_co2_scenarioMethod
load_custom_co2_scenario(path::String) -> Dict{Int,Float32}

Loads a year => CO2 lookup table for the :custom_co2 experiment from a plain-text file, one year CO2 pair per line. Blank lines and lines starting with # are skipped.

source
GREBClimate.load_enso_anomaly_jld2!Method
load_enso_anomaly_jld2!(jld2_dir::String, fields::ClimateFields, cfg::PhysicsConfig, which::Symbol)

Loads the ERA-Interim composite-mean El Niño (which=:elnino) or La Niña (:lanina) anomaly fields into fields.*_anom_enso, gated the same way as load_cc_anomaly_jld2!.

source
GREBClimate.load_greb_jld2!Method
load_greb_jld2!(jld2_dir::String; dataset::Symbol=:ncep)

Load all GREB input data from JLD2 formatted files, returning a fresh ClimateFields. dataset (:ncep/:era) selects which climatology files to read; this is independent of PhysicsConfig.log_clim, which only selects hydrology regression coefficients in set_hydrology_parameters!.

source
GREBClimate.load_solar_forcing_jld2Function
load_solar_forcing_jld2(jld2_dir::String, forcing_type::Symbol, index::Int=0)

Loads an alternate solar-forcing table for paleo/orbital experiments. forcing_type is :paleo, :eccentricity, or :obliquity; for the latter two, index selects the matching row by coordinate value. Used by greb_model! to temporarily swap fields.sw_solar for these experiments.

source
GREBClimate.output!Method
output!(it, irec, mon, surf::SurfaceState, tend, ws, output_buf, acc, timestate)

Accumulates the current timestep into acc; on the last timestep of mon, pushes a monthly-mean MonthlyRecord onto output_buf, resets acc, and advances to the next month. Returns (mon, irec). tend is the NamedTuple tendencies! returns; ws.precip_out/evap_out/ qcrcl_out hold this step's converted precipitation/evaporation/moisture- circulation output.

source
GREBClimate.qflux_correction!Method
qflux_correction!(CO2_ctrl, Ts, Ta, q, To, fields, state, timestate, cfg, ws, time_flux; ws_a=ws, ws_q=ws)

Runs time_flux years of tendencies! to derive the ocean/atmosphere flux corrections (fields.TF_correct/qF_correct/ToF_correct) that make the control climate match observed climatology. Mutates Ts/Ta/q/To in place as it integrates. ws_a/ws_q are forwarded to tendencies!

source
GREBClimate.read_jld2Method
read_jld2(filepath::String)

Read a .jld2 field file written by tools/convert_greb_to_jld2.jl.

Returns

  • named tuple (data, dim_names, coords, ctl) where:
    • data: Array{Float32} with shape as stored
    • dim_names: Vector{String} of dimension names (e.g., ["lon", "lat", "time"])
    • coords: Dict{Int,Vector{Float64}} of physical coordinate values per dimension index, or nothing if the file has none
    • ctl: raw GrADS .ctl metadata text, or nothing if the file has none
source
GREBClimate.seaice!Method
seaice!(Ts0, fields::ClimateFields, timestate, cfg::PhysicsConfig)

Updates fields.cap_surf (surface heat capacity) for ocean points based on Ts0-derived ice fraction, blending land/open-ocean/ice capacities. No-op if cfg.log_ocean_dmc is false; skips the ice-albedo blend if cfg.log_ice is false.

source
GREBClimate.tendencies!Method
tendencies!(CO2, Ts, Ta, To, q, fields, state, ws, timestate, cfg; ws_a=ws, ws_q=ws)

Runs one timestep's physics pipeline - SWradiation!LWradiation! → sensible heat → hydro!circulation! (temperature, then humidity) → deep_ocean! - and returns a named tuple of every intermediate flux/tendency needed by diagnostics! and the caller's own state update.

The two circulation! calls are independent of each other and of every other stage (each reads only pre-timestep state and writes disjoint buffers), so when the caller supplies distinct ws_a/ws_q workspaces and Threads.nthreads() > 1, they run concurrently via Threads.@spawn while the remaining stages run on ws. With the default ws_a=ws_q=ws

source
GREBClimate.time_loop!Method
time_loop!(it, year, CO2, mon, irec, Ts, Ta, q, To, output_buf, fields, state, ws, acc, timestate, cfg; ws_a=ws, ws_q=ws)

One full model timestep: computes tendencies!, integrates Ts/Ta/To/q forward with flux corrections applied, runs seaice!, then dispatches to output! and diagnostics!. Returns (mon, irec). ws_a/ws_q are forwarded to tendencies! - see its docstring for the opt-in threading they enable.

source