Skip to content
Back to skills

APSIM

ASecurity

> **MANDATORY EXECUTION POLICY** — READ BEFORE PROCEEDING >

  • 200 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 11, 2026
toolspythongoc#bashsqlnodedockerdebugginggitdatabase

Works with

  • terminal
  • 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 APSIM --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of APSIM?

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

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

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
>

<!-- 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` (8 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` (20 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` (18 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. |
| what past runs learned | `.kdt_evolution.jsonl` | append-only memory of previous runs and fixes on this KI. |

*Projected 2026-08-17 from the KI's actual contents — 10 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_apsimx.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/build_apsimx.py --help` |
| `tools/convert_met.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/convert_met.py --help` |
| `tools/convert_soil.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/convert_soil.py --help` |
| `tools/parse_output.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/parse_output.py --help` |
| `tools/run_apsim.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/run_apsim.py --help` |

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

## 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/FAOSTAT/SKILL.md` for crop yield observations.
See `data_ki/SPAM/SKILL.md` for gridded yield data.

> 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.

# APSIM Next Generation — Knowledge Infrastructure Skill Document

## 1. Quick Overview

APSIM (Agricultural Production Systems sIMulator) is a process-based crop and farming
systems simulator developed by the APSIM Initiative (Australia). It models crop growth,
soil water balance, nitrogen cycling, and management operations at field/point scale
with a daily timestep. APSIM Next Generation (ApsimX) is the C#/.NET 8.0 rewrite of
the classic Fortran APSIM, using JSON-based simulation files (.apsimx) and SQLite
output databases.

| Attribute          | Value                                          |
|--------------------|------------------------------------------------|
| **Language**       | C# (.NET 8.0)                                  |
| **Build system**   | dotnet (MSBuild, ApsimX.sln)                   |
| **Input format**   | JSON (.apsimx) + custom text weather (.met)     |
| **Output format**  | SQLite (.db), optional CSV export               |
| **Timestep**       | Daily                                           |
| **Spatial scale**  | Point / field (Zone-based, area in ha)          |
| **Key crops**      | Wheat, Maize, Canola, Sorghum, Barley, Soybean, Peanut, Sugarcane, Rice, Oats, Chickpea, Mungbean, and 30+ others |
| **Repository**     | https://github.com/APSIMInitiative/ApsimX       |
| **License**        | MIT-like (see LICENSE.md)                       |
| **CLI binary**     | `apsim` (assembly name from APSIM.Cli)          |

## 2. Installation

### 2.1 From Source (Linux)

```bash
# Prerequisites: .NET 8.0 SDK, libsqlite3-dev
sudo apt-get install -y dotnet-sdk-8.0 libsqlite3-dev

# Clone and build
git clone https://github.com/APSIMInitiative/ApsimX.git
cd ApsimX
dotnet build -c Release -f net8.0

# The CLI binary is at:
#   APSIM.Cli/bin/Release/net8.0/apsim
```

### 2.2 Docker

```bash
docker build -f Dockerfiles/release-dockerfile -t apsim .
docker run --rm -v $(pwd)/data:/data apsim run /data/simulation.apsimx
```

### 2.3 Pre-built Installers

Download from https://www.apsim.info/download-apsim/ for Windows/macOS/Linux.

## 3. Pipeline Stages

The APSIM modelling pipeline has seven stages:

| Stage | Name                | Description                                              | Tool                    |
|-------|---------------------|----------------------------------------------------------|-------------------------|
| S0    | Configuration       | Define crop type, site, simulation period, management    | —                       |
| S1    | Domain Setup        | Select soil profile, crop cultivar, zone properties      | `convert_soil.py`       |
| S2    | Data Preparation    | Convert weather forcing to .met format                   | `convert_met.py`        |
| S3    | Simulation Assembly | Build .apsimx JSON file from components                  | `build_apsimx.py`       |
| S4    | Execution           | Run APSIM via CLI                                        | `run_apsim.py`          |
| S5    | Output Parsing      | Extract results from SQLite .db to CSV                   | `parse_output.py`       |
| S6    | Validation          | Compare simulated vs observed, compute metrics           | (manual / scripts)      |

## 4. Critical Domain Knowledge

### 4.1 Weather (.met) File Format — UNIT TRAPS

The .met file is a custom APSIM text format. **Critical units:**

| Column   | Required | Units          | Common Source Units    | Conversion                  |
|----------|----------|----------------|------------------------|-----------------------------|
| `year`   | YES      | integer year   | —                      | —                           |
| `day`    | YES      | day-of-year    | date string            | Convert date → DOY (1-366)  |
| `radn`   | YES      | MJ/m^2         | W/m² (CMFD/ERA5)       | W/m² × 0.0864 = MJ/m²/day  |
| `maxt`   | YES      | °C             | K (ERA5/CMFD)          | K − 273.15 = °C             |
| `mint`   | YES      | °C             | K                      | K − 273.15 = °C             |
| `rain`   | YES      | mm/day         | mm/3hr (CMFD)          | Sum 8 intervals per day     |
| `pan`    | optional | mm/day         | —                      | —                           |
| `vp`     | optional | hPa            | kPa (ERA5)             | kPa × 10 = hPa             |
| `wind`   | optional | m/s            | —                      | —                           |
| `co2`    | optional | ppm            | —                      | —                           |

**CRITICAL: Radiation must be MJ/m²/day, NOT W/m².** Supplying W/m² (typically 100-400)
instead of MJ/m² (typically 5-30) will cause massively inflated biomass production.
This is the #1 unit trap. See diagnostic triplet dt_001.

**CRITICAL: The header line must use parenthesized units exactly as APSIM expects:**
```
year  day radn  maxt   mint  rain  pan    vp      code
 ()   () (MJ/m^2) (oC) (oC)  (mm)  (mm)   (hPa)     ()
```

**CRITICAL: `tav` and `amp` in the header are REQUIRED metadata.**
- `tav` = annual average ambient temperature (°C)
- `amp` = annual amplitude in mean monthly temperature (°C)
- These drive the soil temperature model. If missing, APSIM crashes silently or
  produces unrealistic soil temperatures. See dt_002.

### 4.2 Soil Parameters — Layer-Based Arrays

APSIM soils are specified as arrays indexed by layer. All layers must have the
same number of elements (same number of layers).

| Parameter        | Units   | Description                     | Typical Range        |
|------------------|---------|---------------------------------|----------------------|
| `Thickness`      | mm      | Layer depth                     | 100–300              |
| `BD`             | g/cc    | Bulk density                    | 1.0–1.8              |
| `AirDry`         | mm/mm   | Air-dry water content           | 0.01–0.15            |
| `LL15`           | mm/mm   | Lower limit (wilting point)     | 0.05–0.25            |
| `DUL`            | mm/mm   | Drained upper limit (field cap) | 0.15–0.45            |
| `SAT`            | mm/mm   | Saturation                      | 0.30–0.55            |
| `KS`             | mm/day  | Saturated hydraulic conductivity| 1–500                |

**CRITICAL ordering: AirDry ≤ LL15 ≤ DUL ≤ SAT.** Violation crashes the water
balance model. See dt_003.

**Crop-specific parameters (SoilCrop):**

| Parameter | Units        | Description                        | Typical Range |
|-----------|--------------|------------------------------------|---------------|
| `LL`      | mm/mm        | Crop lower limit (extraction limit)| ≥ LL15        |
| `KL`      | /day         | Root water uptake rate             | 0.01–0.10     |
| `XF`      | dimensionless| Root exploration factor            | 0.0–1.0       |

**Water balance parameters (SoilWater / WaterBalance):**

| Parameter     | Units | Description                              |
|---------------|-------|------------------------------------------|
| `SummerU`     | mm    | Stage 1 evaporation limit (summer)       |
| `SummerCona`  | mm/d^0.5 | Stage 2 evaporation coefficient (summer) |
| `WinterU`     | mm    | Stage 1 evaporation limit (winter)       |
| `WinterCona`  | mm/d^0.5 | Stage 2 evaporation coefficient (winter) |
| `Salb`        | 0-1   | Bare soil albedo                         |
| `CN2Bare`     | —     | SCS curve number (bare soil)             |
| `SWCON`       | 0-1   | Soil water conductivity (per layer)      |
| `DiffusConst` | —     | Diffusivity constant                     |
| `DiffusSlope` | —     | Diffusivity slope                        |

### 4.3 Simulation JSON Structure (.apsimx)

The .apsimx file is a nested JSON tree. Each node has `$type`, `Name`, and `Children`:

```
Simulations
├── DataStore                    ($type: Models.Storage.DataStore)
└── Simulation                   ($type: Models.Core.Simulation)
    ├── Clock                    (Start, End dates)
    ├── Summary                  (logging)
    ├── Weather                  (FileName → .met path)
    ├── MicroClimate             (light interception)
    └── Zone                     (Area in ha)
        ├── Soil                 (Physical, Chemical, Organic, WaterBalance, SoilCrop)
        ├── Plant / Crop         (cultivar, phenology, organs)
        ├── Manager              (sowing rules, fertilizer, irrigation)
        └── Report               (VariableNames[], EventNames[])
```

**CRITICAL: `%root%` in file paths is replaced with the directory containing the
.apsimx file at runtime.** Relative paths resolve from this root. See dt_004.

### 4.4 Crop Sowing Parameters

Sowing is triggered by a Manager script calling `[Crop].Sow(...)`:

| Parameter       | Units   | Description                          |
|-----------------|---------|--------------------------------------|
| `Population`    | /m²     | Plant population density             |
| `Depth`         | mm      | Sowing depth                         |
| `Cultivar`      | string  | Cultivar name (must match available) |
| `RowSpacing`    | mm      | Row spacing                          |
| `MaxCover`      | 0-1     | Maximum canopy cover                 |
| `BudNumber`     | integer | Number of buds (tuber crops)         |

**CRITICAL: Population is plants per m², NOT per hectare.** 100 plants/m² = 1,000,000
plants/ha. Supplying 100,000 (intended as plants/ha) as plants/m² gives 10^9 plants/ha.
See dt_005.

### 4.5 Key Output Variables

Variables are addressed by model path in Report definitions:

| Variable Path                      | Units  | Description                     |
|------------------------------------|--------|---------------------------------|
| `[Clock].Today`                    | date   | Simulation date                 |
| `[Wheat].Grain.Wt`                | g/m²   | Grain dry weight                |
| `[Wheat].AboveGround.Wt`          | g/m²   | Above-ground biomass            |
| `[Wheat].Leaf.LAI`                | m²/m²  | Leaf area index                 |
| `[Wheat].Phenology.Stage`         | code   | Phenological stage number       |
| `[Wheat].Phenology.CurrentPhaseName`| string | Phase name                    |
| `[Wheat].Root.RootingDepth`       | mm     | Rooting depth                   |
| `[Soil].Water.SW`                 | mm/mm  | Volumetric soil water (array)   |
| `[Soil].Water.ESW`                | mm     | Extractable soil water (array)  |
| `[Soil].SoilWater.Runoff`         | mm     | Surface runoff                  |
| `[Soil].SoilWater.Drainage`       | mm     | Deep drainage                   |
| `[Soil].SoilWater.Es`             | mm     | Soil evaporation                |
| `[Weather].Rain`                  | mm     | Daily rainfall                  |
| `[Weather].MaxT`                  | °C     | Maximum temperature             |
| `[Weather].MinT`                  | °C     | Minimum temperature             |
| `[Weather].Radn`                  | MJ/m²  | Solar radiation                 |

**CRITICAL: Biomass outputs (Wt) are in g/m², NOT kg/ha.** To convert:
kg/ha = g/m² × 10. Grain yield of 300 g/m² = 3000 kg/ha = 3.0 t/ha. See dt_006.

## 6. Output Description

**Source of truth: `dag.yaml`.** The dag defines what this KI predicts. If this
section and `dag.yaml` disagree, `dag.yaml` wins.

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

> `Grain.Wt` — Crop grain dry weight (yield) in the plant/crop biomass medium; g/m^2 x10 = kg/ha, /100 = t/ha. (`g/m^2`)

| Output variable (dag `var`) | Rank | Unit | Description / dag status |
|-----------------------------|------|------|--------------------------|
| `Grain.Wt` | 1 | `g/m^2` | Crop grain dry weight (yield) in the plant/crop biomass medium; g/m^2 x10 = kg/ha, /100 = t/ha. |
| `AboveGround.Wt` | dag output | see `dag.yaml` | Listed by the dag as an APSIM output. |
| `Leaf.LAI` | dag output | see `dag.yaml` | Listed by the dag as an APSIM output. |
| `Phenology.Stage / flowering & maturity date` | dag output | see `dag.yaml` | Listed by the dag as an APSIM output. |
| `Root.RootingDepth` | dag output | see `dag.yaml` | Listed by the dag as an APSIM output. |
| `Soil.Water.SW / ESW` | dag output | see `dag.yaml` | Listed by the dag as an APSIM output. |
| `SoilWater.Drainage / Runoff / Es` | dag output | see `dag.yaml` | Listed by the dag as an APSIM output. |

### 4.6 Fertiliser Application

Fertiliser is applied via Manager script or Operations list:

| Parameter | Units  | Description                              |
|-----------|--------|------------------------------------------|
| `Amount`  | kg/ha  | Application amount                       |
| `Depth`   | mm     | Application depth in soil                |
| `Type`    | enum   | NO3N, NH4N, UreaN, etc.                  |

### 4.7 Irrigation

| Parameter | Units | Description                                |
|-----------|-------|--------------------------------------------|
| `Amount`  | mm    | Irrigation depth                           |
| `Depth`   | mm    | Depth of application in soil               |
| `Duration`| min   | Duration of irrigation event               |
| `Efficiency`| 0-1 | Irrigation efficiency                      |

### 4.8 Phenology and Thermal Time

APSIM crops use thermal time (degree-days) to drive phenological development:

```
ThermalTime = max(0, (Tmax + Tmin)/2 - Tbase)
```

Where Tbase varies by crop (e.g., Wheat ~0°C, Maize ~8°C, Sorghum ~11°C).

Key phenological stages (wheat example):
1. Sowing → Germination
2. Germination → Emergence
3. Emergence → Terminal Spikelet
4. Terminal Spikelet → Flowering
5. Flowering → Start Grain Fill
6. Start Grain Fill → End Grain Fill
7. End Grain Fill → Maturity
8. Maturity → Harvest Ripe

### 4.9 Canopy Cover Calculation

```
CoverGreen = 1 - exp(-ExtinctionCoeff × LAI / MaxCover)
CoverTotal = 1 - (1 - CoverGreen) × (1 - CoverDead)
```

## 5. Unit Trap Table

This table documents the most dangerous unit mismatches when preparing APSIM inputs
from global datasets (ERA5, CMFD, MSWX, SoilGrids, HWSD):

| ID  | Variable    | APSIM Unit   | Common Source | Source Unit     | Conversion Factor              | Severity |
|-----|-------------|--------------|---------------|-----------------|-------------------------------|----------|
| U01 | Radiation   | MJ/m²/day   | ERA5/CMFD     | W/m² (instant)  | × 0.0864 (÷ 11.574)          | FATAL    |
| U02 | Temperature | °C           | ERA5          | K               | − 273.15                      | FATAL    |
| U03 | Vapor press | hPa          | ERA5          | kPa             | × 10                          | degraded |
| U04 | Rainfall    | mm/day       | CMFD          | mm/3hr          | Sum 8 intervals               | FATAL    |
| U05 | Biomass out | g/m²         | Literature    | kg/ha           | ÷ 10 (APSIM→lit) or × 10     | silent   |
| U06 | Population  | plants/m²    | Agronomic     | plants/ha       | ÷ 10000                       | FATAL    |
| U07 | Soil water  | mm/mm (vol)  | SoilGrids     | % (v/v)         | ÷ 100                         | FATAL    |
| U08 | Thickness   | mm           | HWSD          | cm              | × 10                          | FATAL    |
| U09 | Bulk density| g/cc         | SoilGrids     | kg/m³           | ÷ 1000                        | FATAL    |
| U10 | KS          | mm/day       | Literature    | cm/hr           | × 240                         | degraded |
| U11 | Row spacing | mm           | Agronomic     | cm              | × 10                          | degraded |
| U12 | Sowing depth| mm           | Agronomic     | cm              | × 10                          | degraded |
| U13 | Root depth  | mm           | Literature    | cm or m         | × 10 or × 1000               | silent   |
| U14 | CO2         | ppm          | —             | µmol/mol        | 1:1 (same)                    | none     |
| U15 | Wind speed  | m/s          | ERA5          | m/s             | 1:1 (check u/v components)    | degraded |

## 8. Unit Conversion Table

This unit table restates the KI's pipeline unit conversions and the dag's headline
output conversion. It is the quick-check table; detailed I/O shapes remain in
`docs/format_spec.yaml`, and the headline output identity remains in `dag.yaml`.

| Variable | Source unit / common source | Model or reported unit | Conversion | Type |
|----------|-----------------------------|------------------------|------------|------|
| Radiation (`radn`) | W/m² (ERA5/CMFD instant) | MJ/m²/day | × 0.0864 (÷ 11.574) | multiplicative |
| Temperature (`maxt`, `mint`) | K (ERA5/CMFD) | °C | − 273.15 | additive |
| Vapor pressure (`vp`) | kPa (ERA5) | hPa | × 10 | multiplicative |
| Rainfall (`rain`) | mm/3hr (CMFD) | mm/day | Sum 8 intervals | aggregation |
| `Grain.Wt` | `g/m^2` | kg/ha | x10 | multiplicative |
| `Grain.Wt` | `g/m^2` | t/ha | /100 | multiplicative |
| Population | plants/ha | plants/m² | ÷ 10000 | multiplicative |
| Soil water | % (v/v) | mm/mm | ÷ 100 | multiplicative |
| Thickness | cm | mm | × 10 | multiplicative |
| Bulk density | kg/m³ | g/cc | ÷ 1000 | multiplicative |
| KS | cm/hr | mm/day | × 240 | multiplicative |
| Row spacing | cm | mm | × 10 | multiplicative |
| Sowing depth | cm | mm | × 10 | multiplicative |
| Root depth | cm or m | mm | × 10 or × 1000 | multiplicative |
| CO2 | µmol/mol | ppm | 1:1 (same) | identity |
| Wind speed | m/s | m/s | 1:1 (check u/v components) | identity |

## 6. Tool Reference

| Tool                  | Stage | Purpose                                        |
|-----------------------|-------|------------------------------------------------|
| `convert_met.py`      | S2    | Convert global forcing (NetCDF) → APSIM .met   |
| `convert_soil.py`     | S1    | Convert HWSD/SoilGrids → APSIM soil JSON       |
| `build_apsimx.py`     | S3    | Assemble .apsimx simulation file from parts     |
| `run_apsim.py`        | S4    | Execute APSIM CLI with preflight checks         |
| `parse_output.py`     | S5    | Extract SQLite .db results → CSV                |

All tools follow the validate→process→validate pattern:
1. `validate_inputs()` — check files exist, units correct, ranges valid
2. `process()` — core transformation logic
3. `validate_outputs()` — verify output quality and physical constraints

## 7. Execution

### 7.1 Basic Run

```bash
# Run a single simulation
apsim run Wheat.apsimx

# Run with CSV export
apsim run Wheat.apsimx --csv

# Run specific simulations by name regex
apsim run Wheat.apsimx --simulation-names "Dalby.*"

# Run single-threaded (useful for debugging)
apsim run Wheat.apsimx --single-threaded

# Verbose output
apsim run Wheat.apsimx --verbose
```

### 7.2 Edit Before Run

```bash
# Override parameters via config file
apsim run Wheat.apsimx --edit config.txt
```

Config file format (one override per line):
```
[Simulation].Clock.Start = 2000-01-01
[Simulation].Clock.End = 2005-12-31
[Simulation].Zone.Weather.FileName = /data/weather/site.met
```

### 7.3 Output Access

After running, output is in `{filename}.db` (SQLite):
```bash
sqlite3 Wheat.db "SELECT * FROM Report LIMIT 10;"
```

Or use `--csv` flag to auto-export to `{filename}.Report.csv`.

## 8. Validation Metrics for Crop Models

| Metric | Formula / Description                           | Grading source    |
|--------|------------------------------------------------|-------------------|
| RMSE   | √(mean((sim-obs)²))                           | no cited threshold in the provided `Grain.Wt` convention |
| nRMSE  | RMSE / mean(obs) × 100                         | use Section 11 / `docs/validation_convention.yaml` |
| R²     | Coefficient of determination                    | no cited threshold in the provided `Grain.Wt` convention |
| PBIAS  | 100 × Σ(sim-obs) / Σ(obs)                      | choose by dag obs-shape rules; no `Grain.Wt` convention bar stated here |
| d      | Willmott index of agreement                    | no cited threshold in the provided `Grain.Wt` convention |
| EF     | Nash-Sutcliffe model efficiency (=NSE)         | use Section 11 / `docs/validation_convention.yaml` |

Common validation targets:
- **Grain yield** (t/ha): Primary metric for crop models
- **Biomass** (t/ha): Total above-ground dry matter
- **Phenology** (days): Flowering date, maturity date
- **LAI** (m²/m²): Peak LAI timing and magnitude
- **Soil water** (mm): Profile soil water content over time

### 8.1 Obs-shape selection - REQUIRED before computing any metric

`dag.yaml` `outputs[Grain.Wt].observability.comparable_obs_shapes` declares THREE
mutually exclusive comparison modes. Pick by the OBSERVATION's spatial support,
not by the simulation's.

| Obs example | obs_shape | comparison_mode | determining_metric | detrending_options |
|---|---|---|---|---|
| One field trial, one season | `point_snapshot` | `scalar_comparison` | `pbias` | `none` |
| One field trial, many seasons | `point_time_series` | `time_series_comparison` | `pbias` | `none` |
| GDHY / SPAM / FAOSTAT / any gridded, district or national yield | `regional_aggregate_time_series` | `aggregate_trend_comparison` | `pbias` | `none`, `linear_residual`, `decadal_mean` |

**A 0.5-degree GDHY cell, a SPAM pixel, a district series and a national FAOSTAT
series are ALL `regional_aggregate_time_series`.** They average thousands of
fields and carry a secular technology/management trend that a
constant-management, weather-driven point simulation cannot and must not
reproduce. If `resolved_obs.granularity == "grid"`, or the obs is a statistical
aggregate of any kind, the obs_shape is `regional_aggregate_time_series` - full
stop. Declaring it `point_time_series` silently selects the wrong metric family.

### 8.2 Mandatory detrending for `regional_aggregate_time_series`

`ki_tools_common.metrics.all_metrics` alone (raw NSE / r / KGE) is **NOT** valid
for this obs shape. Also call `ki_tools_common.metrics.trend_metrics(obs, sim)`
(`metrics.py:492`), which implements the dag `trend_match` family with
`linear_residual` detrending:

python
from ki_tools_common.metrics import all_metrics, trend_metrics
m = all_metrics(obs, sim)           # magnitude_accuracy: PBIAS, RMSE
m.update(trend_metrics(obs, sim))   # trend_match: r_detr, r_firstdiff, slope_ratio


| Metric | Meaning | Use |
|---|---|---|
| `pbias` | determining metric; magnitude vs the aggregate | grade only against the applicable convention bar |
| `r_detr` | interannual skill after removing each series own linear trend | trend diagnostic |
| `r_firstdiff` | year-over-year change skill (trend-free by construction) | trend diagnostic |
| `slope_ratio` | sim trend / obs trend; near 0 is EXPECTED under constant management | report, do not score |
| `r` (raw), `nse` | NOT skill metrics for this shape | report as `r_raw` for transparency only |

**Do NOT truncate the record to a "management-consistent" sub-window in place of
detrending.** Truncation is not one of the dag `detrending_options`, it discards
data, and it moves PBIAS without removing the trend it was chosen to handle. A
sub-window may be reported as an ADDITIONAL diagnostic, clearly labelled, never
as a substitute.

**Worked example (GDHY wheat, Balcarce AR, 1984-2016, n=33).** Raw `r = -0.19`
looked like an anti-correlated model. `trend_metrics` on the SAME pairs gives
`r_detr = +0.14`, `r_firstdiff = +0.33`, `slope_obs = +0.074 t/ha/yr`,
`slope_sim = -0.042 t/ha/yr`. The negative raw r was entirely an artefact of the
obs technology trend. The only real model finding is `pbias = +40.8%`, i.e. the
attainable-vs-actual yield gap of triplet dt_019 - handle that with
region-matched management (dt_019), not with a metric change.

### 8.3 Calibration / validation split

`period_calibration` and `period_validation` must be DISJOINT. Emitting the same
window twice, so that `nse_val` is bit-identical to `nse_cal`, reports no
independent information. For an uncalibrated forward run, either split the
seasons into two disjoint periods or declare a single period and omit the
`_cal` / `_val` fields.

## 11. Validated Results

No achieved calibration, validation, or full-period metric values are stated in
the provided KI facts. Grade `Grain.Wt` runs against `docs/validation_convention.yaml`;
do not substitute remembered crop-model thresholds.

### Performance Metrics — convention bars for `Grain.Wt`

Each row below restates one convention entry for `Grain.Wt`. For minimize metrics,
lower values are better; for maximize metrics, higher values are better.

| Variable | Metric | Direction | Very good band | Good band | Satisfactory band |
|----------|--------|-----------|----------------|-----------|-------------------|
| `Grain.Wt` | `nrmse` | minimize | <= 10 (`zhao2012`, `brown2018`) | <= 20 (`zhao2012`, `brown2018`) | <= 30 (`zhao2012`, `brown2018`) |
| `Grain.Wt` | `ef` | maximize | >= 1.0 (`brown2018`) | no cited threshold | >= 0.0 (`brown2018`) |
| `Grain.Wt` | `nrmse` | minimize | <= 10 (`zhao2012`, `brown2018`) | <= 20 (`zhao2012`, `brown2018`) | <= 30 (`zhao2012`, `brown2018`) |
| `Grain.Wt` | `nse` | maximize | >= 0.75 (`pasley2023`) | >= 0.65 (`pasley2023`) | >= 0.5 (`pasley2023`) |
| `Grain.Wt` | `nrmse` | minimize | <= 10 (`zhao2012`, `lu2022`) | <= 20 (`zhao2012`, `lu2022`) | <= 30 (`zhao2012`, `lu2022`) |
| `Grain.Wt` | `nse` | maximize | >= 0.75 (`pasley2023`) | >= 0.65 (`pasley2023`) | >= 0.5 (`pasley2023`) |

### Data Replacement Tracking

| Component | Source | Status | Notes |
|-----------|--------|--------|-------|
| Forcing | Pipeline | Pending validation result in this document | Use `preflight_check.py` before any run. |
| Soil | Pipeline | Pending validation result in this document | Use KI soil conversion tools and `docs/format_spec.yaml`. |
| APSIM execution | Actual APSIM binary/package | Required | Do not substitute a simplified formula or approximation. |
| Observations | Observation-binding workflow | Pending validation result in this document | Choose obs shape from the dag before computing metrics. |

## 9. File Structure

```
project/
├── simulation.apsimx          # Main simulation file (JSON)
├── weather/
│   └── site.met               # Weather forcing data
├── simulation.db              # Output database (SQLite, auto-created)
├── simulation.db-wal          # Write-ahead log (temp, auto-managed)
├── simulation.db-shm          # Shared memory (temp, auto-managed)
└── simulation.Report.csv      # CSV export (if --csv flag used)
```

## 10. Diagnostic Triplets Summary

The most dangerous silent errors in APSIM modelling:

1. **dt_001 — Radiation in W/m² instead of MJ/m²/day**: Biomass explodes to
   unrealistic values. Tool `convert_met.py` auto-converts and validates range.

2. **dt_002 — Missing tav/amp in .met header**: Soil temperature model fails
   silently, producing unrealistic soil temperatures that affect germination
   and root growth.

3. **dt_003 — Soil water limits not ordered (AirDry ≤ LL15 ≤ DUL ≤ SAT)**:
   Water balance crashes or produces negative water content.

4. **dt_005 — Plant population in wrong units**: Supplying plants/ha as
   plants/m² gives 10,000× too many plants.

5. **dt_006 — Biomass output confusion (g/m² vs kg/ha)**: Factor of 10
   error in reported yield.

6. **dt_010 — Wrong cultivar name**: Simulation crashes with unhelpful error.
   Must match exactly from available cultivar list.

7. **dt_013 — .met file path not resolved**: %root% macro not properly
   expanded, or relative path broken by directory change.

Files in this skill

  • SKILL.md32.2 KB
  • dag.yaml34.9 KB
  • diagnostics/triplets.yaml23.9 KB
  • docs/REFERENCES.md2 KB
  • docs/format_spec.yaml27.8 KB
  • docs/papers.json5.8 KB
  • docs/s0_configuration.md3 KB
  • docs/s1_domain_setup.md3.7 KB
  • docs/s2_weather_preparation.md4.4 KB
  • docs/s3_simulation_assembly.md4.5 KB
  • docs/s4_execution.md3.8 KB
  • docs/s5_output_parsing.md3.8 KB
  • docs/s6_validation.md7.3 KB
  • docs/s7_calibration.md5.8 KB
  • docs/validation_convention.yaml21.4 KB
  • knowledge_infrastructure.yaml3.6 KB
  • preflight_check.py8 KB
  • run_and_score_faostat.py12.7 KB
  • run_and_score_verify2.py12.4 KB
  • tools/build_apsimx.py19.5 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…