Skip to content
Back to skills

GR4J AirGR

ASecurity

**Package**: `hydrocraft-gr4j-airgr` v1.0.0 **Model**: GR4J daily lumped rainfall-runoff model via airGR R package v1.7.8 **Created by**: Jianyun Zhang Research Group, Hohai University **Last updated**: 2026-03-25 **Stats**: 4 tools | 5 skill documents | 15+ diagnostic triplets | ~1,500 lines of validated Python **Validation status**: `production_validated` (airGR L0123001 built-in dataset) ---

  • 200 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 11, 2026
documentationpythongospringdebugginggitperformancedocumentation

Works with

  • cli

Security analysis

A100/100

Pro scans all 20 files and shows the line behind each finding

Scanned September 11, 2026

npx -y skills add lzwei196/KISS---Knowledge-Infrastructure-for-Scientific-Simulation --skill GR4J___airGR --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of GR4J AirGR?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for GR4J   AirGR
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/lzwei196-gr4j-airgr/badge)](https://www.skillsdirectory.com/skills/lzwei196-gr4j-airgr)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
> **MANDATORY EXECUTION POLICY** — READ BEFORE PROCEEDING
>
> You MUST run the **actual model binary or package** described in this document.
> If the model fails to import, compile, or execute, you MUST:
> 1. Check `diagnostics/triplets.yaml` for a matching error pattern
> 2. Try the fix suggested in the triplet's `remedy` section
> 3. If still failing, report the error to the user with full details
>
> You MUST NOT substitute a simplified Python formula, regression equation,
> or hand-coded approximation in place of the real model.
>
>
> Before starting, run: `python preflight_check.py` (in this KI directory)
> to verify that the model binary/package and required data are available.
>
> **DEBUGGING PROTOCOL** — When something goes wrong, follow this order:
> 1. **Check triplets** — `diagnostics/triplets.yaml` may already cover this error
> 2. **Read official docs** — The model's own documentation for expected formats/units
> 3. **Find working examples** — Check `outputs/` or the model's shipped test data
> 4. **Fix the tool** — With knowledge of what "correct" looks like
>
> Do NOT write custom debug scripts. The answers are in the docs and examples.

<!-- KI-MAP:BEGIN (projected by generate_skill_map.py — edit the KI, not this table) -->
## KI map — what to read, and when

| when you need | read | why |
|---|---|---|
| FIRST, always | `preflight_check.py` | run it (`python preflight_check.py`): proves env/binary/data are usable and emits a machine-readable `PREFLIGHT_REPORT=` line. Do not debug a run that never had a healthy environment. |
| to run the pipeline stages | `tools/` (4 tools) | the executable pipeline. Read each tool's argparse (`--help`) before composing a command; SKILL.md's stage table says which tool serves which stage. |
| before running a stage | `docs/s*_*.md` (5 stage docs) | per-stage procedure, verification and traps — the how-to that SKILL.md's overview compresses. |
| on ANY error, before debugging | `diagnostics/triplets.yaml` (18 entries) | symptom → diagnosis → remedy for this model's known failure modes. Check here FIRST; the answer usually exists. Never renumber or rewrite entries. |
| to know what an output IS | `dag.yaml` | the model's identity: every output's medium, units, `validation_rank` (1 = the headline variable) and observability. Scoring and obs-binding read THIS — when asked 'what does this model predict', the dag is the answer, not a guess. |
| when building inputs / parsing outputs | `docs/format_spec.yaml` | exact I/O shapes + `known_issues`, projected from dag + triplets. Regenerate with `ki_tools_common/generate_format_spec.py` after changing either — never hand-edit. |
| to judge a run's skill | `docs/validation_convention.yaml` | how this model's field judges it validated: per-`dag_variable` metrics, directions and CITED pass-bands. A run is graded against these, not against intuition. |
| for claims and thresholds | `docs/gathered_papers.json` (17 papers) + `docs/papers_index.md` | the literature this KI is judged by; each entry's `text_path` is fetched full text in the central paper cache. `role: benchmark` marks the model's own skill paper. |
| for a machine-readable summary | `knowledge_infrastructure.yaml` | the manifest (package, pipeline, validation tier, counts) — projected by `ki_tools_common/generate_ki_manifest.py`; regenerate after structural changes, never hand-edit. |

*Projected 2026-08-17 from the KI's actual contents — 9 components present. Refresh: `python3 ki_tools_common/generate_skill_map.py --ki_dir <this KI>`.*
<!-- KI-MAP:END -->

<!-- KI-TOOL-INDEX:BEGIN (projected by generate_skill_map.py — the discoverability contract: every public tool, exact path; PURPOSE stays human-authored elsewhere) -->
### Executable tool index (projected — complete by construction)

Every public tool in this KI, by exact path. What each is FOR lives in the
human-written Tool Inventory above; `--help` on any of these prints its arguments.

| tool (exact path) | invocation |
|---|---|
| `tools/convert_catchment_params.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/convert_catchment_params.py --help` |
| `tools/convert_forcing_to_gr4j.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/convert_forcing_to_gr4j.py --help` |
| `tools/parse_gr4j_output.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/parse_gr4j_output.py --help` |
| `tools/run_gr4j.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/run_gr4j.py --help` |

*4 public tools; `_`-prefixed helpers and packaging files excluded.*
<!-- KI-TOOL-INDEX:END -->

# GR4J (airGR) — Knowledge Infrastructure

**Package**: `hydrocraft-gr4j-airgr` v1.0.0
**Model**: GR4J daily lumped rainfall-runoff model via airGR R package v1.7.8
**Created by**: Jianyun Zhang Research Group, Hohai University
**Last updated**: 2026-03-25
**Stats**: 4 tools | 5 skill documents | 15+ diagnostic triplets | ~1,500 lines of validated Python
**Validation status**: `production_validated` (airGR L0123001 built-in dataset)

---

## Data Preparation

### Forcing data

**Data Sources**: Use `from ki_tools_common.load_forcing import load_daily_forcing` for CMFD/MSWX/NASA POWER.

**Data Validation Reference**: See `data_ki/CMFD/SKILL.md` for CMFD unit documentation and known traps.
See `data_ki/HWSD/SKILL.md` for soil property documentation.
See `data_ki/ObservedQ/SKILL.md` for observed discharge data.


## Overview

This knowledge infrastructure enables fully autonomous simulation of catchment rainfall-runoff processes using the GR4J model (Perrin et al., 2003) implemented in the airGR R package. The 4 validated Python tools replace manual R workflow steps with a Python pipeline that integrates directly with HydroCraft's forcing, routing, and calibration infrastructure.

**What GR4J does**: Four-parameter daily lumped conceptual hydrological model. Simulates:
- Production store: soil moisture accounting (interception, evaporation, percolation)
- Two unit hydrographs (UH1: 90% routed, UH2: 10% direct)
- Routing store: nonlinear outflow from routed branch
- Inter-catchment groundwater exchange
- Total runoff = routed flow (QR) + direct flow (QD)

**Key difference from other HydroCraft models**: GR4J operates on a lumped catchment (single spatial unit), not gridded. All inputs are catchment-average values in mm/day. It can optionally couple with CemaNeige for snow processes. The Fortran core is wrapped by R functions in airGR.

**Model Reference**: Perrin, C., Michel, C. and Andreassian, V. (2003). Improvement of a parsimonious model for streamflow simulation. Journal of Hydrology, 279(1-4), 275-289.

---

## Installation

### R Package

```
airGR v1.7.8:  CRAN package (R >= 3.5.0)
Install:       install.packages("airGR")
Source:        https://github.com/cran/airGR
Fortran core:  src/frun_GR4J.f90 (compiled via R CMD INSTALL)
```

### Dependencies (R)

```
Depends: R (>= 3.5.0)
Imports: graphics, grDevices, stats, utils
Suggests: knitr, rmarkdown, caRamel, DEoptim, testthat
```

### Python dependencies (HydroCraft tools)

```
rpy2, numpy, pandas, matplotlib
```

### Test example

```
data(L0123001)  # Built-in fictional catchment
  BasinObs:  DatesR, P [mm/d], T [degC], E [mm/d], Qls [l/s], Qmm [mm/d]
  BasinInfo: code, name, area [km2], HypsoData [m]
  Period:    1984-01-01 to 2005-12-31 (daily)
```

**Validated**: GR4J runs successfully on L0123001 data. Judge performance against
`docs/validation_convention.yaml`, not remembered thresholds.

---

## Model Parameters

GR4J has exactly **4 free parameters**:

| Parameter | Symbol | Unit | Description | Typical Range |
|-----------|--------|------|-------------|---------------|
| X1 | Prod store capacity | mm | Maximum capacity of production (soil moisture) store | 100 - 1200 |
| X2 | Exchange coefficient | mm/d | Inter-catchment groundwater exchange coefficient | -5 - 3 |
| X3 | Routing store capacity | mm | Maximum capacity of routing store | 20 - 300 |
| X4 | UH time constant | d | Time base of unit hydrographs | 1.1 - 2.9 |

### Parameter Constraints
- X1 >= 0.01 mm (enforced by RunModel_GR4J)
- X3 >= 0.01 mm (enforced by RunModel_GR4J)
- X4 >= 0.5 d (enforced by RunModel_GR4J)
- X2 can be negative (catchment loses water to groundwater)

### Parameter Transformation (for calibration)
The calibration uses transformed parameters to ensure unconstrained optimization:
- X1: log transform (real = exp(transformed))
- X2: sinh transform (real = sinh(transformed))
- X3: log transform (real = exp(transformed))
- X4: linear rescaling to [0.5, 39.5] range

---

## Pipeline (7 stages)

| # | Stage | Tool(s) | Description |
|---|-------|---------|-------------|
| 0 | Configuration | (manual) | Catchment selection, period, forcing source |
| 1 | Forcing preparation | `convert_forcing_to_gr4j` | Global forcing (CMFD/ERA5) to airGR input format (P, PE in mm/d) |
| 2 | Catchment parameters | `convert_catchment_params` | HWSD soil data + DEM to catchment properties |
| 3 | Model execution | `run_gr4j` | Run GR4J via rpy2 with warmup, calibration, simulation |
| 4 | Calibration | `run_gr4j` (calibration mode) | Calibration_Michel with NSE/KGE objective |
| 5 | Output parsing | `parse_gr4j_output` | Extract Qsim, store levels, fluxes to CSV |
| 6 | Validation | `parse_gr4j_output` (validation mode) | Compute NSE, KGE, PBIAS, plot observed vs simulated |

### Parallelism

Stages 1 and 2 can run in parallel after stage 0.
Stage 3 depends on 1 and 2.
Stage 4 depends on 3 (uses same tool with calibrate=True).
Stage 5 depends on 3 or 4.
Stage 6 depends on 5.

---

## 3. Input Requirements and I/O Specification

**Exact shapes live in `docs/format_spec.yaml`** (projected from dag + triplets;
regenerate it, never hand-edit). This section explains intent, units, and traps;
the spec file is the contract.

### Inputs (all catchment-average, daily)

| Variable | Unit | Source | Notes |
|----------|------|--------|-------|
| DatesR | POSIXt | Time series dates | Must be continuous, no gaps |
| Precip (P) | mm/day | CMFD, ERA5, gauge | Must be >= 0, no NA allowed |
| PotEvap (E) | mm/day | Oudin formula or pre-computed | Must be >= 0, no NA allowed |
| Qobs | mm/day | Gauged streamflow (for calibration) | NA values allowed |
| TempMean (T) | degC | Required only if computing PE via PE_Oudin | Mean daily air temperature |

### PE_Oudin Formula (if PotEvap not pre-computed)

```
PE_Oudin(JD, Temp, Lat, LatUnit="deg")
  JD:   Julian day of year (1-366)
  Temp: daily mean air temperature [degC]
  Lat:  catchment latitude [degrees or radians]
  Returns: PE [mm/day]
```

### Unit Conversion from CMFD to airGR

| CMFD Variable | CMFD Unit | airGR Variable | airGR Unit | Conversion |
|---------------|-----------|----------------|------------|------------|
| prec | mm/3hr | Precip | mm/day | sum 8 timesteps per day |
| temp | K | TempMean | degC | subtract 273.15 |
| shum + pres | kg/kg, Pa | PotEvap | mm/day | Use PE_Oudin(JD, T_degC, lat) |
| srad | W/m2 | (not used) | - | GR4J uses PE, not radiation directly |
| wind | m/s | (not used) | - | GR4J uses PE, not wind directly |

### Unit Conversion from Discharge

| Source | Source Unit | Target | Target Unit | Conversion |
|--------|-----------|--------|-------------|------------|
| Gauge | m3/s | Qmm | mm/day | Q_m3s * 86400 / (area_km2 * 1e6) * 1000 |
| Gauge | l/s | Qmm | mm/day | Q_ls / 1000 * 86400 / (area_km2 * 1e6) * 1000 |
| VIC routing | mm/day | Qmm | mm/day | Direct (same unit) |

---

## 6. Output Description

**Source: `dag.yaml`.** The dag is the model's identity for observable outputs:
if this section and `dag.yaml` disagree, the dag wins.

**Headline output** (the dag's `validation_rank: 1` variable):

> `Qsim` — Simulated total catchment discharge at the outlet, QR (routing branch) + QD (direct branch). (`mm/day`)

| Output variable (dag `var`) | Rank / role | Unit | Dag description |
|-----------------------------|-------------|------|-----------------|
| Qsim | 1 / headline validation output | mm/day | Simulated total catchment discharge at the outlet, QR (routing branch) + QD (direct branch). |

Other dag outputs: `AE`, `Prod`, `AExch`.

The airGR per-timestep output table below provides the operational parser names
used by the tools; `dag.yaml` remains the source of truth for validation identity,
units, observability, and rank.

---

## 8. Unit Conversion Table

The model uses catchment-average daily water depths. Every forcing and observed
discharge conversion must preserve that convention before execution or validation.

### Unit Trap Table (CRITICAL)

These unit mismatches cause **silent failures** — the model runs but produces garbage.

| Trap ID | Source | Expected by GR4J | Wrong Value | Correct Value | Symptom |
|---------|--------|-------------------|-------------|---------------|---------|
| UT-001 | CMFD temp in K | degC | 293.15 | 20.0 | PE ~300 mm/d, all water evaporates |
| UT-002 | Precip in m/day | mm/day | 0.005 | 5.0 | Near-zero runoff, extreme drought |
| UT-003 | Precip in mm/3hr not aggregated | mm/day | 2.5 (3hr value) | 20.0 (daily sum) | Runoff 1/8 of expected |
| UT-004 | Q_obs in m3/s | mm/day | 100 | 0.86 | NSE = -infinity during calibration |
| UT-005 | Q_obs in l/s not converted | mm/day | 100000 | 0.86 | Calibration fails completely |
| UT-006 | Area in m2 used for conversion | km2 expected | 1e8 | 100 | Q_mm off by factor 1e6 |
| UT-007 | PE from Penman in mm/month | mm/day | 150 | 5.0 | Store depletes instantly |
| UT-008 | Negative PE values | >= 0 | -2.0 | 0.0 | Warning, then truncation artifacts |

---

## 7. Tool Inventory

| Tool | Stage | Script Path | Lines | Purpose |
|------|-------|-------------|------:|---------|
| `convert_forcing_to_gr4j` | s1 | `tools/convert_forcing_to_gr4j.py` | ~250 | CMFD/ERA5/gauge to airGR format (P, PE in mm/d) |
| `convert_catchment_params` | s2 | `tools/convert_catchment_params.py` | ~200 | HWSD soil + DEM to catchment area, hypsometry |
| `run_gr4j` | s3-s4 | `tools/run_gr4j.py` | ~350 | Execute GR4J via rpy2 (simulation + calibration) |
| `parse_gr4j_output` | s5-s6 | `tools/parse_gr4j_output.py` | ~300 | Extract results to CSV, compute metrics, plot |

**Total**: 4 tools, ~1,100 lines of validated Python code.

---

## Skill Knowledge

| Stage | Topic | Skill Document |
|-------|-------|----------------|
| s1 | Forcing preparation, unit conversions | `docs/s1_forcing_preparation.md` |
| s2 | Catchment parameter extraction | `docs/s2_catchment_parameters.md` |
| s3 | Model execution and warmup | `docs/s3_model_execution.md` |
| s4 | Calibration procedure | `docs/s4_calibration.md` |
| s5 | Output analysis and validation | `docs/s5_output_analysis.md` |

---

## 9. Diagnostic Triplets and Critical Domain Knowledge

These non-obvious facts cause **silent failures** if violated. Each has a corresponding diagnostic triplet.

### 1. All fluxes in mm/day, NOT m3/s (dt_001)

GR4J operates entirely in mm/day (water depth equivalent over catchment area). Precipitation, potential evapotranspiration, and simulated discharge are all in mm/day. Observed discharge for calibration MUST be converted from m3/s or l/s to mm/day using: `Qmm = Q_m3s * 86400 / (area_km2 * 1e6) * 1000`. Using m3/s directly causes NSE = -infinity.

### 2. Temperature must be in Celsius for PE_Oudin (dt_002)

The PE_Oudin function expects temperature in degrees Celsius. CMFD provides temperature in Kelvin. Forgetting to subtract 273.15 causes PE values of ~300 mm/day (instead of ~5 mm/day), draining all soil moisture instantly.

### 3. Warm-up period is essential (dt_006)

GR4J has two stores (production and routing) plus unit hydrograph states. Default initialization sets production store to 30% and routing store to 50% capacity. Without a warm-up period of at least 1 year, the first months/years of simulation are unreliable. airGR auto-selects 1 year of warm-up by default.

### 4. No missing values in precipitation or PE (dt_007)

airGR does NOT allow NA values in Precip or PotEvap. Any NA causes an error. Gap-fill forcing data BEFORE creating InputsModel. Observed discharge (Qobs) CAN contain NA values.

### 5. Calibration uses transformed parameter space (dt_008)

Calibration_Michel operates in transformed parameter space (log/sinh transforms). Direct parameter values cannot be used as starting points — they must be transformed first via TransfoParam_GR4J(). The search grid covers a wide range by default.

### 6. IndPeriod must be integer type (dt_009)

R's seq() creates numeric vectors by default. IndPeriod_Run and IndPeriod_WarmUp must be integer vectors. Use `as.integer(seq(...))` or `seq.int(...)`. Non-integer indices cause a hard error.

### 7. Daily precipitation must be positive sums, not rates (dt_010)

GR4J expects daily total precipitation in mm, not instantaneous rates. When aggregating sub-daily data, SUM the values (not average). Averaging 3-hourly precipitation gives 1/8 of the correct daily total.

### 8. X4 minimum is 0.5, not 0 (dt_011)

The unit hydrograph time constant X4 has a hard floor at 0.5 days. Values below 0.5 are silently clipped with a warning. During calibration, the parameter transform ensures X4 stays in [0.5, 39.5].

---

## Model Architecture (Fortran Core)

The GR4J Fortran subroutine (`frun_GR4J.f90`) implements the following water balance:

```
For each daily time step:
  1. Net rainfall/evaporation
     If P >= E: PN = P - E, EN = 0
     If P <  E: PN = 0, EN = E - P

  2. Production store (soil moisture accounting)
     PS = fraction of PN entering store (tanh function of store level / X1)
     ES = actual evaporation from store (tanh function of EN / X1)
     Update store: S = S + PS - ES

  3. Percolation from production store
     PERC = S * (1 - (1 + (S/(9/4*X1))^4)^(-0.25))
     S = S - PERC

  4. Total effective rainfall
     PR = PN - PS + PERC

  5. Split into two branches
     PRUH1 = 0.9 * PR  (slow routed branch)
     PRUH2 = 0.1 * PR  (fast direct branch)

  6. Unit hydrograph convolution
     UH1: S-curve with time base X4 (20 ordinates max)
     UH2: S-curve with time base 2*X4 (40 ordinates max)

  7. Groundwater exchange
     EXCH = X2 * (R/X3)^3.5
     R = routing store level

  8. Routing store
     R = R + Q9 + EXCH  (Q9 = UH1 output)
     QR = R * (1 - (1 + (R/X3)^4)^(-0.25))
     R = R - QR

  9. Direct branch
     QD = max(0, Q1 + EXCH)  (Q1 = UH2 output)

  10. Total discharge
      Q = QR + QD [mm/day]
```

### State Variables (67 total)
- St(1): Production store level [mm]
- St(2): Routing store level [mm]
- StUH1(1:20): UH1 states [mm]
- StUH2(1:40): UH2 states [mm]
- 5 additional internal states

### Output Variables (18 per timestep)
| Index | Name | Description | Unit |
|-------|------|-------------|------|
| 1 | PotEvap | Input PE | mm/d |
| 2 | Precip | Input P | mm/d |
| 3 | Prod | Production store level | mm |
| 4 | Pn | Net rainfall | mm/d |
| 5 | Ps | Part filling production store | mm/d |
| 6 | AE | Actual evapotranspiration | mm/d |
| 7 | Perc | Percolation | mm/d |
| 8 | PR | Effective rainfall | mm/d |
| 9 | Q9 | UH1 outflow | mm/d |
| 10 | Q1 | UH2 outflow | mm/d |
| 11 | Rout | Routing store level | mm |
| 12 | Exch | Potential exchange | mm/d |
| 13 | AExch1 | Actual exchange branch 1 | mm/d |
| 14 | AExch2 | Actual exchange branch 2 | mm/d |
| 15 | AExch | Total actual exchange | mm/d |
| 16 | QR | Routing store outflow | mm/d |
| 17 | QD | Direct flow after exchange | mm/d |
| 18 | Qsim | Simulated discharge | mm/d |

---

## Calibration

### Calibration_Michel Algorithm
1. **Grid screening**: Test predefined parameter combinations on a coarse grid
2. **Steepest descent**: Local search from best grid point, with adaptive step size
3. **Convergence**: Step size shrinks until < 0.01 in transformed space

### Available Criteria
| Criterion | Function | Best Value | Use Case |
|-----------|----------|------------|----------|
| NSE | ErrorCrit_NSE | 1.0 | General flow simulation |
| KGE | ErrorCrit_KGE | 1.0 | Balanced bias/correlation/variability |
| KGE2 | ErrorCrit_KGE2 | 1.0 | Modified KGE (CV ratio) |
| RMSE | ErrorCrit_RMSE | 0.0 | Absolute error |

### Typical Calibrated Values (literature)
| Catchment Type | X1 [mm] | X2 [mm/d] | X3 [mm] | X4 [d] |
|---------------|---------|-----------|---------|--------|
| Humid temperate | 200-500 | 0.5-2.0 | 50-150 | 1.5-2.5 |
| Semi-arid | 500-1200 | -2.0-1.0 | 100-300 | 1.5-3.0 |
| Tropical wet | 100-400 | 1.0-3.0 | 20-100 | 1.0-2.0 |

---

## 11. Validated Results

### Test Basin

| Property | Value |
|----------|-------|
| Dataset | airGR `L0123001` built-in dataset |
| Period | 1984-01-01 to 2005-12-31 (daily) |
| Status | GR4J executes successfully on the built-in dataset |

### Performance Metrics — judged against the field's bar, not intuition

**Source: `docs/validation_convention.yaml`.** The bars below restate the
convention file. Do not substitute uncited thresholds.

| Dag variable | Metric | Direction | Convention bar, cited |
|--------------|--------|-----------|-----------------------|
| Qsim | nse | maximize | very_good >= 0.75 (`moriasi2007`, `moriasi2015`); good >= 0.65 (`moriasi2007`, `moriasi2015`); satisfactory >= 0.5 (`moriasi2007`, `moriasi2015`) |
| Qsim | pbias | zero_centered | very_good <= +/-10 (`moriasi2007`, `moriasi2015`); good <= +/-15 (`moriasi2007`, `moriasi2015`); satisfactory <= +/-25 (`moriasi2007`, `moriasi2015`) |
| AE | nse | maximize | satisfactory: no cited threshold |
| Prod | r | maximize | satisfactory: no cited threshold |

`Qsim` is the rank-1 validation output from `dag.yaml`; `AE`, `Prod`, and
`AExch` are additional dag outputs. A reported run should include achieved metric
values separately and compare them to the cited bars above.

---

## CemaNeige Snow Module (Optional)

For snow-affected catchments, GR4J can be coupled with CemaNeige:
- Function: `RunModel_CemaNeigeGR4J`
- Additional parameters: 2 (CTG: degree-day factor, Kf: snowpack inertia)
- Additional inputs: TempMean [degC], HypsoData [m], ZInputs [m]
- Total parameters when coupled: 6 (4 GR4J + 2 CemaNeige)

**WIRED INTO `run_gr4j.py` (use `--snow`).** For any cold-region / snowmelt-driven
catchment (winter precip falls as snow, hydrograph driven by a spring/summer
freshet), run with `--snow` (alias for `--model cemaneige_gr4j`). The CemaNeige
variant needs the `TempMean_degC` column (written by `convert_forcing_to_gr4j` by
default) and runs as a single elevation layer if no HypsoData is supplied.

**WHY IT MATTERS (HYDAT 08NH120 Moyie R., BC, 2026-06-23):** plain GR4J on this
alpine snowmelt basin calibrated to NSE 0.14 only, with X2 forced to +7.3 mm/d
(far outside the typical −5..3 range) to import phantom groundwater faking the
spring freshet. Adding `--snow` lifted calibration NSE to 0.80 / validation 0.77
and returned X2 to a physical +0.34. Diagnostic tell: if your best-fit X2 is large
and you're on a cold catchment, you are missing snow — switch to `--snow`.
Calibration example (6-param, CemaNeige adds X5=CTG, X6=Kf):
```
run_gr4j.py --forcing forcing_gr4j.csv --output sim.csv --mode calibration --snow \
            --start 2006-01-01 --end 2010-12-31 --criterion NSE --meta-json p.json
# then simulate with the calibrated 6 params: --mode simulation --snow --x1..--x6
```

**ELEVATION LAYERS (`--hypso-json`, added 2026-07-13, Lancang 允景洪):** by default
CemaNeige runs as a SINGLE elevation layer at the forcing elevation, which smears
snow across the full relief. For high-relief basins (>1500 m relief — e.g. the
Lancang at Jinghong spans ~550-5,500 m), pass the catchment-params JSON written by
`convert_catchment_params` (must contain the 101-point `hypsometry` array from the
basin-masked DEM): `--snow --hypso-json catchment_params.json [--nlayers 5]`.
airGR then extrapolates T and P over the elevation bands
(DataAltiExtrapolation_Valery) with ZInputs = median(HypsoData), so only the cold
fraction of the basin accumulates snow. Ascending, exactly-101-value hypsometry is
enforced by the tool.

---

## References

- Perrin, C., Michel, C. and Andreassian, V. (2003). Improvement of a parsimonious model for streamflow simulation. Journal of Hydrology, 279(1-4), 275-289.
- Oudin, L., Hervieu, F., Michel, C., Perrin, C., Andreassian, V., Anctil, F. and Loumagne, C. (2005). Which potential evapotranspiration input for a lumped rainfall-runoff model? Part 2. Journal of Hydrology, 303(1-4), 290-306.
- Valery, A., Andreassian, V. and Perrin, C. (2014). As simple as possible but not simpler: What is useful in a temperature-based snow-accounting routine? Journal of Hydrology, 517, 1176-1187.

Files in this skill

  • SKILL.md24 KB
  • dag.yaml23.9 KB
  • diagnostics/triplets.yaml19.1 KB
  • docs/REFERENCES.md2 KB
  • docs/format_spec.yaml19.6 KB
  • docs/papers.json4.9 KB
  • docs/s1_forcing_preparation.md3.7 KB
  • docs/s2_catchment_parameters.md3.6 KB
  • docs/s3_model_execution.md4.1 KB
  • docs/s4_calibration.md4.4 KB
  • docs/s5_output_analysis.md4.4 KB
  • docs/validation_convention.yaml10.3 KB
  • knowledge_infrastructure.yaml2.1 KB
  • preflight_check.py7.5 KB
  • run_and_score_hydat_08MH001.py9.4 KB
  • run_and_score_ruhr.py6.2 KB
  • tools/convert_catchment_params.py9.4 KB
  • tools/convert_forcing_to_gr4j.py16.1 KB
  • tools/parse_gr4j_output.py11.2 KB
  • tools/run_gr4j.py20.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…