Skip to main content

GRsuite

An unofficial, independent Python port of the airGR suite of GR rainfall-runoff models — a personal project, checked value by value against airGR.

This is not an official package, and it is not airGR. GRsuite is one person's work, developed independently and on personal time. It is not produced, endorsed, reviewed or supported by INRAE, and it carries no institutional guarantee. The models, the science and the reference implementation belong to INRAE's HYCAR unit; what is mine is the translation into Python and the mistakes in it.

If your work needs the reference implementation, use airGR — and please report problems found here to this repository's issue tracker, never to the airGR maintainers.

unofficial port tests PyPI Python License: GPL v2 validated against airGR 1.7.9

GR4J, GR5J, GR6J, GR2M, GR1A, GR4H, GR5H and the CemaNeige snow module — the models hydrologists have been running in R for twenty years, now in Python with no R dependency, no Fortran toolchain, and no reimplementation risk.

Every model output, every criterion and every calibrated parameter set in this package has been checked against airGR 1.7.9 itself: 502 quantities — 1.23 million individual values — agree to 2 × 10⁻¹³, and across 500 calibrations on 100 French catchments the largest deviation is 1.9 × 10⁻¹³.

pip install grsuite

Sixty seconds

import grsuite as gr

catchment = gr.Catchment(dates, precip=P, pot_evap=E, obs_discharge=Q)

fit = catchment.calibrate("GR4J", period=("2000-01-01", "2009-12-31"))
print(fit.describe())

check = fit.evaluate(period=("2010-01-01", "2019-12-31"))
print(check.nse(), check.kge())
GR4J calibrated on KGE = 0.8694
  X1       170.7158   production store capacity [mm]
  X2         0.5897   groundwater exchange coefficient [mm/step]
  X3        78.2571   routing store capacity [mm]
  X4         2.2568   unit hydrograph time constant [step]
  17 iterations, 202 model runs
0.799 0.776

A split-sample test is one call:

fit, validation = catchment.split_sample(
    "GR6J",
    calibration=("2000-01-01", "2009-12-31"),
    validation=("2010-01-01", "2019-12-31"),
    criterion="KGE",
)

Snow, on five elevation bands, needs only temperature and a hypsometric curve:

alpine = gr.Catchment(dates, precip=P, pot_evap=E, obs_discharge=Q,
                      temperature=T, hypsometry=elevation_quantiles)
fit = alpine.calibrate("CemaNeigeGR4J")

Every internal flux is available, under airGR's own names:

sim = fit.simulate()
sim.to_dataframe()[["Qobs", "Qsim", "Prod", "Rout", "Perc", "Exch"]]
sim.plot(log=True)

Why this exists

airGR is the reference implementation of the GR models: careful, peer-reviewed, maintained at INRAE. Its one constraint is that it lives in R. Python users have had to choose between calling R over a bridge, or trusting a reimplementation nobody checked.

GRsuite removes that choice. It was written by translating airGR's Fortran kernels and R logic line by line, and it is continuously verified against airGR's own outputs, which ship with the test suite. If GRsuite and airGR ever disagree, CI fails.

Same numbers 502 quantities compared value by value against airGR — every internal variable, not just discharge
Same calibration Michel's algorithm reproduced step for step — identical iteration counts on 500 calibrations
No R needed pure Python + NumPy, JIT-compiled with Numba
Faster 3.2× quicker than airGR on the same 500 calibrations
Actually usable a one-line calibration API on top of the faithful airGR-mirroring one

What is covered

Component Models and functions Published as
Daily GR4J, GR5J, GR6J Perrin et al. (2003); Le Moine (2008); Pushpalatha et al. (2011)
Hourly GR4H, GR5H (with or without the interception store) Mathevet (2005); Ficchì (2017); Ficchì et al. (2019)
Monthly / annual GR2M, GR1A Mouelhi et al. (2006a, 2006b)
Snow CemaNeige, with or without linear hysteresis Valéry (2010); Valéry et al. (2014); Riboust et al. (2019)
Coupled CemaNeige + GR4J / GR5J / GR6J / GR4H / GR5H as above
Evapotranspiration Oudin formula Oudin et al. (2005)
Elevation bands Valéry extrapolation, daily temperature gradients Valéry (2010)
Criteria NSE, KGE, KGE′, RMSE, weighted composites Nash & Sutcliffe (1970); Gupta et al. (2009); Kling et al. (2012)
Transformations sqrt, log, inv, sort, boxcox, powers Santos et al. (2018)
Calibration Michel's algorithm (grid screening then steepest descent) Michel (1991)
Utilities time-series aggregation, semi-distributed routing, interception capacity Lobligeois (2014); Ficchì et al. (2019)

Full bibliographic entries, with DOIs, are in docs/REFERENCES.md.

CreateErrorCrit_GAPX (de Lavenne et al., 2019) and airGR's plotting helpers are the only pieces left out. GR6H does not exist in airGR 1.7.9, so it does not exist here either.


Validation

Measured agreement against the 5 % requirement

The brief was to stay within 5 %. The measured agreement is eleven orders of magnitude better than that, and sits at the precision limit of the reference files themselves.

500 calibrations

Across 500 independent calibrations — five model configurations on 100 CAMELS-FR catchments — 34 parameter sets came out bit-identical to airGR's, and the rest differ only in the last significant digit of a double.

Read the full validation report →

