ecosim-pftpar-editor
Edit EcoSIM PFT-parameter NetCDF files such as ecosim_pftpar_20260303.nc with the ParEditor class from applications/notebooks/scripts/ParamEditor.py. Use when asked to modify, scale, copy, compare, or
SKILL.md.agents/skills/ecosim-pftpar-editor/SKILL.md
GitHubEcoSIM PFT Parameter Editor (ParamEditor.py)
Use this skill to edit EcoSIM ecosim_pftpar_*.nc PFT-parameter NetCDF files
with the bundled ParEditor class. The canonical tool is
applications/notebooks/scripts/ParamEditor.py; treat it as the source of
truth. Do not reimplement NetCDF editing when this skill applies.
File boundary
Treat every plant_trait.*.desc file as read-only, including when the request is
phrased as editing plant trait parameters. Use a .desc file only for inspection
or validation. Apply requested parameter changes to the corresponding
ecosim_pftpar_*.nc file with ParamEditor.py. Never patch, overwrite, or emit a
replacement .desc file.
Locate the target file
- PFT-parameter NetCDF files usually live in EcoSIM run folders, for example
~/work/github/ecosim_workspace/<case>/input_data/ecosim_pftpar_YYYYMMDD.nc. Search the user-supplied run folder first, thenecosim_workspace/*/input_data/, then the repository (data/,templates/). - If the user gives only a date such as
20260303, matchecosim_pftpar_<date>.nc. If several run folders contain it, ask which case to edit, or edit all cases only when explicitly requested. - Templates exist as
.cdltext; do not edit.cdlfiles with this skill.
Environment and import pattern
Use the repository NetCDF-capable environment and import ParamEditor as a
package module (it does from . import stringTools internally, so it must be
imported as scripts.ParamEditor with applications/notebooks on sys.path):
# run with .venv-cmip6/bin/python from the repo root, or set cwd accordingly
import sys
sys.path.insert(0, 'applications/notebooks')
from scripts.ParamEditor import ParEditor
If .venv-cmip6/bin/python is unavailable, use any Python that can
import netCDF4.
Core API
| Method | Purpose |
|---|---|
ParEditor(pftparfile=path) |
Bind the editor to a PFT-parameter file. Optional micparfile= binds a microbe-parameter file. The change-log stem is the first dot-token of the file basename (for ecosim_pftpar_20260303.nc it is ecosim_pftpar_20260303); records are appended to <stem>.jsonl in the current working directory. |
reset(sure=True) |
Delete the recorded .jsonl change-log files. Call only when the user wants to clear history. |
PlantParamModify(pft, pars, iscale=False, verbose=True) |
Set parameters for one PFT. pars is a dict {varname: value} using exact NetCDF variable names such as VCMX, ETMX, RRAD1M. With iscale=False the value replaces the current value; with iscale=True the value multiplies the current value (a factor of 1.0 leaves it unchanged). |
CopyPlantPft(pft_from, pft_to) |
Copy all parameters from one PFT to another. If pft_to does not exist it is appended to the unlimited npfts dimension as a new record. |
PlantParCompare(pft1, pft2) |
Print parameters that differ between two PFTs. Use before copying to confirm the archetype. |
delete_pft_records(input_file, output_file, names_to_delete) |
Write a new NetCDF with the listed pfts codes removed; the input file is not modified. |
MicrobeParamModify(pars, iscale=False, verbose=True) |
Modify variables in the microbe-parameter file for all records (variable[:]). |
Workflow
List available PFT codes and locate the record before editing:
from netCDF4 import Dataset def pft_codes(pftparfile): with Dataset(pftparfile) as nc: return ["".join(c.decode('utf-8') if isinstance(c, bytes) else c for c in row).strip() for row in nc.variables['pfts'][:].filled(" ")] print(pft_codes(pftparfile))Use the exact six-character code. If the user names a plant, map it to a
pftscode and confirm the match (for example, ponderosa pine asndlf34).Back up before any in-place edit, because
PlantParamModifyandCopyPlantPftopen the file inr+mode and save immediately:mkdir -p result/pftpar_editor cp /path/to/ecosim_pftpar_20260303.nc result/pftpar_editor/ecosim_pftpar_20260303_backup_$(date +%Y%m%d_%H%M%S).ncRead the pre-edit values, apply changes, and read back the post-edit values in one session:
from netCDF4 import Dataset parEditor = ParEditor(pftparfile=pftparfile) pft = 'ndlf34' def pft_index(pftparfile, pft): with Dataset(pftparfile) as nc: codes = ["".join(c.decode('utf-8') if isinstance(c, bytes) else c for c in row).strip() for row in nc.variables['pfts'][:].filled(" ")] return codes.index(pft) def show(names): with Dataset(pftparfile) as nc: i = pft_index(pftparfile, pft) for n in names: print(n, nc.variables[n][i]) show(['VCMX', 'ETMX', 'RSRR']) # before # absolute replacement parEditor.PlantParamModify(pft, {'VCMX': 35.0, 'ETMX': 500.0}, iscale=False, verbose=True) # multiplicative scaling (factor) parEditor.PlantParamModify(pft, {'RSRR': 1.10}, iscale=True, verbose=True) show(['VCMX', 'ETMX', 'RSRR']) # afterTo create a new PFT from an archetype, compare first, then copy and adjust:
parEditor.PlantParCompare('ndlf34', 'ndlf32') parEditor.CopyPlantPft('ndlf34', 'ndlf36') parEditor.PlantParamModify('ndlf36', {'VCMX': 40.0}, verbose=True)To remove PFTs, always write to a new file (default under
result/), never overwrite the run-folder input in place:parEditor.delete_pft_records(input_file, 'result/pftpar_editor/ecosim_pftpar_pruned.nc', ['gr3s32', 'maiz31'])Verify and report:
- Re-open the file and print the edited variables for the target PFT.
- Report the change-log path (for example
./ecosim_pftpar_20260303.jsonlin the working directory) and its latest records. - Report the backup file path under
result/pftpar_editor/. - Warn that other run folders keep their own copy of
ecosim_pftpar_<date>.nc; propagate the same edit to other cases only on request.
Contract and cautions
- Never fabricate variable names: read them from the file first. A wrong name
raises
KeyErrorfromnc_file.variables[parnm]; stop and list the available variables instead of guessing. PlantParamModifywrites values with broadcasting; scalars are safe fornpfts-leading variables.- The
pftsvariable is a character array(npfts, nchars1=10); strip padding when matching codes. - Keep the JSONL change log; it is the audit trail of every modify call
(
{'pft':..., 'parvarnames':[...], 'parvals':[...]}). - Only call
reset()when the user explicitly asks to clear history, because it deletes the.jsonlfiles. - Do not use regex or text editing on NetCDF; edit variables directly through
netCDF4as ParamEditor.py does.