API Reference
This page documents the complete public API exported from the
mnished package. See also:
Recession Analysis —
BrutsaertNieber(Brutsaert–Nieber recession analysis)Data-Driven Priors —
Priorsandsuggest_priors()(data-driven priors)Calibration —
run_and_score()andCalibResult(calibration workflow)CSDMS Basic Model Interface —
BmiMNiShed(CSDMS Basic Model Interface wrapper)
Buckets
The primary class for running a watershed simulation.
- class mnished.Buckets(T_monthly_normals=None)[source]
Bases:
objectIncorporates a list of reservoirs into a linear hierarchy that sends water either downwards or out to the surface. Reservoirs are ordered from top (nearest Earth’s surface) to bottom (deepest groundwater); this order controls the direction of infiltration between layers.
MNiShed is designed as a daily-timestep model. This is a deliberate design choice: the physical parameterisations — degree-day snowmelt, Thornthwaite ET, and linear reservoir drainage — are climatological approximations that are well-founded at daily resolution but lose physical meaning at finer scales. The daily timestep is enforced in initialize().
- __init__(T_monthly_normals=None)[source]
Initialize the watershed model.
If using the ThornthwaiteChang2019 ET method, pass T_monthly_normals here so that the thermal index I and exponent a are computed once from climatological normals and remain fixed throughout the simulation.
- Parameters:
T_monthly_normals (array-like of length 12, optional) – Long-term mean monthly temperatures (°C) used to compute the Thornthwaite thermal index I and exponent a per Chang et al. (2019), https://doi.org/10.1002/ird.2309. Required when evapotranspiration_method is ‘ThornthwaiteChang2019’.
- export_Hlist()[source]
Return the current water depths in all subsurface reservoirs.
Useful for checkpointing reservoir state between a spin-up run and the main simulation, or for restarting a paused run.
- initialize(config_file=None, enforce_water_balance=None)[source]
Set up the model from a YAML configuration file.
Reads the configuration file, loads the input time series, builds the reservoir stack, instantiates snowpack if temperature data are present, optionally computes the water-year ET multiplier, and runs any requested spin-up cycles. Part of the CSDMS Basic Model Interface.
- Parameters:
config_file (str, optional) – Path to the YAML configuration file. If None, all required values must be set on the object directly before calling update().
enforce_water_balance (str or None, optional) –
How to scale ET to close the water balance. When None (default), the value is read from
general: enforce_water_balancein the YAML config, which itself defaults to'water-year'if absent. Accepted values:'water-year'— Scale ET by a per-water-year multiplier so that P - Q - ET = 0 over each water year.'global'— Scale ET by a single multiplier computed from sum(P - Q_obs) / sum(ET_raw) over the full record. No per-year overfitting; does not add hidden degrees of freedom to AIC comparisons.'none'— Use raw ET without correction. Appropriate only when supplying trusted measured ET (e.g. eddy covariance). Using'none'with ThornthwaiteChang2019 will raise a warning because Thornthwaite ET carries large systematic biases.
- compute_water_year()[source]
Assign a water-year label to each row in self.hydrodata.
Adds a ‘Water Year’ column. A water year begins on water_year_start_month and is labelled by the calendar year in which it ends. For example, with a start month of October (USGS convention), 1 Oct 2020 – 30 Sep 2021 is water year 2021.
When water_year_start_month is 1 (January), the water year equals the calendar year and no offset is applied.
- compute_global_ET_multiplier(start=None, end=None)[source]
Compute a single ET scale factor to close the long-term water balance.
Computes scale = sum(P - Q_obs) / sum(ET_raw) over all days where P, ET, and Q_obs are all finite, and stores it as self.global_et_multiplier. Unlike compute_ET_multiplier(), which fits one multiplier per water year, this uses a single ratio and does not overfit interannual variability. Appropriate when enforce_water_balance is set to ‘global’.
- compute_ET_multiplier()[source]
Compute per-water-year ET scaling factors to enforce water balance.
For each water year, computes the ratio of required ET (P - Q) to measured or computed ET, and stores this as ‘ET multiplier’ in self.hydrodata_WY_means. This multiplier is later applied in compute_ET() to scale ET so that P - Q - ET = 0 over each water year.
- compute_ET()[source]
Build the ET time series used in the model.
Obtains raw daily ET from the input data file or the Thornthwaite–Chang 2019 equation (see evapotranspiration_Chang2019()). Five modes:
et_scale (default 1.0) is applied as a universal final multiplier in every mode. Four modes determine the base ET before et_scale:
et_water_stress=True (or et_reservoir_draw + ‘none’): base = raw ET. et_scale is then the sole WB-closure mechanism.
enforce_water_balance=’water-year’ (stress off): base = raw ET × per-water-year multiplier so P - Q - ET ≈ 0 each year (before et_scale).
enforce_water_balance=’global’ (stress off): base = raw ET × single full-record multiplier from sum(P - Q_obs) / sum(ET_raw).
enforce_water_balance=’none’ (stress off): base = raw ET.
In modes 2–4, et_scale=1.0 (the default) leaves existing behaviour unchanged. Set et_scale ≠ 1 to add a calibrated offset from the water-balance multiplier (e.g. to capture decade-specific land-cover or climate sensitivity); this relaxes exact WB closure.
The result is stored as ‘ET for model [mm/day]’ in self.hydrodata.
- update(time_step=None)[source]
Advance the model by one time step.
Routes precipitation minus ET through the snowpack (if present) and then through each subsurface reservoir in order from shallowest to deepest. Stores modeled specific discharge, snowpack SWE, and total subsurface storage in self.hydrodata for the current time step. Part of the CSDMS Basic Model Interface.
- Parameters:
time_step (int, optional) – Index into self.hydrodata for the time step to update. If None, uses and then increments the internal counter self._timestep_i.
- evapotranspiration_Chang2019(Tmax=None, Tmin=None, photoperiod=None, k=0.69)[source]
Modified daily Thornthwaite ET₀ equation.
Chang et al. (2019), Eq. 1–4. https://doi.org/10.1002/ird.2309
- Parameters:
Tmax (array-like) – Daily maximum temperature (°C).
Tmin (array-like) – Daily minimum temperature (°C).
photoperiod (array-like) – Photoperiod N (hours), computed from latitude and Julian day per Allen et al. (1998), Eqs. 2–4 of Chang et al. (2019).
k (float) – Calibration coefficient in the T_ef formula. Default 0.69, recommended by Pereira & Pruitt (2004) for daily ET₀ (https://doi.org/10.1016/j.agrformet.2004.01.005). Use 0.72 for monthly ET₀ per Camargo et al. (1999).
- Returns:
ET0 – Daily reference evapotranspiration (mm day⁻¹).
- Return type:
array-like
- run(start=None, end=None, store_depths=False)[source]
Advance the model through time steps in self.hydrodata.
Resets the internal time counter before iterating, so run() is safe to call more than once (e.g. spin-up then main run). Captures storage at the start of the run for check_mass_balance(). Part of the CSDMS Basic Model Interface.
- Parameters:
Notes
When start or end is provided, only the matching rows are stepped through; reservoir states at the boundaries carry in/out naturally, making windowed runs chainable (e.g. spin-up on pre-decade data followed by a scored run on the decade itself).
- finalize()[source]
Report model skill and display output plots.
Calls compute_NSE(verbose=True) to print the Nash–Sutcliffe Efficiency to stdout, then calls plot() to display a time-series comparison of observed and modeled specific discharge. Part of the CSDMS Basic Model Interface.
- plot()[source]
Display a time-series comparison of precipitation and specific discharge.
Produces a dual-axis figure: precipitation as a bar chart on the left axis and both observed and modeled specific discharge as line plots on the right axis.
- check_mass_balance(time_step=None)[source]
Compute the mass-balance discrepancy at a given time step.
Compares cumulative inputs (P - ET) from the start of the record through time_step with cumulative outputs (discharge) plus current storage (snowpack + subsurface reservoirs) and any carried-over deficit. Returns the excess mass still in the model; a value near zero indicates good mass conservation.
- compute_NSE(return_nse=True, verbose=False)[source]
Compute the Nash–Sutcliffe Efficiency of the discharge simulation.
Compares modeled and observed specific discharge for all time steps where both values are non-missing. Stores the result as self.NSE.
- Parameters:
- Returns:
NSE – Nash–Sutcliffe Efficiency coefficient. Returns None if return_nse is False. A value of 1 indicates perfect agreement; values below 0 indicate the model performs worse than the observed-mean predictor.
- Return type:
float or None
Reservoir
A single power-law (or linear) reservoir.
- class mnished.Reservoir(recession_coeff, f_to_discharge=1.0, Hmax=inf, pdm_H0=None, H0=0.0, f_tile=0.0, tau_tile=None, junction_type='fraction', leakance_R=None, H_threshold=0.0, multipath_threshold=None, multipath_timescale=None)[source]
Bases:
objectGeneric reservoir. Accepts new water (recharge), and sends it to other reservoirs and/or out of the system (discharge) at a rate that is proportional to the amount of water held in the reservoir.
- __init__(recession_coeff, f_to_discharge=1.0, Hmax=inf, pdm_H0=None, H0=0.0, f_tile=0.0, tau_tile=None, junction_type='fraction', leakance_R=None, H_threshold=0.0, multipath_threshold=None, multipath_timescale=None)[source]
Initialize a reservoir.
- Parameters:
recession_coeff (float) – Recession coefficient. For a linear reservoir (recession exponent b = 1) this equals the true e-folding timescale, in days. For b > 1 it is not a timescale — its units are day·mm^(b-1) and the actual mean residence time depends on storage level; use
mean_residence_time()to obtain a physically comparable timescale at a given reference discharge.f_to_discharge (float, optional) – Fraction of water lost each time step that exits as river discharge. The remainder (1 - f_to_discharge) infiltrates to the next-deeper reservoir. Default 1.0 (all to discharge). Used only when junction_type is ‘fraction’ or ‘threshold’.
Hmax (float, optional) – Maximum water depth the reservoir can hold. Default np.inf.
pdm_H0 (float or None, optional) – Characteristic storage depth [mm] for the probability-distributed model (PDM) of saturation-excess overland flow. Storage capacity is assumed exponentially distributed across the catchment with mean pdm_H0; the saturated fraction when reservoir depth is H is f_sat = 1 - exp(-H / pdm_H0). That fraction of each positive recharge pulse is shed immediately as overland flow. Mutually exclusive with a finite Hmax. Default None (PDM off).
H0 (float, optional) – Initial water depth at the start of the simulation. Default 0.
f_tile (float, optional) –
Fraction of subsurface drainage (H_to_next) that is diverted to a fast tile-drain sub-reservoir instead of passing to the next-deeper reservoir. The tile sub-reservoir drains directly to stream with e-folding time tau_tile. This is a fractional-bypass tile representation: a constant fraction of recession outflow is routed through a downstream fast linear reservoir, regardless of current storage. Default 0 (no tile drainage). Requires tau_tile when > 0.
For a threshold-activated parallel drainage representation, in which a second outflow path from the same storage activates only above a water-table depth, use
multipath_threshold/multipath_timescaleinstead.tau_tile (float or None, optional) – E-folding residence time [days] of the tile-drain sub-reservoir (used with
f_tile). Typical values: 3–21 days for agricultural tile systems. Required when f_tile > 0; ignored when f_tile == 0. Default None.multipath_threshold (float or None, optional) –
Storage depth [mm] above which a parallel fast drainage path from this reservoir activates. The parallel path drains directly to stream with e-folding timescale
multipath_timescaleand is added to the discharge alongside the primary recession. The outflow isQ_multipath = max(0, H - multipath_threshold) / multipath_timescale.
Below the threshold this term is exactly zero, so the reservoir behaves identically to the no-multipath case. Above it, a second linear drain operates in parallel with the primary recession, giving a two-timescale response: slow matrix drainage at low storage and faster combined drainage at high storage.
Physical analogue: a tile-drain system installed at a fixed depth that activates only once the water table rises above the drain elevation. Contrast with
f_tile/tau_tile, which is a constant-fraction fast-routing path through a separate downstream reservoir regardless of storage.Both
multipath_thresholdandmultipath_timescalemust be provided together, or both left as None (default = multipath disabled).multipath_timescale (float or None, optional) – E-folding timescale [days] of the parallel multipath drain. Typical values: 3–21 days for agricultural tile systems represented this way. Required together with
multipath_threshold; ignored when it is None. Default None.junction_type (str, optional) –
How drainage is partitioned between river discharge and the next-deeper reservoir. Options:
'fraction'(default)Fixed split:
f_to_dischargefraction exits as stream discharge; remainder infiltrates. Current default behaviour.'leakance'Head-difference driven flow to the next reservoir, physically representing Darcy flow through a confining unit (e.g. a shale layer).
Q_leak = max(H_this - H_next, 0) / leakance_R, capped at the total drainagedH. The remainder goes to stream. Requiresleakance_R.'threshold'Dead-storage threshold: the recession law is applied only to
max(H - H_threshold, 0); water belowH_thresholdnever drains. The above-threshold drainage splits byf_to_dischargeas in the'fraction'case. Models a stream-aquifer connection that activates only when the water table exceeds the streambed elevation.
leakance_R (float or None, optional) – Leakance resistance [days].
Q_leak = ΔH / leakance_R. Required when junction_type is'leakance'. Default None.H_threshold (float, optional) – Dead-storage threshold depth [mm]. Recession is applied only to
max(H - H_threshold, 0). Used when junction_type is'threshold'. Default 0.0 (no threshold; full storage drains).
- Raises:
ValueError – If recession_coeff <= 0, f_to_discharge < 0 or > 1, Hmax < 0, pdm_H0 <= 0, f_tile < 0 or > 1, f_tile > 0 with no tau_tile, junction_type is unrecognised, junction_type is ‘leakance’ with no leakance_R, multipath_threshold < 0, multipath_timescale <= 0, or only one of the two multipath parameters is provided.
- property has_multipath
True when both multipath parameters are configured (drain active).
- recharge(H)[source]
Add or remove water from the reservoir.
Recharge H can be positive (net water input, e.g. P > ET) or negative (net deficit, e.g. ET > P). Sets H_excess if the reservoir overflows Hmax, or H_deficit if more water is removed than the reservoir holds.
- Parameters:
H (float) – Depth of water added (positive) or removed (negative).
- Raises:
ValueError – If Hwater is already negative before recharge is applied.
- discharge(dt, H_next=None)[source]
Discharge water from the reservoir over one time step.
Computes water lost by the recession law, partitions it between river discharge (H_exfiltrated) and infiltration to the next-deeper reservoir (H_to_next) according to junction_type, and adds overflow from recharge() (H_excess) to H_discharge.
- Parameters:
- mean_residence_time(Q_ref)[source]
Mean residence time [days] at a reference steady-state discharge.
For a nonlinear reservoir governed by \(Q = (H/\tau)\cdot(H/H_{\mathrm{ref}})^{b-1} = H^{b}/\tau_{\mathrm{eff}}\), with effective constant \(\tau_{\mathrm{eff}} = \tau\,H_{\mathrm{ref}}^{\,b-1}\), the steady-state storage at discharge Q_ref is \(H_{ss} = (Q_{\mathrm{ref}} \cdot \tau_{\mathrm{eff}})^{1/b}\), giving
\[\mathrm{MRT} = \frac{H_{ss}}{Q_{\mathrm{ref}}} = \frac{\tau_{\mathrm{eff}}^{1/b}}{Q_{\mathrm{ref}}^{\,1 - 1/b}}\]With the default \(H_{\mathrm{ref}} = 1\) this is \(\tau^{1/b} / Q_{\mathrm{ref}}^{\,1-1/b}\).
For a linear reservoir (b = 1) this reduces exactly to \(\tau\). For b > 1, MRT is smaller than \(\tau\) whenever \(Q_{\mathrm{ref}} > 1\) mm/day, reflecting the faster drainage at realistic operating storage depths.
Unlike
recession_coeff, which equals a timescale only when b=1 (linear reservoir), MRT is a physically comparable timescale across reservoirs with different recession exponents.- Parameters:
Q_ref (float) – Representative steady-state discharge from this reservoir [mm/day]. Use the long-term mean flux attributed to this layer (e.g. mean annual discharge partitioned by reservoir).
- Returns:
Mean residence time [days].
- Return type:
- Raises:
ValueError – If Q_ref <= 0.
Snowpack
Snowpack accumulation and positive-degree-day melt.
- class mnished.Snowpack(melt_factor=None)[source]
Bases:
objectSnowpack reservoir driven by temperature.
Accumulates precipitation as snow when mean temperature is at or below 0 °C. Melts at a positive-degree-day rate when temperature is above 0 °C. All melt is routed to the top subsurface reservoir as infiltration; direct discharge to the river is not modeled.
Should precede the subsurface reservoir list in a watershed model. The melt factor is a positive-degree-day factor [mm/°C/day].
- __init__(melt_factor=None)[source]
Initialize an empty snowpack.
- Parameters:
melt_factor (float, optional) – Positive-degree-day melt factor (mm SWE °C⁻¹ day⁻¹). Can be set or updated later via set_melt_factor().
- set_melt_factor(melt_factor)[source]
Set or update the positive-degree-day melt factor.
- Parameters:
melt_factor (float) – Melt rate per positive degree-day (mm SWE °C⁻¹ day⁻¹).
- set_temperature(T)[source]
Set the mean air temperature for the current time step.
- Parameters:
T (float) – Mean air temperature (°C).
- recharge(H)[source]
Apply net water input or deficit to the snowpack.
If T <= 0, positive H accumulates as snow (SWE). If T > 0, positive H bypasses the snowpack and is passed directly to the top subsurface reservoir via H_infiltrated. Negative H (ET > P) is removed from the snowpack as sublimation; any remainder that exceeds available SWE becomes H_deficit.
- Parameters:
H (float) – Net water depth for this time step (mm). Positive = input (P - ET > 0); negative = deficit (ET - P > 0).
- melt(dt, P=0.0)[source]
Compute positive-degree-day and rain-on-snow melt; update state.
Both terms are routed to H_infiltrated (→ top soil reservoir). If total available energy exceeds the SWE present, the leftover is returned as equivalent degree-days so the caller can credit it toward frozen-soil thawing (FGI reduction) rather than losing it.
Rain-on-snow sensible heat: water arriving at T_mean > 0 °C carries (c_p / L_f) · T · P mm SWE of latent-heat capacity. Spring snowpacks are near-isothermal at 0 °C, so cold-content corrections are negligible and the latent-heat term dominates.
References
McCabe et al. (2007) doi:10.1175/BAMS-88-3-319 Würzer et al. (2016) doi:10.1175/JHM-D-15-0181.1
- Parameters:
- Returns:
excess_dd – Leftover melt energy after the snowpack is exhausted, expressed as degree-day equivalent [°C·day] = leftover mm SWE / melt_factor. Zero when SWE is not fully depleted.
The melt factor (mm SWE °C⁻¹ day⁻¹) serves as the bridge between the PDD snowmelt representation and the frozen ground index (FGI): dividing excess melt depth (mm SWE) by melt_factor recovers the equivalent thermal forcing in °C·day, which is the currency the FGI uses. See Buckets._update_fgi().
- Return type:
run_and_score
Run the model with a given parameter set and return goodness-of-fit metrics.
- mnished.run_and_score(cfg, recession_coeff=None, f_to_discharge=None, Hmax=None, pdm_H0=None, f_tile=None, tau_tile=None, multipath_threshold=None, multipath_timescale=None, multipath_calibrated=0, leakance_R=None, leakance_R_calibrated=0, H_threshold=None, H_threshold_calibrated=0, melt_factor=None, fdd_threshold=None, snow_insulation_k=None, et_scale=None, et_alpha=None, wp_soil=None, wp_soil_sigma=None, recession_exponents=None, recession_exponents_calibrated=0, direct_runoff_fraction=None, baseflow_Q=None, modules=None, initial_states=None, post_spinup_states=None, post_spinup_k=0, start=None, end=None, spin_up_cycles=None, metric='KGE', routing_N=2, routing_K=None, enforce_water_balance='water-year')[source]
Run MNiShed and return a CalibResult named tuple.
- Parameters:
cfg (str) – Path to a YAML configuration file. Should have spin_up_cycles: 0 so that spin-up is performed here with the calibrated parameters.
recession_coeff (list of float, optional) – Recession coefficients [days], one per reservoir (shallowest first). Overrides the values in cfg.
f_to_discharge (list of float, optional) – Exfiltration fractions to stream, one per reservoir except the deepest (which is always 1.0). Overrides the values in cfg. Used only for reservoirs whose junction_type is ‘fraction’ or ‘threshold’.
leakance_R (list of float or None, optional) – Leakance resistance [days] for each reservoir, one per reservoir.
Noneentries leave the reservoir at its config-defined junction type. Non-None entries set junction_type to ‘leakance’ and assign the resistance.Q_leak = max(H_this - H_next, 0) / R. Default None (all fraction).leakance_R_calibrated (int, optional) – Number of entries in
leakance_Rthat are free calibration parameters (for AIC k-counting). Default 0.H_threshold (list of float or None, optional) – Dead-storage threshold depth [mm] for each reservoir, one per reservoir.
Noneentries leave the reservoir unchanged. Non-None entries set junction_type to ‘threshold’: onlymax(H - H_threshold, 0)drains. Models a stream-aquifer connection that activates above a threshold head. Default None (no threshold).H_threshold_calibrated (int, optional) – Number of entries in
H_thresholdthat are free calibration parameters (for AIC k-counting). Default 0.multipath_threshold (list of float or None, optional) – Storage depth [mm] above which a parallel fast drain activates, per reservoir.
Noneentries leave the reservoir’s multipath configuration unchanged from cfg. Non-None entries enable a threshold-activated parallel drain that addsmax(0, H - thr)/multipath_timescaleto discharge above the threshold. Distinct fromf_tile/tau_tile(which is a constant-fraction bypass through a downstream sub-reservoir); seemnished.Reservoirfor the contrast. Requires the matchingmultipath_timescaleentry to be non-None. Default None.multipath_timescale (list of float or None, optional) – E-folding timescale [days] of the parallel multipath drain, per reservoir. Required paired with
multipath_threshold. Default None.multipath_calibrated (int, optional) – Number of free parameters contributed by multipath_threshold + multipath_timescale combined (for AIC k-counting). Default 0.
Hmax (list of float, optional) – Maximum effective water depths [mm], one per reservoir. Overrides the values in cfg.
melt_factor (float, optional) – Degree-day snowmelt factor [mm SWE per degC per day]. Overrides the value in cfg.
direct_runoff_fraction (float or None, optional) – Fraction (0–1) of positive daily recharge that bypasses the reservoir cascade and exits directly as runoff. Conceptually inspired by Hortonian (infiltration-excess) overland flow, but at a daily timestep rainfall intensity is unavailable, so the fraction is not a rigorous physical representation – except in extreme events where intense rainfall dominates the daily total. In practice it acts as a calibrated fast-bypass fraction. None (default) leaves the value from the YAML config (itself defaulting to 0; off by default).
fdd_threshold (float or None, optional) – Frozen ground index threshold [°C·day]. The frozen ground index accumulates freezing degree-days and decays during warming (Molnau & Bissell 1983, https://westernsnowconference.org/bibliography/1983Molnau.pdf). When the index exceeds fdd_threshold, infiltration from the top reservoir to deeper layers is set to zero for that timestep (all drainage becomes direct runoff). None (default) disables the effect.
snow_insulation_k (float or None, optional) – Snow insulation decay constant [mm⁻¹ SWE]. Scales the effective air temperature reaching the soil as T_eff = T · exp(-k · SWE), reducing FGI accumulation under a deep snowpack. Applied to both freezing and thawing temperature forcing; excess degree-days from meltwater (excess_dd) are not scaled because meltwater delivers heat directly to the soil surface. None (default) leaves the value from cfg (itself defaulting to 0.0, i.e. no insulation). Literature values: LISFLOOD uses ~0.057 mm⁻¹; GSSHA default is 0.5 (units ambiguous in original source).
initial_states (dict, optional) –
Starting reservoir water depths, snowpack SWE, and frozen ground index, as returned by a previous call’s CalibResult.final_states. Format:
{'reservoirs': [H_shallow, H_deep, ...], 'snowpack': H_snow_SWE, 'fgi': frozen_ground_index}
When provided, these override the H0 values from cfg. Use with spin_up_cycles=0 when chaining consecutive decades so that water storage and frozen-ground state are physically continuous. When None (default), reservoirs are initialised to their analytical steady-state depths before spin-up (see
_steady_state_depths()).post_spinup_states (dict, optional) – Reservoir water depths injected after spin-up completes and before the scored run begins. Same format as
initial_statesbut only the'reservoirs'key is used; individual entries may beNoneto leave that reservoir at its spin-up end state. Intended for calibrating decade-specific initial storage (e.g.log__H0_deep) when the spin-up equilibrium is poorly constrained by sparse pre-decade forcing. Only applied in decade mode (startis not None); ignored in full-record mode.post_spinup_k (int, optional) – Number of free parameters contributing to
post_spinup_states(for AIC counting). Default 0.start (str or datetime-like, optional) – Start of the scoring window (inclusive). Score, AIC, BFI, and FDC are all computed within this window. Spin-up still uses the full record.
end (str or datetime-like, optional) – End of the scoring window (inclusive). Same as start.
spin_up_cycles (int or None, optional) – Number of times to loop the full record before the scored run.
None(default) auto-computes asceil(tau_max / record_length), wheretau_maxis the longest reservoir e-folding time after parameter overrides andrecord_lengthis the number of days in the input record. Because initial conditions are set to analytical steady-state depths, one e-folding time is sufficient to resolve the seasonal and inter-annual climate memory. Set to 0 when providing initial_states for chained decade runs.metric ({'KGE', 'NSE', 'logKGE', 'KGE_logKGE', 'KGE_logKGE_logFDC',) – ‘KGE_logKGE_logFDC_BFI’}, optional Goodness-of-fit metric. Default is ‘KGE’.
'KGE_logKGE'returns 0.5*KGE + 0.5*logKGE, balancing peak and low-flow performance (Yilmaz et al. 2008).'KGE_logKGE_logFDC_BFI'adds a BFI bias-ratio score (1 - abs(BFI_mod/BFI_obs - 1)) as a fourth equal-weight component.routing_N (int, optional) – Number of identical linear reservoirs in the Nash cascade used for channel routing (shape parameter of the gamma IUH). Default is 2. Set routing_K to enable routing; routing_N is counted as a free parameter in k only when it is explicitly calibrated (the caller must add 1 to the k count via run_and_score if routing_N is varied).
routing_K (float or None, optional) – Storage time constant [days] of each Nash-cascade reservoir (scale parameter). Mean travel time through the cascade is routing_N * routing_K. When None (default), no routing is applied and the model output is compared directly to observed discharge. When provided, routing_K is counted as one free parameter.
modules (dict or None, optional) – Enable/disable optional process modules. Keys:
'snowpack','frozen_ground','rain_on_snow','direct_runoff'. Values: bool. Overrides themodulesblock in the YAML config. Absent keys leave the YAML/default value unchanged.enforce_water_balance (str, optional) – ‘water-year’ (default): scale ET by a per-water-year multiplier so that P - Q - ET = 0 over each water year. ‘global’: scale ET by a single multiplier computed from sum(P - Q_obs) / sum(ET_raw) over the full record — no per-year overfitting, does not add hidden degrees of freedom to AIC. ‘none’: use raw ET without correction (only for measured ET). Legacy boolean True/’False are silently mapped to ‘water-year’/’none’. Overrides the enforce_water_balance key in the YAML config.
- Returns:
Named tuple with fields
score,aic,bfi_obs,bfi_mod,fdc_obs,fdc_mod,final_states, andbuckets. SeeCalibResultfor full field descriptions. All scalar fields arenp.nanif the scoring window contains no valid overlapping data.- Return type:
Notes
When
startis provided, the function operates in decade mode:enforce_water_balance='global'closes the water balance over the full record (computed once at initialization), not re-fitted to the decade window. Re-fitting would assume ΔS = 0 over the decade, which is incorrect for transitional wet/dry decades.Spin-up runs only the pre-decade data (record start through the day before
start), so reservoir states at the beginning of the decade reflect pre-decade climatology rather than an arbitrary end-of-record state.The scored run covers
[start, end]only, continuing directly from the spin-up end state.
When
startis None (default), the original full-record behaviour is preserved: spin-up and scoring both run the complete hydrodata record.
CalibResult
Named tuple returned by run_and_score().
- class mnished.CalibResult(score, aic, bfi_obs, bfi_mod, kge_logfdc, fdc_obs, fdc_mod, final_states, buckets)
Named tuple returned by
run_and_score().- score
Goodness-of-fit score (higher is better). Metric is one of KGE, NSE, or logKGE as requested; see
run_and_score().- Type:
- aic
Akaike Information Criterion computed on log-transformed flows (lower is better). Useful for comparing models with different numbers of free parameters.
- Type:
- bfi_obs
Baseflow index of the observed discharge, computed with the Eckhardt (2005) recursive digital filter.
- Type:
- fdc_obs
Observed flow duration curve: discharge at 99 evenly-spaced exceedance probabilities (0.5–99.5 %), indexed by exceedance %.
- Type:
pd.Series
- fdc_mod
Modelled flow duration curve (same format as fdc_obs).
- Type:
pd.Series
- final_states
End-of-run reservoir states suitable for passing as
initial_statesto the next call:{'reservoirs': [H_shallow, H_deep, ...], # [mm] 'snowpack': H_snow_SWE, # [mm SWE] 'fgi': frozen_ground_index} # [°C·day]
- Type:
- buckets
The
Bucketsobject after the final run, including the fullhydrodataDataFrame with modelled discharge.- Type:
- All scalar fields are ``np.nan`` if the scoring window contains no
- valid overlapping data.
HydrographSeparation
Spectral and time-domain decomposition of a discharge record into reservoir-timescale components.
- class mnished.HydrographSeparation(Q, dt=1.0, n_reservoirs=None, max_reservoirs=4, precip=None, recession_min_duration=10, recession_precip_threshold=0.5, recession_antecedent_days=3, tau_deep=None, tau_fast=None)[source]
Bases:
objectSeparate observed discharge into reservoir components and estimate timescales and initial storage depths.
- Parameters:
Q (array-like) – Observed specific discharge [mm/day].
dt (float) – Timestep [days]. Default 1.0.
n_reservoirs (int or None) – Number of reservoirs. If None, selected by AIC on the spectral fit. The slowest reservoir (karst/deep) is always fitted by recession analysis regardless of this setting.
max_reservoirs (int) – Maximum number of reservoirs to test when n_reservoirs is None. Default 4.
precip (array-like or None) – Daily precipitation [mm/day], same length as Q. Used to mask recession periods; if None, only discharge decline is used.
recession_min_duration (int) – Minimum qualifying recession length [days]. Default 10.
recession_precip_threshold (float) – Maximum daily precipitation within a recession segment [mm/day]. Default 0.5.
recession_antecedent_days (int) – Number of days immediately before a recession that must also be dry. Default 3.
tau_deep (float or None) – Externally supplied timescale [days] for the deep (karst) reservoir. When provided, recession fitting is skipped for τ_karst and this value is used directly. Recommended when τ_karst >> T_record, since a decay too slow to observe cannot be reliably estimated from the discharge record alone.
tau_fast (array-like or None) – Externally supplied timescales [days] for the fast reservoirs (all except the deepest), e.g. from a prior calibration run. When provided, spectral fitting is skipped. Note: spectral corner periods are 2πτ, not τ — a 29-day reservoir has its -3 dB corner at 182 days, and a 466-day soil reservoir at ~8 years, which may lie near or beyond the record length and be unreliable from spectral fitting alone.
fit()) (Attributes (populated after)
------------------------------------
tau (ndarray) – Reservoir timescales [days], ordered slowest to fastest.
H0 (ndarray) – Initial storage depths [mm], same order as tau.
n_reservoirs_fitted (int) – Number of reservoirs selected (spectral fast + 1 karst).
aic_scores (list of float) – AIC values for k = 1 … max_reservoirs-1 spectral fits.
tau_karst (float) – Deep-reservoir timescale [days] from recession fitting.
- get_initial_conditions()[source]
Initial reservoir storage depths, ordered fastest to slowest (shallow first, karst last), matching the MNiShed reservoir index convention.
- Returns:
{'H0': [H0_shallow, H0_soil, ..., H0_karst]}in mm.- Return type:
- get_parameter_priors()[source]
Suggested initial values and bounds (in params.yml units) for the MNiShed log__recession_coeff_* calibration parameters.
Bounds are ±0.5 in log10 around the estimated timescale — wide enough to allow the optimizer freedom, tight enough to stay physical.
- Returns:
Keyed by MNiShed parameter name. Each value is a dict with
'initial','lower','upper'in log10(days).- Return type: