Skip to content

Process Package (swimrs.process)

Daily soil water balance engine with typed dataclasses, Numba kernels, and HDF5 SwimInput built from .swim containers.

Loop and IO

run_daily_loop(swim_input: SwimInput, parameters: CalibrationParameters | None = None, properties: FieldProperties | None = None) -> tuple[DailyOutput, WaterBalanceState]

Run the daily water balance simulation loop.

Parameters

swim_input : SwimInput Input data container (HDF5-backed) parameters : CalibrationParameters, optional Calibration parameters. If not provided, uses swim_input.parameters. properties : FieldProperties, optional Field properties. If not provided, uses swim_input.properties. Pass custom properties to use PEST++ calibrated values (awc, mad).

Returns

output : DailyOutput Daily output arrays final_state : WaterBalanceState Final state after simulation

step_day(state: WaterBalanceState, props: FieldProperties, params: CalibrationParameters, ndvi: NDArray[np.float64], etr: NDArray[np.float64], prcp: NDArray[np.float64], tmin: NDArray[np.float64], tmax: NDArray[np.float64], srad: NDArray[np.float64], irr_flag: NDArray[np.bool_], runoff_process: str = 'cn', prcp_hr: NDArray[np.float64] | None = None, f_sub: NDArray[np.float64] | None = None) -> dict[str, NDArray[np.float64]]

Execute a single daily time step.

This function orchestrates all the physics kernels in the correct sequence for one day of simulation.

Parameters

state : WaterBalanceState Current state (modified in-place) props : FieldProperties Static field properties params : CalibrationParameters Calibration parameters ndvi : (n_fields,) NDVI values etr : (n_fields,) Reference ET (mm/day) prcp : (n_fields,) Precipitation (mm) tmin : (n_fields,) Minimum temperature (°C) tmax : (n_fields,) Maximum temperature (°C) srad : (n_fields,) Solar radiation (W/m²), daily mean downward shortwave radiation irr_flag : (n_fields,) Irrigation flag for this day runoff_process : str Runoff mode: 'cn' for Curve Number or 'ier' for infiltration-excess prcp_hr : (24, n_fields,), optional Hourly precipitation (mm/hr), required for IER mode f_sub : (n_fields,), optional Year-specific groundwater subsidy fraction. If provided, overrides props.f_sub for this time step.

Returns

dict Daily output values

DailyOutput dataclass

Container for daily output arrays.

All arrays have shape (n_days, n_fields).

Attributes

n_days : int Number of simulation days n_fields : int Number of fields eta : NDArray[np.float64] Actual ET (mm/day) etf : NDArray[np.float64] ET fraction (ETa/ETr) kcb : NDArray[np.float64] Basal crop coefficient ke : NDArray[np.float64] Evaporation coefficient ks : NDArray[np.float64] Water stress coefficient kr : NDArray[np.float64] Evaporation reduction coefficient runoff : NDArray[np.float64] Surface runoff (mm) rain : NDArray[np.float64] Liquid precipitation (mm) melt : NDArray[np.float64] Snowmelt (mm) swe : NDArray[np.float64] Snow water equivalent (mm) depl_root : NDArray[np.float64] Root zone depletion (mm) dperc : NDArray[np.float64] Deep percolation (mm) irr_sim : NDArray[np.float64] Simulated irrigation (mm) gw_sim : NDArray[np.float64] Groundwater subsidy (mm) et_irr : NDArray[np.float64] ET from irrigation water (mm) - consumptive use dperc_irr : NDArray[np.float64] Deep percolation of irrigation water (mm) - return flow irr_frac_root : NDArray[np.float64] Irrigation fraction in root zone [0, 1] irr_frac_l3 : NDArray[np.float64] Irrigation fraction in layer 3 [0, 1]

n_days: int instance-attribute

n_fields: int instance-attribute

eta: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

etf: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

kcb: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

ke: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

ks: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

kr: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

runoff: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

rain: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

melt: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

swe: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

depl_root: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

dperc: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

irr_sim: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

gw_sim: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

et_irr: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

dperc_irr: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

irr_frac_root: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

irr_frac_l3: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

