Imported from lzwei196/KISS-Knowledge-Infrastructure-for-Scientific-Simulation (
models/APEX/SKILL.md). Install upstream withnpx skills add lzwei196/KISS-Knowledge-Infrastructure-for-Scientific-Simulation --skill APEX. Copyright stays with the author.
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:
- Check
diagnostics/triplets.yamlfor a matching error pattern- Try the fix suggested in the triplet's
remedysection- 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. Doing so produces scientifically invalid results and defeats the purpose of the KI.
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 (model crashes, wrong output, unexpected values), follow this order. Do NOT skip steps or write debug scripts:
- Check triplets —
diagnostics/triplets.yamlmay already cover this error- Check the XLSM editor —
reference/apexeditorrev2203.xlsmcontains the EXACT format specification for every APEX input file (APEXCONT.DAT, OPC, SOL, SIT, list files). Open withopenpyxlto read column names, parameter IDs, and valid ranges. Also seereference/apex_formats.jsonfor pre-extracted specs.- Read official docs / Find working examples — Look in the example workspace for the validated working case. Compare your inputs against these.
- Fix the tool — Now that you know what "correct" looks like, make targeted fixes
XLSM Editor Reference (
reference/apexeditorrev2203.xlsm): The official APEX parameter editor contains complete format specs for ALL input files. Key sheets: APEXCONT.DAT (86 control params), MNGT.MNG (operations format), SOIL.SOL, SITE.SIT, APEXPLANT.TAB (crop database), APEXTILL.TAB (tillage), APEXFERT.TAB (fertilizers), all list files. Usereference/apex_formats.jsonfor the pre-extracted machine-readable version.OPC Management File Format (from XLSM): Col 1: YEAR, Col 2: MONTH, Col 3: DAY, Col 4: TILLAGE_ID (from TILLTABLE), Col 5: MACHINE_ID, Col 6: PLANT_ID (from CROPCOM.DAT), Col 7: OPV, Col 8: OPV1, Col 9: OPV2. To change crop: modify column 6, NOT column 4.
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/ (10 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 (9 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 (24 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 (16 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>.
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/quickstart.py |
KISSPATH_PYTHON_ENV/bin/python {KI}/tools/quickstart.py --help |
tools/s1_setup_workspace.py |
KISSPATH_PYTHON_ENV/bin/python {KI}/tools/s1_setup_workspace.py --help |
tools/s2_convert_forcing.py |
KISSPATH_PYTHON_ENV/bin/python {KI}/tools/s2_convert_forcing.py --help |
tools/s3_build_soil.py |
KISSPATH_PYTHON_ENV/bin/python {KI}/tools/s3_build_soil.py --help |
tools/s4_update_site.py |
KISSPATH_PYTHON_ENV/bin/python {KI}/tools/s4_update_site.py --help |
tools/s5_update_control.py |
KISSPATH_PYTHON_ENV/bin/python {KI}/tools/s5_update_control.py --help |
tools/s6_run_apex.py |
KISSPATH_PYTHON_ENV/bin/python {KI}/tools/s6_run_apex.py --help |
tools/s7_parse_output.py |
KISSPATH_PYTHON_ENV/bin/python {KI}/tools/s7_parse_output.py --help |
tools/s8_update_operations.py |
KISSPATH_PYTHON_ENV/bin/python {KI}/tools/s8_update_operations.py --help |
tools/s9_generate_crop_opc.py |
KISSPATH_PYTHON_ENV/bin/python {KI}/tools/s9_generate_crop_opc.py --help |
10 public tools; _-prefixed helpers and packaging files excluded.
APEX 1501 (Agricultural Policy / Environmental eXtender) — Knowledge Infrastructure
Model: APEX v0806 (PE32 Windows binary via Wine)
Distributor: Texas A&M AgriLife / Blackland Research and Extension Center
Source: https://epicapex.tamu.edu/software/
Language: Fortran 90 (Intel Fortran compiled, PE32 executable)
Domain: Field- and watershed-scale agronomy / hydrology / water-quality
Validation status: validated — Bengbu China corn 6.21 t/ha vs 5.6 observed (+11% bias).
Multi-subarea farm (4 fields) validated with CMFD weather, HWSD soil, GGCMI calendar.
CRITICAL: Use v0806, NOT v1501. The v1501 binary has a confirmed issue where annual
crops produce zero biomass (BIOM=0.01) due to P cycling NaN in the Century C/N model.
Exhaustively tested with 25 PARM fixes, soil P initialization 3-50 ppm, Century pool
initialization from OC — still zero yield. v0806 produces 4.46-6.21 t/ha corn.
Template: Riesel TX cropland (ex1_RiselTX), NOT WRE pasture.
Binary: reference/APEX0806.exe (run via wine APEX0806.exe).
Overview
APEX (Agricultural Policy / Environmental eXtender) is the multi-subarea, watershed- scale extension of the EPIC field-scale model. It simulates the full agronomic, hydrologic, erosion, nutrient, pesticide, carbon, grazing-livestock, and economic processes of fields, farms, and small watersheds at a daily time step, optionally with sub-daily routing.
What APEX does (one paragraph per major process):
- Hydrology — Curve Number (NRCS CN) or Green-Ampt infiltration; soil-water routing through up to 30 layers; ET via Penman-Monteith / Penman / Priestley- Taylor / Hargreaves / Baier-Robertson (selectable); snow melt; lateral subsurface flow; groundwater return flow; tile drainage.
- Erosion — Six water-erosion equations (USLE, MUSLE, MUST, MUSS, MUSI, RUSLE, RUSLE2) and the WEQ wind-erosion model.
- Nutrient cycling — N (mineralization, nitrification, denitrification, fixation, volatilization, leaching, runoff and sediment loss) and P (Sharpley adsorption- desorption with labile/active/stable pools) cycles. Optional Century carbon model.
- Crop growth — EPIC-style heat-unit phenology with LAI, biomass, root growth, water/nutrient/temperature/aeration stresses, harvest index. ~120 crops in PLANTABLE.DAT/CROPCOM.DAT.
- Management — Rotations, tillage, fertilization, irrigation (auto or scheduled), pesticides, grazing, manure, drainage, terraces, contouring, strip cropping, liming, harvesting, residue, cover crops, fire, controlled burn.
- Routing — APEX subareas drain to one another via channel/floodplain routing (variable-storage or Muskingum). Sediment, nutrients, pesticides routed.
- Economics — Crop budgets, costs/returns by operation.
Key difference from EPIC — APEX adds the multi-subarea routing topology (each
*.SUB file describes one subarea; SUBA****.DAT lists them; routing direction is
encoded by WSA / CHL / RCHL). EPIC is single-field; APEX is watershed.
Installation
Binary (already installed)
APEX 1501 binary: KISSPATH_INTERNAL_NOT_SHIPPED/auto_dissect_multi_agent/_work_v2/APEX/source/repo/Apex 1501 - Linux/apex1501
Version: APEX1501 v20231214
Platform: Linux x86-64, statically linked ELF (no shared lib deps)
File size: ~7.3 MB
Source: https://epicapex.tamu.edu/media/w0ecjadt/apex-1501-linux.zip
Manual: https://epicapex.tamu.edu/media/pkff4m34/the-apex1501-user-manual-november-2023.pdf
Theory: https://epicapex.tamu.edu/media/2mwdlhte/the-apex1501-theoretical-documentation-january-2023.pdf
The binary is statically linked — no installation, just copy it to your run directory (or invoke from anywhere). The binary always opens its input files from the current working directory and always writes outputs to the current working directory. There is no command-line argument parsing.
Validation that the binary works
# Run preflight (verifies binary, example dataset, control files)
python preflight_check.py
Expected output:
[OK] APEX1501 binary found at .../apex1501
[OK] APEX1501 binary is executable
[OK] Example dataset found in examples/
[OK] All required control files present (APEXFILE.DAT, APEXCONT.DAT, ...)
[OK] preflight passed — APEX is ready to run
File ecosystem (FORTRAN FIXED-WIDTH FORMATS — COPY, DON'T GENERATE)
APEX 1501 is a Fortran-90 model. Every input file is a Fortran fixed-format text file with rigid column positions. The single most important rule:
NEVER WRITE APEX INPUT FILES FROM SCRATCH. ALWAYS COPY FROM
examples/AND MODIFY SPECIFIC VALUES IN PLACE.
The KI ships with a complete validated example dataset in examples/ derived from
the USDA-ARS published pyAPEXSCU dataset (Maskey et al., grazing study at Marena
ARS station, 35.54°N, 98.05°W, OK). Every tool in tools/ follows the
copy-template-then-modify pattern.
Control / list files (fixed names, single watershed)
| File | Purpose | Fortran unit |
|---|---|---|
APEXFILE.DAT |
Master file index — 19 lines, each <token> <filename> |
22 |
APEXRUN.DAT |
Run table — one line per run referencing site/subarea/operation IDs | 24 |
APEXCONT.DAT |
Run control — NBYR, IYR, IMO, IDA, IPD, NGN, IGN; CO2; physics options | 30 |
APEXDIM.DAT |
Array dimensions (max subareas, layers, owners, etc.) | 36 |
SITELIST.DAT |
Numbered list of *.SIT files (referenced by ISIT in APEXRUN.DAT) |
12 |
SUBSLIST.DAT |
Numbered list of *.SUB files (referenced by ISUB) |
14 |
SOILLIST.DAT |
Numbered list of *.SOL files (referenced by INPS in *.SUB) |
17 |
MNGTLIST.DAT |
Numbered list of operation schedule *.OPC/*.MGT files |
18 |
WPM1LIST.DAT |
Weather parameter (monthly statistics) station list | 13 |
WINDLIST.DAT |
Wind parameter station list | 13 |
WDLYLIST.DAT |
Daily weather (*.DLY) station list |
13 |
PSOLIST.DAT |
Point source list | 19 |
Per-subarea files (one set per subarea)
| File | Purpose | Format spec |
|---|---|---|
*.SIT |
Site (lat/lon, elevation, CO2, weather station references) | 9 lines, fixed-width 8-col fields, Manual §2.3 |
*.SUB |
Subarea (soil ID, operation ID, hydrologic + routing params, grazing herd) | 12 lines + padding rows of zeros to 22 lines (apex1501 EOF quirk), Manual §2.5 |
*.SOL |
Soil profile (up to 30 layers × 50+ properties) | Manual §2.7 |
*.OPC / *.MGT |
Operation schedule (planting, fert, harvest, tillage rows) | Manual §2.10 |
*.WP1 |
Monthly weather statistics (12 months × 13 variables) | Manual §2.13 |
*.WND |
Monthly wind statistics | Manual §2.14 |
*.DLY |
Daily measured weather (year, month, day, srad, tmax, tmin, prcp, RHM, wind) | Manual §2.15 |
Parameter / table files (shared globally, ship with model)
PLANTABLE.DAT (or CROPCOM.DAT) — crop parameters (~120 crops)
TILLTABLE.DAT (or TILLCOM.DAT) — tillage implements
PESTTABLE.DAT (or PESTCOM.DAT) — pesticides
FERTTABLE.DAT (or FERT2012.DAT) — fertilizers
HERDTABLE.DAT (or HERD.DAT) — livestock herd parameters
APEXPARM.DAT (or PARM1102.DAT) — APEX general/internal parameters
APEXPRNT.DAT (or PRNT1102.DAT) — output print code selections
MLRNCOM.DAT — measured weather table (for MLRN feature)
TR55COM.DAT — TR-55 SCS rainfall distribution constants
Pipeline stages (KI tools)
| Stage | Tool | Purpose |
|---|---|---|
| S1 | tools/s1_setup_workspace.py |
Copy entire example template to a fresh workspace dir |
| S2 | tools/s2_convert_forcing.py |
Pull global daily forcing (CMFD/MSWX/NASA POWER) → write *.DLY, *.WP1, *.WND |
| S3 | tools/s3_build_soil.py |
HWSD → *.SOL (10 layers, 50+ properties) using ROSETTA van Genuchten params |
| S4 | tools/s4_update_site.py |
Edit *.SIT lat/lon/elevation in place |
| S5 | tools/s5_update_control.py |
Edit APEXCONT.DAT simulation period & physics options |
| S6 | tools/s6_run_apex.py |
Run binary inside workspace; collect outputs; check water balance |
| S7 | tools/s7_parse_output.py |
Parse *.OUT annual + *.SAD daily subarea → CSV |
| S8 | tools/s8_update_operations.py |
Edit existing OPSC*.MGT / *.OPC operation schedules in place |
| S9 | tools/s9_generate_crop_opc.py |
Generate APEX0806 crop operation schedules and wire OPSCCOM.DAT |
Stage skill docs:
- S1 setup workspace
- S2 convert forcing
- S3 build soil
- S4 update site
- S5 update control
- S6 run APEX
- S7 parse output
- S8 update operations
- S9 generate crop OPC
Every tool follows validate → process → validate:
validate_inputs()checks lat/lon ranges, year ranges, file existence- Process step copies template, modifies via string replacement (NOT regeneration)
validate_outputs()checks the resulting file is parseable and physically plausible
Unit trap table
| Variable | APEX unit | Common other units (DON'T mix up) | Where it appears |
|---|---|---|---|
| Latitude / longitude | decimal degrees | DMS, radians | *.SIT line 4 fields 1–2 |
| Elevation | m | ft (US Survey), km | *.SIT line 4 field 3 |
| Channel length CHL / RCHL | km | m, mi | *.SUB line 4 fields 2–3 |
| Channel slope CHS | m/m (dimensionless fraction) | %, deg | *.SUB line 4 field 5 |
| Watershed area WSA | ha | m², km², ac | *.SUB line 4 field 1 |
| Daily precipitation | mm/day | inches, cm | *.DLY field 6 |
| Tmax / Tmin | °C | °F, K | *.DLY fields 4–5 |
| Solar radiation SRAD | MJ/m²/day | W/m², ly/day | *.DLY field 3 |
| Wind speed | m/s | mph, km/h | *.DLY field 8 (if NGN includes wind) |
| Relative humidity | fraction (0–1) | percent | *.DLY field 7 |
| CO2 | ppm (volume) | ppmv, mol/mol | APEXCONT.DAT line 3 field 2; *.SIT line 4 field 5 |
| Saturated K (Ksat) | mm/h | cm/day, m/s | *.SOL |
| Soil bulk density | g/cm³ (= Mg/m³) | kg/m³ | *.SOL |
| Soil organic C | % by weight | g/kg, kg/ha | *.SOL |
| Soil pH | dimensionless | — | *.SOL |
| N applied | kg/ha | lb/ac | *.OPC fertilizer rows |
| Crop yield (output) | t/ha dry matter | bu/ac, kg/ha | *.ACY, *.OUT |
| Water yield WYLD | mm (or m³ in mass balance block) | inches | *.OUT |
| Sediment yield Y | t/ha | t/ac, kg/ha | *.OUT |
Most common unit traps (causing silent wrong answers):
- Slope as percent vs m/m — APEX wants 0.05 for 5%, NOT 5.0.
- Elevation in feet — APEX uses meters universally. Convert ft × 0.3048.
- CO2 in ppmv vs ppm — APEX uses ppm by volume; modern atmospheric value ≈ 420 ppm.
- Daily SRAD in W/m² instead of MJ/m²/day — multiply W/m² by 0.0864 to get MJ/m²/day (mean daytime W/m² × seconds per day / 1e6 ≈ × 0.0864 for daily mean).
- Lat in southern hemisphere positive — APEX wants negative degrees south.
Unit Conversion Table (template §8)
Exact I/O shapes live in docs/format_spec.yaml and the dag. This unit table
summarizes the conversions and unit traps this KI already documents; do not
replace it with remembered conventions.
| Variable | Source unit (verified or expected) | APEX model unit | Conversion / handling | Type |
|---|---|---|---|---|
| Latitude / longitude | decimal degrees | decimal degrees | use as-is; southern hemisphere is negative | identity |
| Elevation | ft, m, or source DEM unit | m | ft × 0.3048 when source is feet | multiplicative |
| Channel length CHL / RCHL | m, km, or mi | km | convert source length to km before writing *.SUB |
unit conversion |
| Channel slope CHS | percent, degrees, or fraction | m/m fraction | percent ÷ 100; do not write 5.0 for 5% | unit conversion |
| Watershed area WSA | m², km², ac, or ha | ha | convert source area to hectares before writing *.SUB |
unit conversion |
| Daily precipitation | source forcing native unit | mm/day | CMFD 3-hr kg/m²/s ×10800 per step, sum 8 steps; MSWX 3-hr mm/3hr sum 8 steps | accumulation |
| Tmax / Tmin | K or °C | °C | K − 273.15; °C unchanged | additive or identity |
| Solar radiation SRAD | W/m² or MJ/m²/day | MJ/m²/day | daily mean W/m² × 0.0864; MJ/m²/day unchanged | multiplicative |
| Wind speed | m/s, mph, or km/h | m/s | convert source wind to m/s | unit conversion |
| Relative humidity | percent or fraction | fraction (0-1) | percent ÷ 100 | unit conversion |
| CO2 | ppmv or ppm | ppm | ppmv is treated as ppm by volume | identity |
| Saturated K (Ksat) | source soil hydraulic unit | mm/h | convert to mm/h before writing *.SOL |
unit conversion |
| Soil bulk density | kg/m³ or g/cm³ | g/cm³ (= Mg/m³) | kg/m³ ÷ 1000 | multiplicative |
| Soil organic C | g/kg or percent by weight | percent by weight | g/kg ÷ 10 | multiplicative |
| Soil pH | dimensionless | dimensionless | use as-is | identity |
| N applied | lb/ac or kg/ha | kg/ha | lb/ac × 1.12085; kg/ha unchanged | multiplicative |
Crop yield output YLDG |
APEX output | t/ha dry matter | do not compare directly to bu/ac or kg/ha without conversion | output unit |
Above-ground biomass output BIOM |
APEX output | see dag.yaml |
use dag unit when scoring | output unit |
Water yield output WYLD |
APEX output | mm, or m³ in mass balance block | check output block before scoring | output unit |
Evapotranspiration output ET |
APEX output | see dag.yaml / output block |
check output block before scoring | output unit |
Deep percolation output DPRK |
APEX output | see dag.yaml / output block |
check output block before scoring | output unit |
Sediment yield output Y |
APEX output | t/ha | do not compare directly to t/ac or kg/ha without conversion | output unit |
Sign Conventions and Output Units
APEX reports agronomic and hydrologic annual outputs as positive magnitudes in the
printed output tables used by tools/s7_parse_output.py. For water-balance checks,
use the documented closure convention:
PCP ≈ WYLD + ET + DPRK + ΔS within ±5%.
Quickstart — run APEX on the bundled example
cd KISSPATH_KI_ROOT/APEX/knowledge_infrastructure
python preflight_check.py
python tools/s6_run_apex.py --workspace /tmp/apex_run --use-example
python tools/s7_parse_output.py --workspace /tmp/apex_run --out /tmp/apex_run/results.csv
Expected output: 15-year simulation (1979–1993) of a 1.63 ha pasture subarea in Marena OK; annual water yield ≈ 584 mm/yr; ET ≈ 348 mm/yr (1979–93 mean).
Quickstart — run APEX on a new lat/lon
from tools.s1_setup_workspace import setup
from tools.s2_convert_forcing import build_forcing
from tools.s3_build_soil import build_soil
from tools.s4_update_site import update_site
from tools.s5_update_control import update_control
from tools.s6_run_apex import run
from tools.s7_parse_output import parse
ws = setup("/tmp/apex_bengbu") # copy template
build_forcing(ws, lat=32.94, lon=117.36, year1=2010, year2=2015) # CMFD → DLY+WP1+WND
build_soil(ws, lat=32.94, lon=117.36) # HWSD → SOL
update_site(ws, lat=32.94, lon=117.36, elev_m=23.0)
# spinup_years=25 prepends 25 extra years (soil equilibration). ngn=2 = generate
# TMAX from WP1 monthly stats, read all other variables from DLY.
update_control(ws, year1=2010, year2=2015, ngn=2, spinup_years=25)
run(ws) # wine APEX0806.exe
df = parse(ws) # → DataFrame; spinup rows marked
df_actual = df[~df["spinup"]] # filter to analysis period
Important: also copy a validated OPC file to the workspace (or generate one with s9_generate_crop_opc.py) and update OPSCCOM.DAT to point subareas at it. s9 generates APEX0806-compatible op codes (136/261/292) and fertilizer codes (53/54). Do NOT use OPC files from APEX1501 runs — the op codes are different.
Output files (key ones — tools/s7 parses these)
| File | What it contains |
|---|---|
<run>.OUT |
Master annual print (per subarea, per year) — most important |
<run>.SAD |
Daily subarea output (when IPD specifies daily) |
<run>.SUS |
Subarea summary |
<run>.ACY |
Annual crop yield |
<run>.MAN |
Watershed manure summary |
<run>.MSW |
Monthly subarea water |
<run>.DPS |
Daily pesticide |
<run>.AWP |
Annual watershed pesticide |
<run>.HYC |
Hydrograph at watershed outlet |
RUN1501.SUM |
Multi-run summary (one row per APEXRUN.DAT entry) |
EPICERR.DAT |
Error log (check this if a run crashes) |
Annual *.OUT rows that matter for water balance verification:
- PCP (precipitation, m³ for whole watershed)
- WYLD (water yield)
- ET (evapotranspiration)
- DPRK (deep percolation)
- PER (percolation)
- DF (delta storage)
Closure: PCP ≈ WYLD + ET + DPRK + ΔS (within ±5%).
Output Description (template §6)
Source of truth: dag.yaml. This section restates the KI's dag facts for readers;
if this section and dag.yaml ever disagree, dag.yaml wins.
Headline output (dag validation_rank: 1):
YLDG— Crop grain yield, dry matter (harvest index x above-ground biomass, reduced by water stress and pest factor) (t/ha)
Output variable (dag var) |
Rank | Unit | Description / role |
|---|---|---|---|
YLDG |
1 | t/ha |
Crop grain yield, dry matter (harvest index x above-ground biomass, reduced by water stress and pest factor) |
BIOM |
see dag.yaml |
see dag.yaml |
Other dag output |
LAI |
see dag.yaml |
see dag.yaml |
Other dag output |
WYLD |
see dag.yaml |
see dag.yaml |
Other dag output |
ET |
see dag.yaml |
see dag.yaml |
Other dag output |
DPRK |
see dag.yaml |
see dag.yaml |
Other dag output |
Y |
see dag.yaml |
see dag.yaml |
Other dag output |
N losses (leaching / runoff / sediment) |
see dag.yaml |
see dag.yaml |
Other dag output |
P losses (soluble runoff / sediment / tile) |
see dag.yaml |
see dag.yaml |
Other dag output |
outlet hydrograph (HYC) |
see dag.yaml |
see dag.yaml |
Other dag output |
APEX0806 vs APEX1501 — critical differences
The KI uses APEX0806 (PE32 Windows binary via Wine). APEX1501 is a native Linux binary but has a confirmed P-cycling NaN bug that produces zero biomass for annual crops. Never use apex1501 for crop yield work.
Operation codes (DIFFERENT between versions — mixing them silently misfires)
| Action | APEX0806 code | APEX1501 code |
|---|---|---|
| Plant / drill | 136 | 132 |
| Fertilize | 261 | 580 |
| Harvest grain | 292 | 316 |
| Field cultivator | 151 | 151 (same) |
| Cultivation | 157 | 157 (same) |
| Kill crop | 451 | 397 |
Fertilizer codes (APEX0806 FERTCOM.DAT only has entries 1–72)
| Nutrient | Safe code | Name | Notes |
|---|---|---|---|
| Nitrogen | 53 | Elem-N, 100%N | Use this, not 92 |
| Phosphorus | 54 | Elem-P, 100%P | Use this, not 93 |
Fert codes 92/93 do NOT exist in APEX0806's FERTCOM.DAT. They trigger a
Fortran PAUSE that blocks the process indefinitely when running via Wine
without a tty (see triplet fert_code_pause).
File ecosystem differences
APEX0806 uses COM-style list files (CRLF required):
| APEX0806 file | APEX1501 equivalent | Purpose |
|---|---|---|
WDLSTCOM.DAT |
WDLYLIST.DAT |
Daily weather station list |
WPM1.DAT |
WPM1LIST.DAT |
Monthly weather parameter list |
WINDCOM.DAT |
WINDLIST.DAT |
Wind parameter list |
SITECOM.DAT |
SITELIST.DAT |
Site list |
SOILCOM.DAT |
SOILLIST.DAT |
Soil list |
OPSCCOM.DAT |
MNGTLIST.DAT |
Operation schedule list |
SUBACOM.DAT |
SUBSLIST.DAT |
Subarea list |
COM-style list files require CRLF (\r\n) line endings. APEXCONT.DAT and
OPC files use LF. Writing COM files with LF-only causes silent misreads.
Wine execution — CONOUT$ trap
APEX0806 writes status messages to the Windows console handle CONOUT$. When
running under Wine without a controlling tty (nohup, background &, systemd),
Fortran WRITE(*,...) fails with:
forrtl: severe (38): error during write, unit -1, file CONOUT$
Fix: always invoke via Python subprocess with capture_output=True (s6 already
does this). Never launch with nohup wine APEX0806.exe & directly from the shell.
Spin-up requirement
The ex1_RiselTX template has Texas soil at Texas-climate equilibrium. For any non-Texas location, a minimum 20–25 year spin-up is required before the soil water/nutrient pools reach steady state for the new climate. Without spin-up: WS > 50, yields < 2 t/ha for the first several years regardless of management.
s5_update_control.py handles this via --spinup-years N (default 25). The forcing
dataset is recycled over the spin-up years. s7_parse_output.py marks spin-up rows
with spinup=True for easy filtering.
Known traps & quirks (from the 1501 binary specifically)
- Filenames are case-sensitive on Linux — APEX1501 reads filenames literally
from
APEXFILE.DATand other list files. IfSITELIST.DATsaysSITE01.SITbut the actual file isSITE01.sit, you get aFile ... IS MISSINGerror and silent exit 0. Always use uppercase extensions on disk. APEXFILE.DATrequires theLWE.DATline — if you take a dataset from a pre-1501 build, you must append aFLWE LWE.DATline and create an emptyLWE.DATfile (or the binary EOFs at unit 22).- Subarea
*.SUBfiles need ≥22 lines for apex1501 — the manual documents 12 lines per subarea, but apex1501 reads beyond and EOFs at MAIN_1501.f90:2858. Pad with rows of0.00until the file has 22 lines. APEXCONT.DATis structured — apex1501 expects ≥6 lines plus a long block of zero rows (the EPIC-derived padding pattern). Use the example template.- Negative WSA in
*.SUBsignals "this subarea's runoff is added to another subarea before routing further downstream" — easy to set wrong. - CHL == RCHL identifies a headwater (extreme) subarea. CHL > RCHL identifies a downstream subarea. Setting CHL < RCHL is invalid.
AYEAR.DATmust contain the simulation start year as a single integer line — if missing, weather generator will silently spin its own random sequence.EPICERR.DAT— the error log file. Always check this after a crash; it often holds the real diagnostic message that the stderrforrtl: severe (...)doesn't reveal.- Statically linked — no
LD_LIBRARY_PATH, no patchelf needed; runs on any Linux x86-64 from kernel 3.2+. - Exit code is always 0 even on Fortran severe errors — never trust the exit
code; always check whether
RUN1501.SUMwas written and whether*.OUTcontains the closingTOTAL RUN TIMEline.
Scoring YLDG (or BIOM) against a gridded / regional-aggregate yield (GDHY, SPAM, FAOSTAT)
When the obs is a GDHY 0.5-degree cell (~2500 km2 cropland area-average), a
SPAM pixel/region, or a national FAOSTAT series, it is a
regional_aggregate_time_series, NOT a point_time_series. A GDHY cell is an
area-average over an entire 0.5-deg of mixed cropland, not a field trial. Two
MANDATORY setup rules (dag.yaml outputs[YLDG].observability, lines 146-151):
-
Classify as an aggregate and DETREND before scoring variability. Set
obs_shape=regional_aggregate_time_series,comparison_mode=aggregate_trend_comparison. Regional/gridded yields carry a technology/management trend (e.g. the Bengbu 32.75N,117.25E GDHY cell rises ~3.0 -> 4.7 t/ha over 1981-2016) that a fixed-management, weather-driven APEX run structurally CANNOT reproduce. Before comparing inter-annual variability, apply adetrending_option(linear_residualorfirst_difference) to BOTH sim and obs and compute r on the residuals; report levelpbiasfor magnitude AND detrendedrfor pattern. NEVER score the raw levels of a trended aggregate aspoint_time_series-- that yields spuriously catastrophic scores (this case: nse -20.5, r 0.06 against a trend the model was never expected to track). -
Management must be CELL-AVERAGE representative, not field-optimal. A single high-input subarea (PHU1800, N=184.8 kg/ha at full potential) yields the field-trial optimum ~6.7 t/ha -- nearly 2x the GDHY cell average of ~3.4 t/ha (this case: pbias +96%). Disabling auto-irrigation ALONE is insufficient. For a 0.5-deg area-average, configure management representative of the actual regional cropping: reduce N toward the regional mean application rate, use the regional cultivar/PHU, keep the dominant water regime (rainfed/supplemental for the Huai plain), and/or apply an area-weighted marginal-land fraction, so the simulated MEAN targets the GDHY cell mean (~3.4 t/ha) rather than the field-trial validation target (5.6-6.2 t/ha). This is a representativeness setup choice (dag
scope_in: management/fertilization/irrigation), NOT parameter calibration.
Validated Results (template §11)
Test case: Bengbu China corn
| Property | Value |
|---|---|
| Location | Bengbu, China |
| Crop | corn |
| Simulated yield | 6.21 t/ha |
| Observed yield | 5.6 t/ha |
| Reported bias | +11% |
| Validation status | validated |
Performance Metrics — judged against the field's bar, not intuition
Source of truth: docs/validation_convention.yaml. The convention wins over
remembered thresholds. Every band below carries the citation key supplied by the
convention.
| Dag variable | Metric | Direction | Very good | Good | Satisfactory | Citation key |
|---|---|---|---|---|---|---|
YLDG |
pbias |
zero_centered | 5.0 | 10.0 | 15.0 | jiang2021 |
YLDG |
nrmse |
minimize | 10.0 | 20.0 | 30.0 | jiang2021 |
BIOM |
nrmse |
minimize | 10.0 | 20.0 | 30.0 | jiang2021 |
BIOM |
pbias |
zero_centered | 5.0 | 10.0 | 15.0 | jiang2021 |
For zero-centered pbias, compare the absolute bias magnitude to the cited band.
For minimize nrmse, lower values are better. No uncited threshold is implied for
any metric or output not listed in docs/validation_convention.yaml; write
no cited threshold when the convention has a null band.
Data Replacement Tracking
| Component | Source | Status | Notes |
|---|---|---|---|
| Forcing | CMFD weather pipeline | validated for the Bengbu China corn case | Prepared through KI tools |
| Soil | HWSD soil pipeline | validated for the Bengbu China corn case | Prepared through KI tools |
| Management / crop calendar | GGCMI calendar and APEX0806-compatible operation schedules | validated for the Bengbu China corn case | Use tools/s9_generate_crop_opc.py for compatible op and fertilizer codes |
| Execution binary | reference/APEX0806.exe via Wine |
validated | Use v0806 for crop-yield work |
| Parsing and scoring | tools/s7_parse_output.py; docs/validation_convention.yaml |
validated convention available | Score against cited bars, not intuition |
References
- APEX1501 User Manual (November 2023), Steglich et al., Texas A&M AgriLife https://epicapex.tamu.edu/media/pkff4m34/the-apex1501-user-manual-november-2023.pdf
- APEX1501 Theoretical Documentation (January 2023), Williams et al. https://epicapex.tamu.edu/media/2mwdlhte/the-apex1501-theoretical-documentation-january-2023.pdf
- Williams, J. R., et al. (2008). The APEX model. In Watershed Models. CRC Press.
- pyAPEXSCU (Maskey et al.) — published worked example used as our test dataset https://github.com/mlmaskey/pyAPEXSCU