Core Concepts

The package is easiest to understand if you keep three objects in mind:

  • Atmosphere: one timestep of atmospheric conditions
  • Weather: a convenient constructor for weather tables made of Atmosphere rows
  • TimeStepTable: the underlying table abstraction used across the package

Atmosphere: One Timestep

using PlantMeteo
using Dates

row = Atmosphere(
    date = DateTime(2025, 7, 1, 12),
    duration = Hour(1),
    T = 24.0,
    Wind = 1.8,
    Rh = 0.58,
    P = 101.3,
    Ri_SW_f = 620.0
)

row
Atmosphere(date = DateTime("2025-07-01T12:00:00"), duration = Hour(1), T = 24.0, Wind = 1.8, P = 101.3, Rh = 0.58, Precipitations = 0.0, Cₐ = 400.0, e = 1.7373682725833977, eₛ = 2.9954625389368927, VPD = 1.258094266353495, ρ = 1.1875807472771054, λ = 2.44424e6, γ = 0.06749702930430417, ε = 0.5946170191650276, Δ = 0.18041050771926415, Ri_SW_f = 620.0)

An Atmosphere row stores one weather timestep. Some variables are mandatory (T, Wind, Rh), while others are optional or can be computed from those core inputs.

Construction is strict by default. Invalid wind, humidity, or pressure throws an error before dependent variables are computed. check=false skips these checks but does not clamp wind, divide humidity by 100, convert pressure, or otherwise change the supplied values. Physical zero remains valid for calm wind, dry air, darkness, and zero incoming radiation.

Optional clearness and Ri_*_f forcing is structural. If a keyword is omitted, the property is absent; if the source explicitly contains a missing value, pass missing and the property remains present. PlantMeteo does not use Inf to mean "not supplied".

Weather: A Convenient Weather Constructor

weather = Weather(
    [
        row,
        Atmosphere(
            date = DateTime(2025, 7, 1, 13),
            duration = Hour(1),
            T = 25.0,
            Wind = 2.0,
            Rh = 0.55,
            P = 101.3,
            Ri_SW_f = 580.0
        ),
    ],
    (site = "demo", source = "synthetic")
)

weather
TimeStepTable{Atmosphere{(:date, :duration,...}(2 x 17):
date duration T Wind P Rh Precipitations Cₐ e eₛ VPD ρ λ γ ε Δ Ri_SW_f
DateTime Hour Float64 Float64 Float64 Float64 Float64 Float64 Float64 Float64 Float64 Float64 Float64 Float64 Float64 Float64 Float64
1 2025-07-01T12:00:00 1 hour 24.0 1.8 101.3 0.58 0.0 400.0 1.73737 2.99546 1.25809 1.18758 2.44424e6 0.067497 0.594617 0.180411 620.0
2 2025-07-01T13:00:00 1 hour 25.0 2.0 101.3 0.55 0.0 400.0 1.74911 3.1802 1.43109 1.1836 2.44188e6 0.0675624 0.594904 0.190095 580.0
Metadata: `Dict("source" => "synthetic", "site" => "demo")`

Weather is usually the easiest way to say "this is a weather table made of atmospheric rows". If an optional forcing exists on only some input rows, Weather keeps one stable union schema and inserts missing in the other rows. A forcing omitted from every row remains structurally absent from the whole table.

TimeStepTable: The Shared Table Abstraction

Weather is built on top of TimeStepTable, which exposes row access, column access, metadata, and the Tables.jl interface.

weather[1]
╭──── TimeStepRow ─────────────────────────────────────────────────────────────╮
  Step 1: date=2025-07-01T12:00:00, duration=1 hour, T=24.0, Wind=1.8,        
  P=101.3, Rh=0.58, Precipitations=0.0, Cₐ=400.0, e=1.7373682725833977,       
  eₛ=2.9954625389368927 ...                                                   
╰──────────────────────────────────────────────────────────────────────────────╯
weather[:T]
2-element Vector{Float64}:
 24.0
 25.0
weather[2, :T]
25.0
metadatakeys(weather)
("site", "source")

This is what makes the rest of the package coherent: whether the data came from an API, a CSV file, or a synthetic example, you work with the same table abstraction afterward.

Metadata

Metadata is attached to the table, not to each row:

metadata(weather)
Dict{String, String} with 2 entries:
  "source" => "synthetic"
  "site"   => "demo"

This is useful for keeping site information, provenance, or source notes attached to the weather series. PlantMeteo preserves metadata values from imported files without interpreting them. Column transformations apply only to table columns: they never parse or rename metadata values. Downstream code may interpret a metadata key only when that behavior is part of its documented API; otherwise the value remains source provenance.

Variables And Units

PlantMeteo expects canonical variable names and units in Atmosphere rows. For example:

  • T: air temperature in degrees Celsius
  • Rh: relative humidity in 0-1 units
  • Wind: wind speed in m s-1
  • P: air pressure in kPa
  • Ri_SW_f: incoming short-wave radiation flux in W m-2

This is why read_weather matters: local files rarely arrive with these exact names and units. Declare non-canonical humidity and pressure units with input_units, or call normalize_weather_import directly. Conversion is never guessed from the magnitude of a value. Imported tables append a YAML-safe provenance record that lists the conversions applied without discarding earlier import history.

What Comes Next