__post_init__()

Initialize output arrays.

__init__(n_days: int, n_fields: int, eta: NDArray[np.float64] = None, etf: NDArray[np.float64] = None, kcb: NDArray[np.float64] = None, ke: NDArray[np.float64] = None, ks: NDArray[np.float64] = None, kr: NDArray[np.float64] = None, runoff: NDArray[np.float64] = None, rain: NDArray[np.float64] = None, melt: NDArray[np.float64] = None, swe: NDArray[np.float64] = None, depl_root: NDArray[np.float64] = None, dperc: NDArray[np.float64] = None, irr_sim: NDArray[np.float64] = None, gw_sim: NDArray[np.float64] = None, et_irr: NDArray[np.float64] = None, dperc_irr: NDArray[np.float64] = None, irr_frac_root: NDArray[np.float64] = None, irr_frac_l3: NDArray[np.float64] = None) -> None

SwimInput(h5_path: Path, start_date: datetime = None, end_date: datetime = None, n_days: int = 0, n_fields: int = 0, fids: list = list(), runoff_process: str = 'cn', refet_type: str = 'eto', properties: FieldProperties = None, parameters: CalibrationParameters = None, spinup_state: WaterBalanceState = None, _h5_file: h5py.File = None, _gwsub_years: dict = dict()) dataclass

HDF5-backed input data container for soil water balance modeling.

This container provides all data needed for a SWIM-RS simulation run. It can be built from JSON input files and saved to HDF5 for distribution to PEST++ workers, or loaded directly from HDF5.

Attributes

h5_path : Path Path to the HDF5 file start_date : datetime Simulation start date end_date : datetime Simulation end date n_days : int Number of simulation days n_fields : int Number of fields/pixels fids : list[str] Field identifiers runoff_process : str Runoff mode ('cn' Curve Number or 'ier' infiltration-excess) refet_type : str Reference ET type ('eto' or 'etr') properties : FieldProperties Static field properties parameters : CalibrationParameters Calibration parameters (base values) spinup_state : WaterBalanceState Initial state from spinup

Example

Build from container and access data:

>>> from swimrs.container import SwimContainer
>>> from swimrs.process.input import build_swim_input, SwimInput
>>>
>>> # Build HDF5 from container
>>> container = SwimContainer.open("project.swim")
>>> swim_input = build_swim_input(container, output_h5="input.h5")
>>>
>>> # Access data
>>> print(f"Fields: {swim_input.n_fields}, Days: {swim_input.n_days}")
>>> ndvi = swim_input.get_time_series("ndvi", day_idx=0)
>>> swim_input.close()

h5_path: Path instance-attribute

start_date: datetime = field(default=None) class-attribute instance-attribute

end_date: datetime = field(default=None) class-attribute instance-attribute

n_days: int = field(default=0) class-attribute instance-attribute

n_fields: int = field(default=0) class-attribute instance-attribute

fids: list = field(default_factory=list) class-attribute instance-attribute

runoff_process: str = field(default='cn') class-attribute instance-attribute

refet_type: str = field(default='eto') class-attribute instance-attribute

properties: FieldProperties = field(default=None) class-attribute instance-attribute

parameters: CalibrationParameters = field(default=None) class-attribute instance-attribute

spinup_state: WaterBalanceState = field(default=None) class-attribute instance-attribute

_h5_file: h5py.File = field(default=None, repr=False) class-attribute instance-attribute

_gwsub_years: dict = field(default_factory=dict, repr=False) class-attribute instance-attribute

__post_init__()

Open HDF5 file and load metadata if path exists.

_load_from_h5()

Load metadata and static arrays from HDF5.

_load_gwsub_years(h5: h5py.File) -> dict[int, NDArray[np.float64]]

Load year-specific f_sub data from HDF5.

Returns

dict[int, NDArray[np.float64]] Mapping of year -> f_sub array (n_fields,)

_load_properties(h5: h5py.File) -> FieldProperties

Load field properties from HDF5.

_load_parameters(h5: h5py.File) -> CalibrationParameters

Load calibration parameters from HDF5.

_load_spinup(h5: h5py.File) -> WaterBalanceState

