Installs into .claude/skills of the current project.
Are you the author of HydroCNHS?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/lzwei196-hydrocnhs)
> **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/` (5 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` (6 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` (10 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/build_model_config.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/build_model_config.py --help` |
| `tools/convert_climate_inputs.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/convert_climate_inputs.py --help` |
| `tools/convert_parameters.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/convert_parameters.py --help` |
| `tools/parse_output.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/parse_output.py --help` |
| `tools/run_hydrocnhs.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/run_hydrocnhs.py --help` |
*5 public tools; `_`-prefixed helpers and packaging files excluded.*
<!-- KI-TOOL-INDEX:END -->
# HydroCNHS Knowledge Infrastructure
**Package**: HydroCNHS KI v1.0
**Model**: HydroCNHS v1.2.1
**Domain**: Hydrology — Coupled Natural-Human Systems
**Created**: 2026-03-25
**Validation**: Tualatin River Basin (TRB), Oregon, USA (1981–2013)
| Metric | Value |
|--------|-------|
| Tools | 5 |
| Pipeline stages | 8 |
| Diagnostic triplets | 18 |
| Skill documents | 6 |
| Validation basin | TRB, Oregon |
---
## 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.
## 1. Overview
HydroCNHS is a Python package for simulating **Coupled Natural-Human Systems** in water
resource management. It integrates semi-distributed hydrological modeling (rainfall-runoff
+ Lohmann routing) with agent-based modeling (ABM) for human decision-making. The model
operates on a **daily time step** and supports two rainfall-runoff schemes (GWLF and ABCD),
Lohmann routing, and four ABM APIs (Dam, RiverDiv, Conveying, InSitu).
Key capabilities:
- Semi-distributed hydrological simulation at daily resolution
- Pluggable rainfall-runoff models (GWLF: 9 params, ABCD: 5 params)
- Lohmann routing with 4 parameters per link
- Agent-based modeling for dams, diversions, aqueducts, and in-situ modifications
- Built-in genetic algorithm (DEAP) calibration with parallel computing
- Evaluation indicators: NSE, KGE, iKGE, iNSE, r, r², RMSE, RSR, Cp
The model is entirely Python-based (no compiled binaries). Execution is via the
Python API: `model = hydrocnhs.Model("model.yaml"); model.run(temp, prec, pet)`.
---
## 2. Installation
```bash
# Create virtual environment
python3 -m venv venv && source venv/bin/activate
# Install from source
cd source/repo && pip install -e .
# Or from PyPI
pip install hydrocnhs
```
**Dependencies**: joblib, matplotlib, numpy, pandas, ruamel.yaml, scipy,
scikit-learn, tqdm, pyyaml, deap
**Python versions**: 3.10, 3.11, 3.12
**Quick test**:
```python
import hydrocnhs
print(hydrocnhs.__version__) # 1.2.1
```
---
## 3. Pipeline
The HydroCNHS pipeline has 8 stages from data preparation through validation.
| # | Stage | Tool | Input | Output |
|---|-------|------|-------|--------|
| S0 | Basin setup | — | GIS/literature | Subbasin areas, latitudes, flow lengths |
| S1 | Climate data prep | `convert_climate_inputs.py` | Global gridded data (ERA5, CMIP) | `temp_dict`, `prec_dict` [°C, cm/day] |
| S2 | Parameter estimation | `convert_parameters.py` | Soil/land-use data | Initial GWLF/ABCD params in YAML |
| S3 | Model config build | `build_model_config.py` | Basin geometry + params | `model.yaml` |
| S4 | ABM setup | — | Operational rules, literature | ABM module `.py` file |
| S5 | Model execution | `run_hydrocnhs.py` | `model.yaml` + climate dicts | `Q_routed` [cms] |
| S6 | Calibration | `run_hydrocnhs.py` | Observed streamflow + bounds | Calibrated `model.yaml` |
| S7 | Output analysis | `parse_output.py` | `Q_routed`, observed data | CSV + metrics + plots |
---
## 4. Unit Trap Table
These are the **critical unit conversions** that cause silent failures if violated.
Every value must match the model's internal expectations exactly.
| Variable | Model expects | Common source unit | Conversion | Trap ID |
|----------|--------------|-------------------|------------|---------|
| Precipitation | **cm/day** | mm/day (ERA5, CMIP) | ÷ 10 | dt_001 |
| Precipitation | **cm/day** | kg/m²/s (CMIP) | × 86400 ÷ 10 | dt_002 |
| Temperature | **°C** | K (CMIP, ERA5) | − 273.15 | dt_003 |
| PET | **cm/day** | mm/day | ÷ 10 | dt_004 |
| Subbasin area | **ha** | km² | × 100 | dt_005 |
| Subbasin area | **ha** | m² | ÷ 10000 | dt_006 |
| Flow length | **m** | km | × 1000 | dt_007 |
| Latitude | **decimal degrees** | DMS | convert properly | dt_008 |
| Discharge (output) | **cms** (m³/s) | — | native output unit | — |
| Soil water capacity (Ur) | **cm** | mm | ÷ 10 | dt_009 |
| Snowmelt coeff (Df) | **cm/°C** | mm/°C | ÷ 10 | dt_010 |
| Wave velocity | **m/s** | km/h | × 1000/3600 | dt_011 |
| Diffusivity | **m²/s** | — | native | — |
**Rule**: If your simulated discharge is 10× too high or too low, check precipitation
units first. This is the #1 cause of failed HydroCNHS runs.
---
## 8. Unit Conversion Table
Exact I/O shapes live in `docs/format_spec.yaml`; unit traps and remedies live in
`diagnostics/triplets.yaml`. This unit table documents the model-facing conversions used by
the pipeline and keeps trap ids only where the KI has a corresponding diagnostic.
| Variable | Source unit (verified) | Model unit | Factor / conversion | Type | Trap ID |
|----------|------------------------|------------|---------------------|------|---------|
| Precipitation | `mm/day` | `cm/day` | divide by 10 | multiplicative | `dt_001` |
| Precipitation | `kg/m^2/s` | `cm/day` | multiply by 86400, then divide by 10 | multiplicative | `dt_002` |
| Temperature | `K` | `degC` | subtract 273.15 | additive | `dt_003` |
| PET | `mm/day` | `cm/day` | divide by 10 | multiplicative | `dt_004` |
| Subbasin area | `km^2` | `ha` | multiply by 100 | multiplicative | `dt_005` |
| Subbasin area | `m^2` | `ha` | divide by 10000 | multiplicative | `dt_006` |
| Flow length | `km` | `m` | multiply by 1000 | multiplicative | `dt_007` |
| Date strings | `YYYY-MM-DD` | `YYYY/M/D` | replace hyphens with slashes | format | `dt_008` |
| Soil water capacity (`Ur`) | `mm` | `cm` | divide by 10 | multiplicative | `dt_009` |
| Snowmelt coefficient (`Df`) | `mm/degC` | `cm/degC` | divide by 10 | multiplicative | `dt_010` |
| Wave velocity (`Velo`) | `km/h` | `m/s` | multiply by 1000/3600 | multiplicative | `dt_011` |
| Discharge output (`Q_routed`) | native model output | `cms (m^3/s)` | no conversion | native | — |
| Local runoff output (`Q_runoff`) | native model output | `cms (m^3/s)` | no conversion | native | — |
| Hamon PET output (`pet`) | native model output | `cm/day` | no conversion | native | — |
| Monthly sediment output (`TSS_monthly`) | native model output | `Mg` | no conversion | native | — |
**Output unit verification checklist**:
- Read the dag before post-processing: `Q_routed` is `cms (m^3/s)`.
- Print the first 10 output values and confirm the expected order of magnitude.
- For discharge, compare absolute flow in `m^3/s`, not depth per subbasin.
- For PET and runoff-generation diagnostics, confirm whether values are forcing inputs or model outputs.
---
## 5. Tools Reference
| Tool | Stage | Script | Purpose |
|------|-------|--------|---------|
| Climate converter | S1 | `tools/convert_climate_inputs.py` | ERA5/CMIP → temp[°C], prec[cm/day] dicts |
| Parameter converter | S2 | `tools/convert_parameters.py` | Soil/land-use → GWLF/ABCD initial params |
| Model config builder | S3 | `tools/build_model_config.py` | Generate model.yaml from basin geometry |
| Execution wrapper | S5–S6 | `tools/run_hydrocnhs.py` | Run model or calibration |
| Output parser | S7 | `tools/parse_output.py` | Extract Q_routed to CSV + compute metrics |
All tools follow the **validate → process → validate** pattern:
1. Parse CLI arguments with `argparse`
2. Validate all inputs (check files exist, units plausible, ranges correct)
3. Process (convert, build, run, parse)
4. Validate outputs (check results exist, values in expected range)
5. Return JSON: `{"status": "success/error", "output": {...}, "log": [...]}`
---
## 6. Output Description (sourced from `dag.yaml`)
The source of truth for model outputs is `dag.yaml`. This section restates the dag; if
this section and the dag disagree, the dag wins.
**Headline output** (the dag's `validation_rank: 1` variable):
> `Q_routed` — Daily routed streamflow at routing/gauged outlets (and dam-agent inflow outlets); the primary return of Model.run(). (`cms (m^3/s)`)
Other dag outputs: `Q_runoff`, `pet`, `TSS_monthly`, `ABM_agent_records`.
| Output variable (dag `var`) | Rank | Emitted in | Unit | Description |
|-----------------------------|------|------------|------|-------------|
| `Q_routed` | 1 | `model.dc.Q_routed[outlet]` (data collector) | `cms (m^3/s)` | Daily routed streamflow at routing/gauged outlets (and dam-agent inflow outlets); the primary return of Model.run(). |
| `Q_runoff` | 2 | `model.dc.Q_runoff[outlet]` (data collector) | `cms (m^3/s)` | Local unrouted subbasin runoff (also exposed as Q_local) before Lohmann routing. |
| `pet` | 3 | `model.dc.pet[outlet]` (data collector) | `cm/day` | Hamon-computed potential evapotranspiration (atmospheric water demand) when PET is not supplied as input. |
| `TSS_monthly` | 4 | `model.dc TSS field` (data collector, sediment mode) | `Mg` | Monthly routed total suspended sediment (sediment mode only). |
| `ABM_agent_records` | 5 | `model.dc.<user-defined field>` (data collector) | `varies (storage volume, diversion volume)` | Agent-specific water-management outputs (e.g., reservoir storage, diversion volume; bookkeeping records, not a single field observable) recorded by user-defined ABM modules via the shared data collector. |
**Scoring caveats for `Q_routed` from the dag**:
- Exclude a 1-2 yr warm-up before scoring so soil/groundwater/snow stores equilibrate.
- Align simulated and observed on the date index, not array position; a 1-day offset destroys correlation in flashy basins.
- Regulated reaches require the corresponding ABM agents configured or the comparison conflates natural and human signals.
---
## 6b. Critical Domain Knowledge
These facts are non-obvious and cause **silent failures** if violated:
1. **Precipitation must be in cm/day** (dt_001, dt_002). Most global datasets
provide mm/day or kg/m²/s. Forgetting the ÷10 conversion is the single most
common error. The model will run without error but discharge will be 10× wrong.
2. **PET is auto-calculated if not provided** (Hamon method). The Hamon PET
uses latitude and temperature. If you provide PET, it must be in cm/day.
If PET values seem too high, check if you passed mm/day by mistake.
3. **Area must be in hectares** (dt_005, dt_006). The GWLF runoff-to-discharge
conversion uses area in ha. If you pass km², discharge will be 100× too low.
4. **CN2 sensitivity** — The SCS Curve Number (CN2, range 25–100) is the most
sensitive GWLF parameter. A change of ±5 can shift peak discharge by 30–50%.
Always calibrate CN2 first.
5. **Routing parameters interact** — GShape/GScale control within-subbasin UH
shape, while Velo/Diff control between-subbasin wave propagation. Calibrating
them separately can lead to equifinality. Calibrate jointly.
6. **ABM agent execution order matters** — Agents are executed in priority order
(low number = first). Dam releases affect downstream diversions. If priorities
are wrong, water balance violations occur silently.
7. **Calibration uses -99 sentinel** — Parameters set to -99 in the YAML are
marked for calibration. If you forget to set bounds for a -99 parameter,
the GA will use default bounds which may not suit your basin.
8. **Date format must be YYYY/M/D** — The model expects "1981/1/1" not
"1981-01-01". Using the wrong format causes a silent parse failure.
9. **Data length must match date range** — The `DataLength` field in YAML must
equal the number of days between StartDate and EndDate (inclusive). A mismatch
causes index errors or silent truncation.
---
## 7. GWLF Parameters (per subbasin)
| Parameter | Symbol | Unit | Range | Sensitivity | Description |
|-----------|--------|------|-------|-------------|-------------|
| Curve Number | CN2 | — | [25, 100] | Very High | SCS runoff curve number |
| Interception | IS | — | [0, 0.5] | Medium | Fraction of precip intercepted |
| Recession | Res | — | [0.001, 0.5] | High | Baseflow recession coefficient |
| Deep seepage | Sep | — | [0, 0.5] | Low | Fraction to deep aquifer |
| Baseflow | Alpha | — | [0, 1] | High | Groundwater discharge rate |
| Percolation | Beta | — | [0, 1] | Medium | Unsaturated zone percolation |
| Soil water | Ur | cm | [1, 15] | High | Available water capacity |
| Snowmelt | Df | cm/°C | [0, 1] | Medium | Degree-day coefficient |
| Land cover | Kc | — | [0.5, 1.5] | Medium | Crop/vegetation coefficient |
---
## 8. ABCD Parameters (per subbasin)
| Parameter | Symbol | Unit | Range | Sensitivity | Description |
|-----------|--------|------|-------|-------------|-------------|
| Runoff ctl | a | — | [0, 1] | High | Controls runoff during unsaturation |
| Saturation | b | cm | [0, 400] | High | Maximum soil water storage |
| Recharge | c | — | [0, 1] | Medium | Groundwater recharge fraction |
| Discharge | d | — | [0, 1] | Medium | Groundwater discharge rate |
| Snowmelt | Df | cm/°C | [0, 1] | Medium | Degree-day coefficient |
---
## 9. Lohmann Routing Parameters (per link)
| Parameter | Symbol | Unit | Range | Description |
|-----------|--------|------|-------|-------------|
| UH shape | GShape | — | [1, 100] | Gamma distribution shape |
| UH scale | GScale | — | [0.01, 150] | Gamma distribution scale |
| Wave velocity | Velo | m/s | [0.5, 55] | Saint-Venant celerity |
| Diffusivity | Diff | m²/s | [200, 4000] | Saint-Venant diffusion |
---
## 11. Validated Results
**Basin**: Tualatin River Basin (TRB), Oregon, USA
**Period**: 1981/1/1 – 2013/12/31 (33 years, 12,053 days)
**Subbasins**: 7 (HaggIn, TRTR, DLLO, TRGC, DAIRY, RCTV, WSLO)
**Model**: GWLF + Lohmann routing + ABM (reservoir + diversion + pipe)
### Performance Metrics — judged against `docs/validation_convention.yaml`
No new body-campaign achieved values are asserted in this edit. Calibration,
validation, and full-period achieved values remain pending unless produced by a
model run and scored against the bars below.
| Dag variable | Obs shape | Metric | Direction | Convention bar (cited per band) | Calibration | Validation | Full period |
|--------------|-----------|--------|-----------|----------------------------------|-------------|------------|-------------|
| `Q_routed` | `point_time_series` | `nse` | maximize | satisfactory >= 0.5 [`moriasi_repro_nh2017`, `arnold2012`, `mikeswat2014`]; good >= 0.65 [`moriasi_repro_nh2017`, `arnold2012`, `mikeswat2014`]; very_good >= 0.75 [`moriasi_repro_nh2017`, `arnold2012`, `mikeswat2014`] | pending body campaign | pending body campaign | pending body campaign |
| `Q_routed` | `point_time_series` | `pbias` | zero_centered | very_good \|PBIAS\| <= 10 [`moriasi_repro_nh2017`, `mikeswat2014`]; good \|PBIAS\| <= 15 [`moriasi_repro_nh2017`, `mikeswat2014`]; satisfactory \|PBIAS\| <= 25 [`moriasi_repro_nh2017`, `mikeswat2014`] | pending body campaign | pending body campaign | pending body campaign |
| `Q_routed` | `point_snapshot` | `pbias` | zero_centered | very_good \|PBIAS\| <= 10 [`moriasi_repro_nh2017`]; good \|PBIAS\| <= 15 [`moriasi_repro_nh2017`]; satisfactory \|PBIAS\| <= 25 [`moriasi_repro_nh2017`] | pending body campaign | pending body campaign | pending body campaign |
| `Q_runoff` | `point_time_series` | `nse` | maximize | satisfactory >= 0.5 [`moriasi_repro_nh2017`, `arnold2012`]; good >= 0.65 [`moriasi_repro_nh2017`, `arnold2012`]; very_good >= 0.75 [`moriasi_repro_nh2017`, `arnold2012`] | pending body campaign | pending body campaign | pending body campaign |
**Legacy body note already present in this SKILL**: calibrated performance at WSLO outlet (monthly):
- KGE ≈ 0.80–0.90
- NSE ≈ 0.75–0.85
- r ≈ 0.90–0.95
Key findings:
1. CN2 ranges 46–99 across subbasins, reflecting diverse land use
2. Routing velocity 8.6–48 m/s, diffusivity 295–3847 m²/s
3. ABM agents critical for reproducing regulated flow at WSLO
4. Warm-up period of 1–2 years recommended before evaluation
---
## 11. Coupling Points
HydroCNHS couples with external systems through its ABM APIs:
| API | Direction | What it controls |
|-----|-----------|-----------------|
| Dam API | Instream | Reservoir releases, storage |
| RiverDiv API | Off-stream | Irrigation diversions, return flows |
| Conveying API | Inter-basin | Aqueducts, pipelines, pumps |
| InSitu API | Within-basin | Groundwater extraction, urbanization |
---
## 12. Data Requirements
| Data | Source | Unit | Required |
|------|--------|------|----------|
| Daily temperature | ERA5, station | °C | Yes |
| Daily precipitation | ERA5, station | cm/day | Yes |
| Daily PET | Calculated or station | cm/day | Optional |
| Subbasin areas | GIS | ha | Yes |
| Subbasin latitudes | GIS | decimal degrees | Yes |
| Flow lengths | GIS | m | Yes |
| Observed streamflow | USGS, gauge | cms | For calibration |
| Soil/land-use | SSURGO, NLCD | varies | For initial params |
---
## 13. Quick Start
```python
import hydrocnhs
import pickle
# Load climate data
with open("TRB_inputs.pickle", "rb") as f:
inputs = pickle.load(f)
# Run model
model = hydrocnhs.Model("Calibrated_TRB_GWLF.yaml")
Q = model.run(temp=inputs["temp"], prec=inputs["prec"])
sim = model.dc.Q_routed["WSLO"]
# Evaluate
indicator = hydrocnhs.Indicator()
print("NSE:", indicator.get_nse(observed, sim))
print("KGE:", indicator.get_kge(observed, sim))
# Visualize
hydrocnhs.Visual().plot.timeseries(
Q_routed=model.dc.Q_routed,
labels=["WSLO"],
figsize=(12, 4)
)
```
---
## Output Description
HydroCNHS stores simulation results in the `model.dc` (data collector) object after
`model.run()`. The dag headline output is `model.dc.Q_routed[outlet]`, keyed by
gauge/subbasin name, containing daily routed streamflow arrays in `cms (m^3/s)`.
Use `parse_output.py` to export `Q_routed` to CSV with columns `date, Q_sim (cms)`
and compute performance indicators (NSE, KGE, RMSE, r) against observed streamflow.
The dag output list is `Q_routed`, `Q_runoff`, `pet`, `TSS_monthly`, and
`ABM_agent_records`. `Q_runoff` is local unrouted subbasin runoff before Lohmann
routing, `pet` is Hamon-computed potential evapotranspiration when PET is not supplied
as input, `TSS_monthly` is sediment-mode monthly routed total suspended sediment, and
`ABM_agent_records` are user-defined water-management bookkeeping records.
---
## 9. Diagnostic Triplets (Top 5)
See `diagnostics/triplets.yaml` for 18 symptom → diagnosis → remedy entries.
Do not duplicate the full corpus here; read the YAML first on any error.
| # | Triplet ID | Error / symptom | Diagnosis | Remedy |
|---|------------|-----------------|-----------|--------|
| 1 | `dt_001` | Simulated discharge is exactly 10× higher than observed | Precipitation data is in mm/day instead of cm/day | Divide all precipitation values by 10 before passing to `model.run()` |
| 2 | `dt_002` | Simulated discharge is orders of magnitude wrong (100× or more) | CMIP precipitation in kg/m²/s not converted to cm/day | Use `prec_cm = prec_kgm2s * 86400.0 / 10.0` |
| 3 | `dt_003` | PET calculation returns unrealistic values; seasonal cycle is muted | Temperature data is in Kelvin instead of Celsius | Subtract 273.15 from all temperature values |
| 4 | `dt_004` | Discharge consistently too low; evaporation excessive | PET provided in mm/day instead of cm/day | Divide PET values by 10 |
| 5 | `dt_005` | Simulated discharge is exactly 100× lower than observed | Subbasin area specified in km² instead of hectares (ha) | Multiply all area values by 100 |
Key failure domains:
- **unit_conversion** (7 triplets): Silent errors from wrong input units
- **parameter_format** (3 triplets): YAML config mistakes
- **runtime** (3 triplets): Crashes during execution
- **silent_error** (3 triplets): Model runs but results are wrong
- **calibration** (2 triplets): GA convergence issues
---
## 15. File Structure
```
ki/
├── SKILL.md # This file — main entry point
├── tools/
│ ├── convert_climate_inputs.py # ERA5/CMIP → model format
│ ├── convert_parameters.py # Soil/land-use → GWLF/ABCD params
│ ├── build_model_config.py # Generate model.yaml
│ ├── run_hydrocnhs.py # Execute model or calibration
│ └── parse_output.py # Extract results to CSV + metrics
├── docs/
│ ├── s1_climate_data_skill.md # Climate data preparation
│ ├── s2_parameter_estimation_skill.md # Parameter estimation
│ ├── s3_model_configuration_skill.md # Model config building
│ ├── s5_execution_skill.md # Model execution
│ ├── s7_output_analysis_skill.md # Output analysis
│ └── s8_calibration_skill.md # Calibration workflow
└── diagnostics/
└── triplets.yaml # 18 diagnostic triplets
```