<< All versions

Skill v1.0.0

currentAutomated scan100/100
lzwei196/kiss-knowledge-infrastructure-for-scientific-simulation/lpj-guess
──Details
PublishedNovember 1, 2026 at 01:58 AM
Content Hashsha256:98607d9f8bdd19cb...
Git SHA83b757d15c2a
──Files
Files (1 file, 22.7 KB)
SKILL.md22.7 KBactive
SKILL.md · 382 lines · 22.7 KB

metadata: version: "1.0.0"


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. 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:
1. Check triplets — diagnostics/triplets.yaml may already cover this error
2. Read official docs — Check the model's own documentation (PDF manual, README,
official examples) for expected input formats, variable names, and units
3. Find working examples — Look in outputs/ for previous successful runs of
this model, or check if the model ships with test/example data
4. Fix the tool — Now that you know what "correct" looks like, make targeted fixes
Resist the urge to write diagnostic/debug Python scripts. The answers are almost
always in the official docs and working examples, not in reverse-engineering the binary.

<!-- KI-MAP:BEGIN (projected by generate_skill_map.py — edit the KI, not this table) -->

KI map — what to read, and when

when you needreadwhy
FIRST, alwayspreflight_check.pyrun 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 stagestools/ (8 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 stagedocs/s*_*.md (9 stage docs)per-stage procedure, verification and traps — the how-to that SKILL.md's overview compresses.
on ANY error, before debuggingdiagnostics/triplets.yaml (35 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 ISdag.yamlthe 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 outputsdocs/format_spec.yamlexact 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 skilldocs/validation_convention.yamlhow 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 thresholdsdocs/gathered_papers.json (20 papers) + docs/papers_index.mdthe 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 summaryknowledge_infrastructure.yamlthe manifest (package, pipeline, validation tier, counts) — projected by ki_tools_common/generate_ki_manifest.py; regenerate after structural changes, never hand-edit.

Projected 2026-10-07 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_lpjguess_cf_forcing.pyKISSPATH_PYTHON_ENV/bin/python {KI}/tools/build_lpjguess_cf_forcing.py --help
tools/build_lpjguess_co2_file.pyKISSPATH_PYTHON_ENV/bin/python {KI}/tools/build_lpjguess_co2_file.py --help
tools/convert_forcing_to_lpjguess.pyKISSPATH_PYTHON_ENV/bin/python {KI}/tools/convert_forcing_to_lpjguess.py --help
tools/convert_parameters_to_lpjguess.pyKISSPATH_PYTHON_ENV/bin/python {KI}/tools/convert_parameters_to_lpjguess.py --help
tools/parse_lpjguess_engine_output.pyKISSPATH_PYTHON_ENV/bin/python {KI}/tools/parse_lpjguess_engine_output.py --help
tools/parse_output_lpjguess.pyKISSPATH_PYTHON_ENV/bin/python {KI}/tools/parse_output_lpjguess.py --help
tools/run_lpjguess.pyKISSPATH_PYTHON_ENV/bin/python {KI}/tools/run_lpjguess.py --help
tools/run_lpjguess_engine.pyKISSPATH_PYTHON_ENV/bin/python {KI}/tools/run_lpjguess_engine.py --help

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

LPJ-GUESS -- Knowledge Infrastructure Skill Document

Version: LPJ-GUESS 4.1.1 (real engine) — KI rewired 2026-10-07
Domain: terrestrial biogeochemistry / dynamic vegetation (C, N, water)
Last updated: 2026-10-07
Validation status: real engine; official demo reproduced exactly; one FLUXNET site scored as validation, untuned (manifest tier tested)
Default run route: tools/run_lpjguess_engine.py (the real guess binary). The surrogate is never the default.
SURROGATE WARNING. tools/run_lpjguess.py, convert_forcing_to_lpjguess.py,
convert_parameters_to_lpjguess.py and parse_output_lpjguess.py are a **Python
light-use-efficiency SURROGATE** (LUE GPP + Q10 respiration) kept for history. They are
not LPJ-GUESS and their numbers (e.g. a calibrated GPP NSE ~0.90) must never be reported
as LPJ-GUESS results (dt_lpjguess_033). Their old contract is kept apart in
docs/surrogate_lpjguess_lue_dag.yaml; their old scores sit only under
validation.surrogate_metrics_not_lpjguess in knowledge_infrastructure.yaml. Triplets
dt_lpjguess_001-004 and 011-014 apply to the surrogate only (applies_to: surrogate). Every
result in this document comes from the real engine through the four *_engine* /
build_lpjguess_* tools.

1. Model Identity

PropertyValue
Full nameLund-Potsdam-Jena General Ecosystem Simulator
Version4.1.1 research release
SourceZenodo record 8065737 (doi 10.5281/zenodo.8065737), linked from https://web.nateko.lu.se/lpj-guess/download.html
LicenseMPL-2.0
LanguageC++ (cmake), NetCDF C for the CF input module
BinaryKISSPATH_HOME/engine_builds_20261006/LPJ_GUESS/build/guess (ELF, 1.4 MB)
Engine sourceKISSPATH_HOME/engine_builds_20261006/LPJ_GUESS/src/
Build logKISSPATH_HOME/engine_builds_20261006/LPJ_GUESS/BUILD_LOG.md
Key papersSmith et al. 2001 (GEB 10:621); Smith et al. 2014 (Biogeosciences 11:2027); Sitch et al. 2003 (GCB 9:161)

2. What This Model Does

LPJ-GUESS simulates vegetation and soil carbon, nitrogen and water from daily weather and CO2. Plants are individuals/cohorts of plant functional types (12 global PFTs in global.ins) that compete for light and water on replicate patches; establishment, mortality and disturbance run yearly. Daily processes: photosynthesis and stomatal conductance (canexch.cpp), multi-layer soil water and snow (soil.cpp), autotrophic respiration; CENTURY soil organic matter with a coupled N cycle (somdynam.cpp, ntransform.cpp); fire (GLOBFIRM here; BLAZE needs files not on the server).

The engine reads climate through input modules: demo (toy monthly climate, used for the official demo), cru (CRU binary archives, not on the server) and cf (CF-NetCDF — what this KI uses for real sites).

Capabilities wired by this KI (full list: docs/input_preparation.md §1):

  1. [PRIMARY] Site carbon/water fluxes — GPP, Ra, Rh, Reco, NEE, NPP, ET components, monthly and annual.
  2. Official demo / install check — 13 cells, byte-exact against the build-time run.
  3. Vegetation composition — PFT selection via --set 'pft "X" ( include 0 )'.
  4. Fire model choice — --firemodel GLOBFIRM|NOFIRE|BLAZE.
  5. Spin-up / patch / any `.ins` switch — --nyear_spinup, --npatch, --set.
  6. Water fluxes — transpiration, soil evaporation, interception, runoff, PET + water-balance check.
  7. Scoring against FLUXNET2015 monthly GPP/NEE/RECO/ET.

Not wired yet: crops/land cover/managed forest, transient N deposition, sub-daily output.

3. Input Requirements

Exact shapes: docs/format_spec.yaml (projected from dag.yaml). Preparation plan with the verified shared-library schema: docs/input_preparation.md.

3.1 Meteorological Forcing (CF input, daily)

VariableUnit the engine checksCF standard_nameBuilt from loader key
tempKair_temperaturetemp_mean_c + 273.15
preckg m-2 s-1precipitation_fluxprecip_mm / 86400
insolW m-2 (24-h mean)surface_downwelling_shortwave_flux_in_airsrad_wm2
min_temp / max_tempKair_temperaturetemp_min_c / temp_max_c + 273.15
relhum1 (fraction)relative_humidityfrom shum_kgkg, pres_pa, temp
windm s-1wind_speedwind_ms (10 m)

At least 30 full years are required (spin-up climate = first 30 years; dt_lpjguess_021). Data source used: NASA POWER (global, proxy-safe, ~4 s/yr; shortwave from 1984). FLUXNET met is too short (≤26 yr); CMFD is China-only; MSWX is slow and its 1979 file is broken.

3.2 Static Inputs

InputFileNote
CO2models/LPJ_GUESS/inputs/co2/co2_1901_2014.txtLaw Dome (pre-1959) + NOAA Mauna Loa; not shipped with 4.1.1 (dt_lpjguess_022)
Soil codeshipped src/data/env/soils_lpj.datrun tool adds an exact site line (dt_lpjguess_019/020)
Gridlistgridlist_cf.txt0 0 <site> — array INDICES (dt_lpjguess_024)
N depositionnoneconstant pre-industrial 2 kgN/ha/yr (dt_lpjguess_035)

3.3 Configuration Files

Copied from src/data/ins/: global.ins (PFTs + switches), global_cf.ins (file paths, imports global.ins and global_soiln.ins), global_demo.ins. The cf mode writes site_cf.ins = global_cf.ins with only the param "file_*" values replaced on active lines, plus appended overrides (later lines win). Nothing is generated from scratch.

4. Build Instructions

Already built — do not rebuild for KI work. For reference (BUILD_LOG.md):

bash
cd KISSPATH_HOME/engine_builds_20261006/LPJ_GUESS/build
cmake ../src -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM=3.5
make -j4 # 7 s, warnings only; NetCDF found -> cf input compiled in

5. Execution

bash
PY=KISSPATH_PYTHON_ENV/bin/python; KI=KISSPATH_KI_ROOT/LPJ_GUESS/knowledge_infrastructure
$PY $KI/preflight_check.py
# official demo (~4 min), compared with the build-time reference:
$PY $KI/tools/run_lpjguess_engine.py example --out_dir /tmp/lpj_demo
# a FLUXNET site:
$PY $KI/tools/build_lpjguess_cf_forcing.py --site DE-Tha --lat 50.9624 --lon 13.5652 \
--start_year 1984 --end_year 2014 --source nasa_power --out_dir forcing
$PY $KI/tools/run_lpjguess_engine.py cf --forcing_meta forcing/forcing_meta.json \
--co2_file KISSPATH_KI_ROOT/LPJ_GUESS/inputs/co2/co2_1901_2014.txt --out_dir run_detha
$PY $KI/tools/parse_lpjguess_engine_output.py --run_dir run_detha/run --out_dir parsed \
--fluxnet_dir KISSPATH_OBS/fluxnet/sites/DE-Tha \
--forcing_meta forcing/forcing_meta.json --figure fig.png --site DE-Tha
# (a run with several cells: add --cell LON LAT; cells are never averaged)

The example mode needs the complete build-time reference <engine>/run_global_demo (19 .out files); a missing, empty or incomplete reference is exit 5, never a pass. --reference_dir '' skips the check and the JSON then says "reproduced": false. Headless command underneath: cd <run> && guess -input cf site_cf.ins (or -input demo global_demo.ins). Run tool exit codes: 0 ok, 2 bad input, 3 engine failed (rc≠0, no Finished, timeout), 4 outputs missing/incomplete, 5 demo differs from reference. The engine's own failures exit 99 with a bare message in guess.log (no "Error" prefix — dt_lpjguess_030).

6. Output Description

From dag.yaml (authoritative). The rank-1 output is GPP — "Gross Primary Production (terrestrial vegetation carbon assimilation flux)." (umol/m2/s).

dag varrankdag unitengine table (native unit)
GPP1umol/m2/smgpp.out kgC m-2 month-1 (GPP minus leaf respiration)
NPP2umol/m2/smnpp.out (= mgpp − mra)
Ra3umol/m2/smra.out
Rh4umol/m2/smrh.out
Reco5umol/m2/smra.out + mrh.out
NEE6umol/m2/smnee.out (= mrh − mnpp; + = source; fire C excluded)

Other tables: annual cmass (kgC m-2 per PFT), lai, fpc, agpp, anpp, aaet, cflux, cpool, dens, tot_runoff; monthly maet (transpiration only), mevap, mintercep, mrunoff, mpet, mlai. Tables are whitespace columns Lon Lat Year ..., 3 decimals. The parser's annual.csv keeps every annual table of the run (incl. dens, doc, cton_leaf and the nitrogen tables) and every column of each, as <table>_<column> (per-PFT cmass_TeBS, cflux_Fire, cpool_SoilC, npool_SoilN, ...).

7. Tool Inventory

ToolKindPurposeOutput
tools/build_lpjguess_cf_forcing.pyenginedaily CF NetCDF forcing via load_daily_forcing + validate_outputs7 .nc, gridlist, forcing_meta.json
tools/build_lpjguess_co2_file.pyengineannual CO2 file from Law Dome + Mauna Loa<year> <ppm> text
tools/run_lpjguess_engine.pyenginerun guess (example / cf) with success checksrun dir + JSON
tools/parse_lpjguess_engine_output.pyenginetables → CSV, water balance, FLUXNET metrics, figureCSV, summary.json, PNG
tools/run_lpjguess.pySURROGATEPython LUE stand-innot LPJ-GUESS
tools/convert_forcing_to_lpjguess.pySURROGATECSV forcing for the stand-in—
tools/convert_parameters_to_lpjguess.pySURROGATELUE parameter JSON—
tools/parse_output_lpjguess.pySURROGATEparses stand-in CSV—

Stage docs: docs/s6_build_cf_forcing.md, docs/s7_build_co2_file.md, docs/s8_run_engine.md, docs/s9_parse_engine_output.md (engine); docs/s1_preflight.md; docs/s2–s5 (surrogate).

Shared Utilities (ki_tools_common)

load_forcing.load_daily_forcing (forcing), validation.validate_forcing_ranges and validate_water_balance, metrics.all_metrics (keys NSE KGE PBIAS RMSE r).

8. Unit Conversion Table

VariableSource unit (verified)Engine unitOperation
Air temperature°C (loader)K+ 273.15
Precipitationmm/day (loader)kg m-2 s-1÷ 86400
ShortwaveW m-2 daily mean (loader)W m-2× 1
Humiditykg/kg + Pa + °Cfractione = q·p/(0.622+0.378q); RH = e/es(T)
Monthly carbon outkgC m-2 month-1gC m-2 d-1× 1000 ÷ days in month
Carbon fluxgC m-2 d-1µmol CO2 m-2 s-1× 1e6/12.011/86400 = 0.9636
Monthly water outmm month-1mm d-1÷ days in month
Tower LEW m-2mm d-1× 0.0864/2.45

8b. CMFD/MSWX Data Conventions

The loader returns °C, mm/day and W m-2 for every source; this KI converts once, in build_lpjguess_cf_forcing.py. CMFD covers China only. MSWX P_1979.nc has a faulty time axis, so MSWX runs start in 1980.

8c. Sign Conventions and Output Units

NEE: positive = carbon source (same as FLUXNET NEE_VUT_REF). GPP, Ra, Rh, NPP positive. FLUXNET2015 MM files are in gC m-2 d-1, so scoring is done in that unit.

9. Diagnostic Triplets (Top 5)

The entries in diagnostics/triplets.yaml (current count: the KI map at the top of this file); dt_lpjguess_019–035 are real-engine traps reproduced on this server. Most important:

  • dt_lpjguess_019 — searchradius_soil segfaults -input cf (engine bug); the tool adds a site soil line instead.
  • dt_lpjguess_021 — CF forcing needs ≥30 years.
  • dt_lpjguess_026 — maet is transpiration only; ET = maet + mevap + mintercep.
  • dt_lpjguess_027 — default run = potential natural vegetation, not the planted stand.
  • dt_lpjguess_033 — surrogate output is not LPJ-GUESS.

10. Coupling Interfaces

Inputs are CF-NetCDF files and text; outputs are whitespace tables. A coupler can feed any daily CF forcing on a lat/lon grid (gridlist = indices) and read the monthly tables.

11. Validated Results

Official example (global_demo)

run_lpjguess_engine.py example (2026-10-07): rc 0, Finished, 252 s, years 500–599, 19/19 `.out` files byte-identical to the build-time run (max abs diff 0). Matches the build log (e.g. final-year total cmass: Amazon 16.497, C. Europe 8.466, Canada boreal 4.847 kgC m-2).

Test site: DE-Tha (Tharandt, Germany; 50.9624 N, 13.5652 E; planted Norway spruce)

Role: validation only. Nothing was calibrated. Default, untuned run: all 12 global PFTs as shipped in global.ins (potential natural vegetation, PNV), GLOBFIRM fire, 500-year spin-up, constant pre-industrial N deposition. Forcing NASA POWER 1984-2014 at the tower point (not tower meteorology); CO2 Law Dome + NOAA Mauna Loa (1901-2014); soil code 2 from the 0.5-degree cell (13.75, 50.75). Engine run 15 s, last year 2014.

Scored run (2026-10-07, KDT detached run): KISSPATH_KI_ROOT/LPJ_GUESS/detached/real_case/752ec75aabc741d9b7a241e383174692/work/run_detha/run (an earlier identical run, same mgpp.out bytes: KISSPATH_OUTPUTS/lpjguess_detha_real_engine/run). Figure: KISSPATH_KI_ROOT/LPJ_GUESS/figures/s8_validation.png.

Observations: FLUXNET2015 FULLSET_MM for DE-Tha. Months kept where NEE_VUT_REF_QC >= 0.5; the same 221 months for every variable, 1996-07 .. 2014-12. Compared in gC m-2 d-1 (mm d-1 for ET):

Variable (monthly)enginetowerNSEKGErPBIAS %RMSE
GPP (dag rank 1)mgpp (GPP minus leaf resp.)GPP_NT_VUT_REF0.6900.6110.963−34.82.22
Recomra + mrhRECO_NT_VUT_REF0.8510.8530.950−12.00.89
NEEmnee (= mrh − mnpp, no fire C)NEE_VUT_REF0.0060.0480.826−83.51.77
ET (not a dag output)maet + mevap + mintercepLE_F_MDS × 0.0864/2.450.6860.6550.927+8.80.43 mm d-1

Means: GPP obs 5.36 vs engine 3.49; NEE obs −1.67 vs engine −0.28; Reco obs 3.66 vs 3.22; ET obs 1.11 vs 1.20. Water balance over 1984-2014: P 22408 mm, ET 13483 mm, runoff 8836 mm, residual 89 mm (0.4 %). Re-scored from the existing outputs with ki_tools_common.metrics.all_metrics and plain numpy (they agree): KISSPATH_HOME/ki_fix_campaign/kdt_real_engine/review_LPJ-GUESS/score_detha.py.

Judged against `docs/validation_convention.yaml` (GPP, Reco, NEE: headline NSE, only cited band = satisfactory NSE ≥ 0, walker2014; no good/very-good tier is cited): GPP 0.69 and Reco 0.85 pass the floor. NEE 0.006 is above the floor by a hair, i.e. no real skill beyond the observed mean; treat NEE as not reproduced. ET has no dag entry.

Known bias (why GPP and NEE are too small). The default run grows PNV, not the planted spruce stand: in 2014 cmass is 5.96 of 6.77 kgC m-2 temperate broadleaf summergreen (TeBS) and only 0.21 needleleaf (BNE + BINE). So winter GPP is near zero (Dec-Feb calendar-month means: engine 0.02-0.07 vs tower 0.51-0.97 gC m-2 d-1) and the summer peak is low (June mean 8.2 vs 11.2; dt_lpjguess_027); mgpp also excludes leaf respiration (dt_lpjguess_025). NEE: the 500-year spin-up grows unmanaged natural vegetation (no planting, thinning or harvest), so the stand has no young managed-stand history and the sink is far too small (dt_lpjguess_034). Zhu et al. 2020 report a site-mean GPP RMSE of 2.13 gC m-2 d-1 as context (not a gate).

Side test (a configuration choice, not calibration, and NOT the reported result): only BNE + C3G allowed (--set 'pft "X" ( include 0 )' for the other 10 PFTs), same forcing: GPP NSE 0.80, PBIAS −25.8 %; Reco NSE 0.87; ET NSE 0.72; NEE NSE −0.22 (KISSPATH_OUTPUTS/lpjguess_detha_real_engine/sensitivity_needleleaf_only/).

Data Replacement Tracking

ComponentSourceStatus
ForcingNASA POWER via load_daily_forcingreal data
CO2Law Dome + NOAA Mauna Loareal data
Soilshipped LPJ soil-code mapshipped data
N depositionconstant pre-industrialdefault (file missing)
EngineLPJ-GUESS 4.1.1 binaryreal model
ObservationsFLUXNET2015 DE-Thaindependent

12. Parameter Selection by Region

No parameter calibration is done; PFT traits stay as shipped. Choose PFTs for managed stands (e.g. spruce: BNE; pine: BNE/TeNE; beech: TeBS); for tropical sites keep TrBE/TrIBE/TrBR. Soil code comes from the 0.5° map.

13. Known Limitations

  • Weather is reanalysis at the tower point, not tower met.
  • No N-deposition file; no BLAZE fire; no crops/land-cover in the KI tools.
  • Monthly tables have 3 decimals (~0.03 gC m-2 d-1 resolution).
  • dag.yaml was updated by hand on 2026-10-07 to the real engine (outputs kept); it was not regenerated by ki_dag_generator.

14. Spinup Requirements

nyear_spinup 500 (shipped default), cycling the first 30 forcing years (detrended temperature). The calendar starts 500 years before the first forcing year and CO2 is read by calendar year (cfinput.cpp set_first_calendar_year, co2[date.get_calendar_year()]); years before the CO2 file's first year get its first value (globalco2file.cpp). For DE-Tha (forcing 1984-2014, CO2 file 1901-2014) the spin-up covers 1484-1983: 1484-1900 at 296.2 ppm, then 1901-1983 with the real rising CO2 record. Then the real years. N limitation is off for the first 100 spin-up years (freenyears). Boreal/peat sites may need 1000+ years (dt_lpjguess_010).

15. References

  • Smith, B., Prentice, I.C., Sykes, M.T. (2001) Global Ecology & Biogeography 10, 621-637.
  • Smith, B. et al. (2014) Biogeosciences 11, 2027-2054.
  • Sitch, S. et al. (2003) Global Change Biology 9, 161-185.
  • Walker, A.P. et al. (2014) JGR Biogeosciences, doi 10.1002/2013JG002553 (NSE floor).
  • Zhu, Z. et al. (2020) ESSD 12, 2725 (GPP RMSE context).
  • Etheridge et al. (1996); MacFarling Meure et al. (2006) — Law Dome CO2; NOAA GML Mauna Loa CO2.
  • Full list: docs/gathered_papers.json, docs/papers_index.md.
All versions