Load spinup state from HDF5.

close()

Close the HDF5 file.

__enter__()

__exit__(exc_type, exc_val, exc_tb)

get_time_series(variable: str, day_idx: int | None = None) -> NDArray[np.float64]

Get time series data for a variable.

Parameters

variable : str Variable name (e.g., 'ndvi', 'prcp', 'tmin', 'tmax', 'srad', 'ref_et', 'etr', 'eto'). Note: 'etr'/'eto' are aliases for 'ref_et' in newer HDF5 files, and 'ref_et' is an alias for 'etr'/'eto' in older files. day_idx : int, optional If provided, return only data for this day index. Otherwise return full time series (n_days, n_fields).

Returns

NDArray[np.float64] Time series data. Shape (n_fields,) if day_idx provided, otherwise (n_days, n_fields).

get_irr_flag(day_idx: int | None = None) -> NDArray[np.bool_]

Get irrigation flag data.

Parameters

day_idx : int, optional If provided, return only data for this day index.

Returns

NDArray[np.bool_] Irrigation flag array. Shape (n_fields,) if day_idx provided, otherwise (n_days, n_fields).

has_hourly_precip() -> bool

Check if hourly precipitation data is available.

Returns

bool True if prcp_hr dataset exists in time_series group

get_hourly_precip(day_idx: int) -> NDArray[np.float64] | None

Get hourly precipitation for a specific day.

Parameters

day_idx : int Day index

Returns

NDArray[np.float64] | None Hourly precip array of shape (24, n_fields), transposed from storage format (n_fields, 24). Returns None if not available.

get_date(day_idx: int) -> datetime

Get date for a given day index.

get_day_idx(date: datetime) -> int

Get day index for a given date.

get_f_sub_for_year(year: int) -> NDArray[np.float64]

Get year-specific groundwater subsidy fraction.

Parameters

year : int The year for which to get f_sub values

Returns

NDArray[np.float64] f_sub array of shape (n_fields,) for the specified year. Falls back to static properties.f_sub if year-specific data is not available.

has_year_specific_gwsub() -> bool

Check if year-specific groundwater subsidy data is available.

apply_multipliers(mult_dir: Path | str) -> CalibrationParameters

Apply PEST++ multipliers to create adjusted parameters.

Parameters

mult_dir : Path | str Directory containing multiplier CSV files. Files should be named: p_{param}_{fid}_0_constant.csv

Returns

CalibrationParameters New parameters with multipliers applied

build_swim_input(container: SwimContainer, output_h5: Path | str, spinup_state: dict[str, NDArray[np.float64]] | None = None, spinup_json_path: Path | str | None = None, calibrated_params_path: Path | str | None = None, start_date: str | datetime | None = None, end_date: str | datetime | None = None, runoff_process: str = 'cn', refet_type: str = 'eto', etf_model: str = 'ssebop', met_source: str = 'gridmet', fields: list[str] | None = None, empirical_kc_max: bool = False) -> SwimInput

Build HDF5 input file from SwimContainer.

Parameters