Two implementation details decide whether a re-implementation of airGR is merely correct or actually identical. Both are documented in docs/FIDELITY.md; the short version is that airGR's Fortran evaluates 0.9 in single precision before promoting it, and that its automatic warm-up period carries a leap-year correction. Miss either and your discharge is off by 2.4 × 10⁻⁷ or 3 × 10⁻⁶ respectively.


Two APIs, on purpose

The high-level one — for getting work done.

catchment = gr.Catchment(dates, precip=P, pot_evap=E, obs_discharge=Q)
fit = catchment.calibrate("GR6J", criterion="KGE", transfo="sqrt")

The faithful one — a direct translation of airGR, function by function, for porting an existing R workflow without rethinking it.

inputs = gr.InputsModel(dates, precip=P, pot_evap=E)
options = gr.RunOptions(inputs, "GR4J", ind_period_run=index)
crit = gr.InputsCrit("NSE", obs=Q[index])
result = gr.calibration_michel(inputs, options, crit, gr.CalibOptions("GR4J"))

The mapping from every airGR function to its GRsuite counterpart is in docs/MIGRATING_FROM_AIRGR.md.


Examples

File What it shows
examples/01_simulate.py Run GR4J with known parameters, inspect the internal fluxes
examples/02_calibrate.py Calibrate, then validate on an independent period
examples/03_compare_models.py GR4J vs GR5J vs GR6J on the same catchment
examples/04_snow.py CemaNeige on elevation bands, snow pack dynamics
examples/05_hourly.py GR4H and GR5H with an interception store
examples/06_low_flows.py Objective functions for low-flow performance
examples/07_semi_distributed.py Routing upstream sub-catchments to an outlet
examples/08_from_csv.py Going from a plain CSV to a calibrated model

All of them run against the demonstration catchment shipped in tests/data, so they work straight after a clone.


Installation

pip install grsuite            # runtime: numpy, numba
pip install "grsuite[io]"      # adds pandas for the DataFrame helpers

From source:

git clone https://github.com/Najim33/GRsuite
cd GRsuite
pip install -e ".[dev]"
pytest

Python 3.9 to 3.13, on Linux, macOS and Windows.


Performance

The kernels are JIT-compiled by Numba, so the first call to a model pays a compilation cost of a second or two and everything afterwards runs at compiled speed. Recompilation is cached on disk between sessions.

On the 500-calibration benchmark (5 configurations × 100 catchments, 20 years of daily data each):

Wall clock
airGR 1.7.9 (R + Fortran) 17.5 min
GRsuite (Python + Numba) 5.4 min

Same parameters, same criteria, same iteration counts.


Citing

GRsuite introduces no new hydrology. The models, the calibration algorithm and the reference implementation belong to their authors, at Cemagref / Irstea / INRAE. If GRsuite supports published work, cite airGR:

Coron, L., Thirel, G., Delaigue, O., Perrin, C., Andréassian, V. (2017). The suite of lumped GR hydrological models in an R package. Environmental Modelling & Software, 94, 166–171. doi:10.1016/j.envsoft.2017.05.002

Coron, L., Delaigue, O., Thirel, G., Dorchies, D., Perrin, C., Michel, C. airGR: Suite of GR Hydrological Models for Precipitation-Runoff Modelling. R package version 1.7.9, INRAE, HYCAR Research Unit, Antony, France. doi:10.15454/EX11NA

and the model you actually ran — GR4J is Perrin et al. (2003), CemaNeige is Valéry (2010), and so on. Every one of them, with its DOI, is listed in docs/REFERENCES.md.

If the port itself is relevant to your methods, cite this repository too — see CITATION.cff.


Contributing

Bug reports, models, criteria and examples are all welcome. The one hard rule: anything that changes model numerics must keep the airGR comparison tests green. See CONTRIBUTING.md.


Licence

GPL-2.0-or-later. GRsuite is a derivative work of airGR (INRAE, GPL-2) and carries the same licence — see NOTICE for the full attribution.

GRsuite is an independent, unofficial project. It is not produced, endorsed or supported by INRAE, and it is not a release of airGR.

Ce README existe aussi en français.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

grsuite-1.0.0.tar.gz (61.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

grsuite-1.0.0-py3-none-any.whl (55.9 kB view details)

Uploaded Python 3

File details

Details for the file grsuite-1.0.0.tar.gz.

File metadata

  • Download URL: grsuite-1.0.0.tar.gz
  • Upload date:
  • Size: 61.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for grsuite-1.0.0.tar.gz
Algorithm Hash digest
SHA256 6d234494a95d754a67a0993c47794415830b86a329b4ee92231d5924a0e2287e
MD5 0d0a86354a9a6123951eabbbf92c3038
BLAKE2b-256 860d02ea55086ddb96078d3b4f2dd0144e1151e8c07e18d624a81e7305217683

See more details on using hashes here.

Provenance

The following attestation bundles were made for grsuite-1.0.0.tar.gz:

Publisher: release.yml on Najim33/GRsuite

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file grsuite-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: grsuite-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 55.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for grsuite-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a2f5e133297328940a8773808d06dfa4be55588ae9915b0b70e84bdbac857bed
MD5 5850a4717942924fcc898c717f457e0b
BLAKE2b-256 c1304b9092e87f24c5bd87570e6e0a996c6627fb1611c88fdd3cfb6b9ce4810f

See more details on using hashes here.

Provenance

The following attestation bundles were made for grsuite-1.0.0-py3-none-any.whl:

Publisher: release.yml on Najim33/GRsuite

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page