Leaf processes respond to the air temperature, humidity, wind, and CO₂ concentration around the leaf. PlantMeteo describes these conditions with an Atmosphere for one timestep or a Weather series for several timesteps. Pass either one as environment=meteo when creating a CompositeModel.
Start with the conditions measured near your leaf:
| Input | Meaning | Unit |
|---|---|---|
T | Air temperature | °C |
Rh | Relative humidity | Fraction from 0 to 1 |
Wind | Wind speed | m s⁻¹ |
P | Air pressure | kPa |
Cₐ | Air CO₂ concentration | µmol mol⁻¹ |
duration | Timestep duration | A period such as Hour(1) |
Atmosphere supplies defaults for optional inputs, including Cₐ, but provide measured values when available. Specify the duration explicitly when using a time series or calculating totals.
using PlantMeteo
meteo = Atmosphere(T=20.0, Wind=1.0, P=101.3, Rh=0.65, duration=Hour(1))Atmosphere calculates related quantities such as vapour pressure deficit (VPD, kPa) and air density (ρ, kg m⁻³). You can override a derived value when you have an independent measurement or calculation:
using PlantMeteo
Atmosphere(T=20.0, Wind=1.0, P=101.3, Rh=0.65, VPD=0.82, duration=Hour(1))Read a value with the dot syntax. For example, saturation vapour pressure (eₛ) is in kPa:
meteo.eₛIncident radiation can also be supplied through Atmosphere, using Ri_PAR_f and Ri_NIR_f in W m⁻². Leaf models need absorbed radiation, which is supplied on the leaf or calculated by a light model. See Light interception for the distinction.
Weather collects consecutive Atmosphere values, with optional metadata such as a site name. Here are three hourly timesteps:
using PlantMeteo
w = Weather(
[
Atmosphere(T=20.0, Wind=1.0, P=101.3, Rh=0.65, duration=Hour(1)),
Atmosphere(T=23.0, Wind=1.5, P=101.3, Rh=0.60, duration=Hour(1)),
Atmosphere(T=25.0, Wind=3.0, P=101.3, Rh=0.55, duration=Hour(1))
],
(
site = "Montpellier",
)
)| TimeStepTable{Atmosphere{(:date, :duration,...}(3 x 16): | ||||||||||||||||
| date | duration | T | Wind | P | Rh | Precipitations | Cₐ | e | eₛ | VPD | ρ | λ | γ | ε | Δ | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Dates.DateTime | Dates.Hour | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | 2026-10-01T09:30:19.183 | 1 hour | 20.0 | 1.0 | 101.3 | 0.65 | 0.0 | 400.0 | 1.52555 | 2.347 | 0.821448 | 1.20379 | 2.4537e6 | 0.0672368 | 0.584806 | 0.145734 |
| 2 | 2026-10-01T09:30:19.183 | 1 hour | 23.0 | 1.5 | 101.3 | 0.6 | 0.0 | 400.0 | 1.69211 | 2.82018 | 1.12807 | 1.19159 | 2.4466e6 | 0.0674318 | 0.592664 | 0.171147 |
| 3 | 2026-10-01T09:30:19.183 | 1 hour | 25.0 | 3.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 |
Use this series as the scene's environment and run three steps with run!(scene; steps=3, outputs=:all). PlantSimEngine reads the corresponding weather row at each step; the several-timestep tutorial shows the complete workflow.
A Weather can also be declared from a DataFrame, provided each row is an observation from a time-step, and each column is a variable needed for Atmosphere (see the help of Atmosphere for more details on the possible variables and their units).
This example uses a CSV fixture shipped with PlantMeteo. Replace its path with your own file and match the column names and units to your data.
using CSV, DataFrames, PlantMeteo
file = joinpath(pkgdir(PlantMeteo), "test", "data", "meteo.csv")
df = CSV.read(file, DataFrame; header=5, skipto = 6, dateformat = "yyyy/mm/dd")
# Preserve the start time of each observation before selecting columns:
df.date = Date.(df.date) .+ Time.(df.hour_start)
# Select and rename the variables:
select!(df, :date, :temperature => :T, :relativeHumidity => (x -> x ./ 100 ) => :Rh, :wind => :Wind, :atmosphereCO2_ppm => :Cₐ)
df[!, :duration] = fill(Minute(30), nrow(df))
# Make the weather, and add some metadata:
Weather(df, (site = "Aquiares", file = file))| TimeStepTable{Atmosphere{(:date, :duration,...}(3 x 16): | ||||||||||||||||
| date | duration | T | Wind | P | Rh | Precipitations | Cₐ | e | eₛ | VPD | ρ | λ | γ | ε | Δ | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Dates.DateTime | Dates.Minute | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | 2016-06-12T12:00:00 | 30 minutes | 25.0 | 1.0 | 101.325 | 0.6 | 0.0 | 380.0 | 1.90812 | 3.1802 | 1.27208 | 1.18389 | 2.44188e6 | 0.0675791 | 0.602345 | 0.190095 |
| 2 | 2016-06-12T12:30:00 | 30 minutes | 26.0 | 1.5 | 101.325 | 0.62 | 0.0 | 380.0 | 2.09238 | 3.37481 | 1.28243 | 1.17993 | 2.43951e6 | 0.0676446 | 0.610038 | 0.200215 |
| 3 | 2016-06-12T13:00:00 | 30 minutes | 25.3 | 1.5 | 101.325 | 0.58 | 0.0 | 380.0 | 1.87776 | 3.23752 | 1.35976 | 1.1827 | 2.44117e6 | 0.0675987 | 0.60088 | 0.193085 |
The three records retain their start times: 12:00, 12:30, and 13:00 on 12 June 2016. Keeping these timestamps makes it possible to match simulated outputs to the original measurements.
For an Archimed-ϕ-formatted CSV with metadata, read_weather handles the import directly. The column transformations below convert relative humidity from percent to a fraction and rename the weather variables:
using Dates, PlantMeteo
meteo = read_weather(
file,
:temperature => :T,
:relativeHumidity => (x -> x ./100) => :Rh,
:wind => :Wind,
:atmosphereCO2_ppm => :Cₐ,
date_format = DateFormat("yyyy/mm/dd")
)| TimeStepTable{Atmosphere{(:date, :duration,...}(3 x 24): | ||||||||||||||||||||||||
| date | duration | T | Wind | P | Rh | Precipitations | Cₐ | e | eₛ | VPD | ρ | λ | γ | ε | Δ | clearness | hour_start | hour_end | temperature | relativeHumidity | Re_SW_f | wind | atmosphereCO2_ppm | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Dates.DateTime | Dates.CompoundPeriod | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Dates.Time | Dates.Time | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | 2016-06-12T12:00:00 | 30 minutes | 25.0 | 1.0 | 101.325 | 0.6 | 0.0 | 380.0 | 1.90812 | 3.1802 | 1.27208 | 1.18389 | 2.44188e6 | 0.0675791 | 0.602345 | 0.190095 | 0.75 | 12:00:00 | 12:30:00 | 25.0 | 60.0 | 500.0 | 1.0 | 380.0 |
| 2 | 2016-06-12T12:30:00 | 30 minutes | 26.0 | 1.5 | 101.325 | 0.62 | 0.0 | 380.0 | 2.09238 | 3.37481 | 1.28243 | 1.17993 | 2.43951e6 | 0.0676446 | 0.610038 | 0.200215 | 0.75 | 12:30:00 | 13:00:00 | 26.0 | 62.0 | 500.0 | 1.5 | 380.0 |
| 3 | 2016-06-12T13:00:00 | 30 minutes | 25.3 | 1.5 | 101.325 | 0.58 | 0.0 | 380.0 | 1.87776 | 3.23752 | 1.35976 | 1.1827 | 2.44117e6 | 0.0675987 | 0.60088 | 0.193085 | 0.75 | 13:00:00 | 13:30:00 | 25.3 | 58.0 | 500.0 | 1.5 | 380.0 |
PlantMeteo also provides functions for individual weather calculations:
vapor_pressure computes e (kPa), the vapor pressure from the air temperature and the relative humidity
e_sat computes eₛ (kPa), the saturated vapor pressure from the air temperature
air_density computes ρ (kg m-3), the air density from the air temperature, the pressure, and some constants
latent_heat_vaporization computes λ (J kg-1), the latent heat of vaporization from the air temperature and a constant
psychrometer_constant computes γ (kPa K−1), the psychrometer "constant" from the air pressure, the latent heat of vaporization and some constants
atmosphere_emissivity(T,e,constants.K₀) computes ε (0-1), the atmosphere emissivity from the air temperature, the vapor pressure and a constant
PlantMeteo.e_sat_slope computes Δ (kPa K⁻¹), the slope of saturation vapour pressure with temperature
Note
All constants are found in Constants