container : SwimContainer SwimContainer instance with ingested data output_h5 : Path | str Path for output HDF5 file spinup_state : dict, optional Dictionary with spinup arrays: depl_root, swe, kr, ks, zr. If not provided, uses default initialization. spinup_json_path : Path | str, optional Path to spinup JSON file (like old model's spinup.json). Takes precedence over spinup_state if both provided. calibrated_params_path : Path | str, optional Path to JSON file with calibrated parameters per field. Format: {fid: {param_name: value, ...}, ...} start_date : str | datetime, optional Override start date (default: from container) end_date : str | datetime, optional Override end date (default: from container) runoff_process : str Runoff mode: 'cn' (curve number) or 'ier' (infiltration excess) refet_type : str Reference ET type to use from the container: 'eto' (grass) or 'etr' (alfalfa). This is typically configured in the project TOML and passed through the CLI. etf_model : str ET fraction model (e.g., 'ssebop', 'ptjpl') met_source : str Meteorology source (e.g., 'gridmet', 'era5') fields : list[str], optional List of field UIDs to include (default: all fields in container) empirical_kc_max : bool If True, use empirical kc_max from container (90th percentile ETf). If False (default), use fixed FAO-56 value of 1.2.

Returns

SwimInput Loaded SwimInput container

Example

>>> from swimrs.container import SwimContainer
>>> from swimrs.process.input import build_swim_input
>>>
>>> container = SwimContainer.open("project.swim")
>>> swim_input = build_swim_input(
...     container=container,
...     output_h5="swim_input.h5",
... )
>>> print(f"Fields: {swim_input.n_fields}, Days: {swim_input.n_days}")

State containers

WaterBalanceState(n_fields: int, depl_root: NDArray[np.float64] = None, depl_ze: NDArray[np.float64] = None, daw3: NDArray[np.float64] = None, taw3: NDArray[np.float64] = None, swe: NDArray[np.float64] = None, albedo: NDArray[np.float64] = None, zr: NDArray[np.float64] = None, kr: NDArray[np.float64] = None, ks: NDArray[np.float64] = None, irr_continue: NDArray[np.float64] = None, next_day_irr: NDArray[np.float64] = None, s: NDArray[np.float64] = None, s1: NDArray[np.float64] = None, s2: NDArray[np.float64] = None, s3: NDArray[np.float64] = None, s4: NDArray[np.float64] = None, irr_frac_root: NDArray[np.float64] = None, irr_frac_l3: NDArray[np.float64] = None) dataclass

Mutable state arrays for daily water balance computation.

All arrays have shape (n_fields,). State is updated in-place during the daily step loop.

Attributes

n_fields : int Number of fields/pixels being modeled depl_root : NDArray[np.float64] Root zone depletion (mm), 0 = field capacity depl_ze : NDArray[np.float64] Surface layer depletion (mm) for evaporation daw3 : NDArray[np.float64] Available water in layer 3 below root zone (mm) taw3 : NDArray[np.float64] Total available water capacity in layer 3 (mm) swe : NDArray[np.float64] Snow water equivalent (mm) albedo : NDArray[np.float64] Snow albedo (dimensionless, 0-1) zr : NDArray[np.float64] Current root depth (m) kr : NDArray[np.float64] Evaporation reduction coefficient (damped) ks : NDArray[np.float64] Water stress coefficient (damped) irr_continue : NDArray[np.float64] Irrigation continuation flag (1.0 if continuing from previous day) next_day_irr : NDArray[np.float64] Carryover irrigation amount for next day (mm) s : NDArray[np.float64] Current day S retention parameter (mm) for CN runoff s1, s2, s3, s4 : NDArray[np.float64] S history from 1-4 days ago (mm), used for smoothed runoff on irrigated fields irr_frac_root : NDArray[np.float64] Fraction of root zone water that originated from irrigation [0, 1]. Used for consumptive use accounting. irr_frac_l3 : NDArray[np.float64] Fraction of layer 3 water that originated from irrigation [0, 1]. Used for deep percolation accounting.

n_fields: int instance-attribute

depl_root: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

depl_ze: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

daw3: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

taw3: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

swe: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

albedo: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

zr: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

kr: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

ks: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

irr_continue: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

next_day_irr: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

s: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

s1: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

s2: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

s3: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

s4: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

irr_frac_root: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

irr_frac_l3: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

__post_init__()

Initialize arrays with zeros if not provided.

from_spinup(n_fields: int, depl_root: NDArray[np.float64], swe: NDArray[np.float64], kr: NDArray[np.float64], ks: NDArray[np.float64], zr: NDArray[np.float64], daw3: NDArray[np.float64] | None = None, taw3: NDArray[np.float64] | None = None, depl_ze: NDArray[np.float64] | None = None, albedo: NDArray[np.float64] | None = None, s: NDArray[np.float64] | None = None, s1: NDArray[np.float64] | None = None, s2: NDArray[np.float64] | None = None, s3: NDArray[np.float64] | None = None, s4: NDArray[np.float64] | None = None, irr_frac_root: NDArray[np.float64] | None = None, irr_frac_l3: NDArray[np.float64] | None = None, irr_status: NDArray[np.bool_] | None = None) -> WaterBalanceState classmethod

Create state from spinup values.

Parameters

n_fields : int Number of fields depl_root : NDArray[np.float64] Initial root zone depletion (mm) swe : NDArray[np.float64] Initial snow water equivalent (mm) kr : NDArray[np.float64] Initial evaporation reduction coefficient ks : NDArray[np.float64] Initial water stress coefficient zr : NDArray[np.float64] Initial root depth (m) daw3 : NDArray[np.float64], optional Initial layer 3 available water (mm) taw3 : NDArray[np.float64], optional Initial layer 3 total capacity (mm) depl_ze : NDArray[np.float64], optional Initial surface layer depletion (mm) albedo : NDArray[np.float64], optional Initial snow albedo s : NDArray[np.float64], optional Current S retention (mm) s1, s2, s3, s4 : NDArray[np.float64], optional S history from 1-4 days ago (mm) irr_frac_root : NDArray[np.float64], optional Irrigation fraction in root zone [0, 1]. If not provided, initialized based on irr_status (0.5 if irrigated, 0.0 if not). irr_frac_l3 : NDArray[np.float64], optional Irrigation fraction in layer 3 [0, 1]. If not provided, initialized based on irr_status (0.5 if irrigated, 0.0 if not). irr_status : NDArray[np.bool_], optional Whether each field is irrigated. Used to initialize irrigation fractions when they are not provided in spinup data.

Returns

WaterBalanceState Initialized state container

copy() -> WaterBalanceState

Create a deep copy of the state.

FieldProperties(n_fields: int, fids: NDArray = None, awc: NDArray[np.float64] = None, ksat: NDArray[np.float64] = None, rew: NDArray[np.float64] = None, tew: NDArray[np.float64] = None, cn2: NDArray[np.float64] = None, zr_max: NDArray[np.float64] = None, zr_min: NDArray[np.float64] = None, mad: NDArray[np.float64] = None, irr_status: NDArray[np.bool_] = None, perennial: NDArray[np.bool_] = None, gw_status: NDArray[np.bool_] = None, ke_max: NDArray[np.float64] = None, kc_max: NDArray[np.float64] = None, f_sub: NDArray[np.float64] = None, ndvi_bare: NDArray[np.float64] = None, ndvi_full: NDArray[np.float64] = None) dataclass

Static soil and crop properties for each field.

All arrays have shape (n_fields,). These properties are read from the HDF5 input file and do not change during simulation.

Attributes

n_fields : int Number of fields/pixels fids : NDArray Field identifiers (string or int) awc : NDArray[np.float64] Available water capacity (mm/m) ksat : NDArray[np.float64] Saturated hydraulic conductivity (mm/day).

This is converted to an hourly infiltration capacity (mm/hr) when
running infiltration-excess runoff (IER) using hourly precipitation.

rew : NDArray[np.float64] Readily evaporable water (mm) tew : NDArray[np.float64] Total evaporable water (mm) cn2 : NDArray[np.float64] Curve number for average antecedent moisture (AMC II) zr_max : NDArray[np.float64] Maximum root depth (m) zr_min : NDArray[np.float64] Minimum root depth (m) mad : NDArray[np.float64] Depletion fraction for stress onset irr_status : NDArray[np.bool_] Whether field is irrigated perennial : NDArray[np.bool_] Whether crop is perennial (affects root dynamics) gw_status : NDArray[np.bool_] Whether groundwater subsidy is available ke_max : NDArray[np.float64] Maximum soil evaporation coefficient, derived from ETf observations where NDVI < 0.3 (90th percentile of bare soil ETf) kc_max : NDArray[np.float64] Maximum crop coefficient, derived from ETf observations (90th percentile of all ETf values) f_sub : NDArray[np.float64] Groundwater subsidy fraction (0-1), derived from ETa/PPT ratio where f_sub = (ratio - 1) / ratio when ratio > 1 ndvi_bare : NDArray[np.float64] NDVI value representing bare/dormant soil conditions, used for computing fractional cover directly from NDVI. Typically the 5th percentile of the site's NDVI record. Default: 0.15. ndvi_full : NDArray[np.float64] NDVI value representing full vegetation cover, used for computing fractional cover directly from NDVI. Typically the 95th percentile of the site's NDVI record. Default: 0.85.

n_fields: int instance-attribute

fids: NDArray = field(default=None) class-attribute instance-attribute

awc: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

ksat: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

rew: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

tew: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

cn2: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

zr_max: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

zr_min: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

mad: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

irr_status: NDArray[np.bool_] = field(default=None) class-attribute instance-attribute

perennial: NDArray[np.bool_] = field(default=None) class-attribute instance-attribute

gw_status: NDArray[np.bool_] = field(default=None) class-attribute instance-attribute

ke_max: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

kc_max: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

f_sub: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

ndvi_bare: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

ndvi_full: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

__post_init__()

Initialize arrays with reasonable defaults if not provided.

compute_taw(zr: NDArray[np.float64]) -> NDArray[np.float64]

Compute total available water for given root depth.

TAW = AWC * Zr

Guards are applied to prevent: - Division by zero (TAW >= 0.001) - Early stress with shallow roots (TAW >= TEW)

Parameters

zr : NDArray[np.float64] Root depth (m)

Returns

NDArray[np.float64] Total available water (mm)

compute_raw(taw: NDArray[np.float64]) -> NDArray[np.float64]

Compute readily available water.

RAW = p * TAW

Parameters

taw : NDArray[np.float64] Total available water (mm)

Returns

NDArray[np.float64] Readily available water (mm)

CalibrationParameters(n_fields: int, kc_min: NDArray[np.float64] = None, ndvi_k: NDArray[np.float64] = None, ndvi_0: NDArray[np.float64] = None, swe_alpha: NDArray[np.float64] = None, swe_beta: NDArray[np.float64] = None, kr_damp: NDArray[np.float64] = None, ks_damp: NDArray[np.float64] = None, max_irr_rate: NDArray[np.float64] = None) dataclass

Parameters that can be modified by PEST++ multipliers.

All arrays have shape (n_fields,). These are the calibration parameters that PEST++ adjusts via multiplier files.

Attributes

n_fields : int Number of fields/pixels kc_min : NDArray[np.float64] Minimum crop coefficient (bare soil) ndvi_k : NDArray[np.float64] Sigmoid steepness parameter for Kcb ndvi_0 : NDArray[np.float64] Sigmoid midpoint (inflection) NDVI swe_alpha : NDArray[np.float64] Snow melt radiation coefficient swe_beta : NDArray[np.float64] Snow melt degree-day coefficient kr_damp : NDArray[np.float64] Kr damping factor (0-1) ks_damp : NDArray[np.float64] Ks damping factor (0-1) max_irr_rate : NDArray[np.float64] Maximum daily irrigation rate (mm/day)

n_fields: int instance-attribute

kc_min: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

ndvi_k: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

ndvi_0: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

swe_alpha: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

swe_beta: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

kr_damp: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

ks_damp: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

max_irr_rate: NDArray[np.float64] = field(default=None) class-attribute instance-attribute

__post_init__()

Initialize arrays with default values if not provided.

from_base_with_multipliers(base: CalibrationParameters, multipliers: dict[str, NDArray[np.float64]]) -> CalibrationParameters classmethod

Create parameters by applying multipliers to base values.

Parameters

base : CalibrationParameters Base parameter values multipliers : dict Parameter name -> multiplier array

Returns

CalibrationParameters New parameters with multipliers applied

copy() -> CalibrationParameters

Create a deep copy of the parameters.

from_pest_mult(mult_dir: str, fids: list[str], base: CalibrationParameters | None = None) -> CalibrationParameters classmethod

Load parameters from PEST++ multiplier CSV files.

PEST++ writes parameter multiplier files in the format: mult/p_{param}_{fid}_0_constant.csv

The CSV has a header row and the value is in the last column ('1').

Parameters

mult_dir : str Path to the mult/ directory containing CSV files fids : list[str] Field IDs in simulation order base : CalibrationParameters, optional Base parameters to start from. If None, uses defaults.

Returns

CalibrationParameters Parameters loaded from mult files