Releases: MNiMORPH/MNiShed
MNiShed v3.1.0
MNiShed v3.1.0 — a backward-compatible minor release (single-cascade behaviour is unchanged from v3.0.0).
Added
- Parallel sub-catchments: a basin can be partitioned into spatially distinct
zones that drain to the same channel in parallel, each with its own
reservoir cascade and snowpack/frozen-ground state. Basin discharge and
storage are the area-weighted means over sub-catchments. Configure with a
sub_catchments:YAML block (each entry has aname,area_fraction, its
ownreservoirsblock, and optionalinitial_conditions); calibrate by
passing asub_catchments=[...]argument torun_and_score. Supported on
both the pure-Python and Numba JIT time loops. A single sub-catchment of
area 1.0 reproduces the previous single-cascade behaviour exactly, so
existing configurations and calls are unchanged. NewSubCatchmentclass
andBuckets.sub_catchments/Buckets.n_sub_catchments.
run_and_scorechains per-sub-catchment storage state (reservoir depths,
snowpack, frozen-ground index, carried deficit) across decade windows:
final_states/initial_statesare nested per sub-catchment when there
are several, and stay flat/scalar for a single sub-catchment. - The Numba JIT now covers PDM saturation-excess (
pdm_H0) and
et_water_stress; those configurations previously fell back to the
pure-Python loop. The JIT and pure-Python loops remain verified-identical, so
the JIT is now used for every supported configuration whenever Numba is
importable.
Changed
- The pure-Python time-loop fallback is no longer silent.
Buckets.run()emits
a one-timeUserWarningwhen Numba is installed but fails to import (usually
a NumPy/Numba version mismatch), so an unexpected ~100× slowdown is visible.
A plain "Numba not installed" stays quiet, since pure Python is the expected
default without thejitextra.
Deprecated
- The flat single-sub-catchment state shape (
{'reservoirs': [...], 'snowpack': ..., 'fgi': ...}) forrun_and_score'sinitial_states/
post_spinup_states. Passing it now emits aDeprecationWarning; it will be
removed in v4.0 in favour of the uniform per-sub-catchment form
({'sub_catchments': [...]}). See
#18. The nested form is
accepted at any number of sub-catchments (including one) and does not warn.
Fixed
run_and_scorenow validates chainedinitial_states/post_spinup_states
and raises a clearValueErrorif they contain non-finite (NaN/inf) values,
naming the offending key/index. Previously a NaN state from a partial-data or
failed decade propagated silently — every modelled flow became NaN and the
score looked merely poor rather than broken. (Nonereservoir entries in
post_spinup_states, meaning "keep the spin-up value", are still allowed.)- The BMI
snowpack__liquid_equivalent_depthand
land_surface__frozen_ground_indexoutputs are now the area-weighted basin
mean over sub-catchments, instead of reporting only the first sub-catchment.
Exact for a single sub-catchment, so K=1 couplers are unchanged
(#16).
MNiShed v3.0.0
TL;DR
Major release. The library was renamed from hydroRaVENS to MNiShed.
Several parameter, attribute, and config names changed (see the migration
table below). The numerical core moved to a Numba JIT time loop —
roughly 100×–400× faster than the pure-Python loop depending on record
length — installable via the new jit extra (pip install mnished[jit]). New mechanics: power-law (nonlinear) recession,
leakance + threshold junctions between reservoirs, constant-fraction
tile drainage and threshold-activated multipath parallel drainage,
and exponential PDM saturation-excess overland flow, plus snow
insulation, DTR-based frozen-ground decay, and flexible ET modules. A
CSDMS BMI wrapper (BmiMNiShed) was introduced with CSDMS Standard
Names–aligned variables. GitHub Actions CI added. Substantial
calibration-robustness and numerical-correctness fixes (water-balance
closure, deficit handling, NaN propagation, multi-decade chaining,
JIT↔pure-Python equivalence, and the mean-residence-time gauge).
Breaking changes (you'll need to update existing code/configs)
| Old | New | Where it bites |
|---|---|---|
Package name hydroRaVENS |
mnished |
imports, install: pip install mnished, from mnished import ... |
BMI class BmiHydroRaVENS |
BmiMNiShed |
BMI users update the class name and import (from mnished import BmiMNiShed) |
Reservoir(t_efold=...) / t_recession=... |
Reservoir(recession_coeff=...) |
constructor arg name |
YAML e_folding_residence_times__days: |
recession_coefficients: |
all config files |
Reservoir.H_infiltrated |
Reservoir.H_to_next |
attribute access |
Boolean scale_et=True/False |
string enforce_water_balance='water-year' / 'global' / 'none' |
run_and_score() argument; YAML enforce_water_balance: key |
evapotranspiration_method: ThorntwaiteChang2019 (misspelled) |
ThornthwaiteChang2019 |
YAML evapotranspiration_method: value |
BMI variable names (atmosphere__temperature, daily min/max temperature, channel_exit_water__volume_flow_rate, ET forcing input) |
CSDMS-aligned (atmosphere_bottom_air__temperature, …__time_min_of_temperature / …__time_max_of_temperature, channel_exit_water_x-section__volume_flow_rate, …__uncorrected_evapotranspiration_volume_flux) |
BMI couplers update variable names |
Migration: for an existing config + driver pair, do a global
search-and-replace on the old terms (t_efold, t_recession,
e_folding_residence_times__days, H_infiltrated, and the misspelled
ThorntwaiteChang2019 → ThornthwaiteChang2019), and re-spell
scale_et=True/False as the corresponding enforce_water_balance
string. BMI couplers update the variable names above. Note also that
Buckets.initialize() now raises FileNotFoundError / yaml.YAMLError
on a missing or unparseable config file instead of calling sys.exit(), so
library, BMI, and notebook callers can handle the error (the mnished CLI
still exits cleanly).
New features
Numerical core
- Numba JIT-compiled time loop (
_jit_run). The daily loop is roughly
100×–400× faster than the pure-Python implementation, scaling with
record length (~120× on a 3-year run, ~300–400× on multi-decade to
century-long daily records — see the Performance page in the documentation
for the full scaling analysis and benchmark scripts). Used automatically
when Numba is installed; install it with thejitextra (pip install mnished[jit]). The pure-Python loop is retained as a fallback for
non-Numba environments and for code paths that don't yet fit into the JIT
(PDM, ET water-stress).
Reservoir mechanics
- Power-law (nonlinear) recession.
recession_exponentsper reservoir
(default 1.0 = linear). Exact integration in the JIT loop;
mean_residence_time()for physically-comparable timescales at a
reference discharge. - Junction types between reservoirs. New
junction_typeargument
onReservoirand matchingjunction_types:,leakance_R__days:,
H_threshold__mm:YAML keys:fraction(default, current behaviour)leakance— head-difference driven flow with leakance resistance Rthreshold— dead-storage threshold; recession only above H_threshold
- Tile drain sub-reservoir.
f_tile+tau_tiledivert a constant
fraction of subsurface drainage to a fast linear sub-reservoir that
drains directly to stream. Represents constant-fraction agricultural
tile bypass. - Multipath threshold-activated parallel drain. New
multipath_threshold+multipath_timescaleon Reservoir; per-reservoir
YAML listsmultipath_thresholds__mm/multipath_timescales__days.
Adds a second linear outflow path direct to stream when storage
exceeds the threshold. Distinct fromf_tile/tau_tile: it is
state-dependent (activates only above the threshold), not a constant-
fraction split. Models a tile-drain network at a fixed installation
depth. Both tile mechanisms can be configured independently. - Exponential PDM saturation-excess overland flow.
pdm_H0opens up
the probability-distributed-model fraction of recharge that is shed
immediately to discharge from a fraction of catchment with
exponentially-distributed storage capacities.
Hydrologic processes
- Snowpack insulation in FGI.
snow_insulation_kreduces effective
air temperature reaching the soil under deep snowpack, with
documented equifinality caveats. - DTR-based FGI decay. When daily Tmax/Tmin are available, FGI decay
coefficient A_t scales with the fraction of the day above 0°C
(Molnau & Bissell 1983); falls back to the constant A=0.97 when not. - Constant regional baseflow
baseflow_Qfor cases with sub-basin
groundwater import. - Direct-runoff (Hortonian) bypass.
direct_runoff_fraction(γ):
fraction of positive recharge that bypasses the cascade. Reframed
from a snow-coupled to a free fast-bypass parameter. - ET module flexibility. Three independent module toggles:
et_reservoir_draw: post-cascade ET drawn from reservoirs with
optional wilting-point threshold (recommended for calibrations
with a soil reservoir)et_water_stress: storage-dependent ET scaling (et_scale,
wp_soil,wp_soil_sigma)et_scaleis also usable as a free universal ET multiplier when
neither stress module is enabled
- Water-balance enforcement vocabulary.
enforce_water_balance
accepts'water-year','global','none'instead of a single
boolean.'global'rescales ET by a single multiplier across the
entire record (no hidden per-year DoFs that would inflate AIC). - Module enable/disable toggles. Top-level
modules:block in
YAML to switch snowpack, frozen_ground, rain_on_snow, direct_runoff,
dtr_fgi_decay, et_water_stress, et_reservoir_draw on/off. - Auto-compute spin-up cycles. When
spin_up_cycles=None,
computed automatically as ceil(tau_max / record_length). - Analytical steady-state initial conditions. Used by default
before spin-up to remove cycle-zero artifacts. post_spinup_stateshook. Inject per-decade initial conditions
after spin-up; supports decade-chaining workflows where each new
decade starts from the prior decade's end state.
Analysis and diagnostics
- BrutsaertNieber recession analysis class. Fits −dQ/dt = a·Q^b to
observed hydrograph recessions for B-N-style architecture diagnosis.
Power-law goodness-of-fit diagnostics included. - HydrographSeparation class. Data-driven model initialization;
time-domain recession analysis is now the primary timescale estimator,
with the spectral (PSD) approach retained as a fallback/diagnostic;
rolling-minimum τ_soil estimation, decoupled from LP separation. Priorsandsuggest_priors. Suggested prior distributions for
calibration parameters from observed-data diagnostics.- Composite scoring metrics.
KGE_logKGE,KGE_logKGE_logFDC,
KGE_logKGE_logFDC_BFI,logKGE_logFDC_BFI. The mean-of-multiple-
KGEs framing avoids over-emphasizing high flows. kge_logfdcdiagnostic onCalibResult.Reservoir.mean_residence_time()for nonlinear reservoirs:
physically-comparable timescale at a reference steady-state discharge.
CSDMS BMI wrapper
BmiMNiShedclass implementing the Community Surface
Dynamics Modeling System Basic Model Interface.- 10-reservoir cap (up from 3) via
reservoir_0throughreservoir_9. channel_exit_water_x-section__volume_flow_rateBMI output in m³ s⁻¹.- Variable names reviewed against the current CSDMS Standard Names
conventions: air temperature uses theatmosphere_bottom_airobject
(atmosphere_bottom_air__temperature, and
…__time_min_of_temperature/…__time_max_of_temperaturefor the daily
extremes). The ET forcing input is
land_surface_water__uncorrected_evapotranspiration_volume_flux— a
deliberately model-specific name for the ET as supplied (Thornthwaite or
user series), before the water-balance correction — distinct from the
corrected ET outputland_surface_water__evapotranspiration_volume_flux. - Flux-partition, state, and ET outputs: direct-runoff, baseflow,
tile-drain, and multipath*_volume_fluxcomponents, plus
land_surface__frozen_ground_indexand an actual-ET
land_surface_water__evapotranspiration_volume_fluxoutput. The
baseflow term (baseflow_Q) is exposed as its own output and is not
folded into the runoff total, so a coupler adds it explicitly. Note this
differs fromrun_and_score, whose scored discharge does include
baseflow_Qand Nash routing (routing_K) as output-layer
post-processing; the streaming BMI applies neither (routing is an
inherently batch operation), so a routed/baseflow-augmented calibration
is not reproduced through the BMI unless the coupler reapplies them. - BMI tests skip gracefully if
bmipynot installed; `bmip...
v2.3.0
What's new in v2.3.0
Physics and correctness
- Rain-on-snow sensible heat melt (McCabe et al. 2007; Würzer et al. 2016): precipitation arriving at T > 0 °C contributes (c_p/L_f)·T·P mm SWE of melt energy
- Frozen ground index (Molnau & Bissell 1983): accumulates freezing degree-days; when it exceeds a user-set threshold, shallow-to-deep infiltration is blocked (all drainage becomes direct runoff)
- Leftover melt energy after snowpack exhaustion is credited to frozen-soil thawing rather than discarded
- Nash-cascade channel routing in
run_and_score()(routing_N,routing_Kparameters)
Bug fixes
check_mass_balance(): now subtracts initial storage so the discrepancy is ~0 for a mass-conserving runrun(): resets internal time counter at the start, so calling it more than once (e.g. spin-up + main run) no longer crashescompute_ET_multiplier(): warns when annual discharge exceeds precipitation (ET multiplier ≤ 0 would make ET water-generating)compute_ET(): uses.to_numpy()for the ET scaling product to prevent silent row misalignment after the water-year merge_update_fgi(): raises a clearValueErrorwhen FGI is enabled but temperature data is absent, instead of an opaqueKeyErrorcalibration.run_and_score():_fgi(frozen ground index) is now included infinal_statesand restored frominitial_statesso frozen-ground state is physically continuous when chaining decade runscalibration.run_and_score():b.melt_factorkept in sync withb.snowpack.melt_factorwhen overriding
Naming and clarity
- YAML keys
water_reservoir_effective_depths__m,maximum_effective_depths__m, andsnowpack__m_SWErenamed to__mmvariants to match the actual unit used throughout Buckets.H_deficitrenamed toH_deficit_carryto accurately describe it as a timestep carry-over debt, not a cumulative accumulation- CalibResult extended with
bfi_obs,bfi_mod(Eckhardt baseflow index),fdc_obs,fdc_mod(flow duration curves), andfinal_statesfor decade chaining
Breaking changes
- YAML config files must use the new
__mmkey names (water_reservoir_effective_depths__mm,maximum_effective_depths__mm,snowpack__mm_SWE)
v2.2.0
Documentation
- Launched full Sphinx documentation site on ReadTheDocs, including model description, configuration reference, API reference, and bibliography
- Added NumPy-style docstrings to all public methods and classes
- Expanded README with installation instructions, quick-start example, data format description, and model overview
- Added
CONTRIBUTING.mdwith bug-reporting guidelines, code-contribution workflow, and style conventions
Bug fixes
- Fixed
AttributeErrorwhen accessingself.snowpackon runs without a temperature column; snowpack operations are now guarded byself.has_snowpackthroughout - Fixed spin-up restart resetting to index
0instead ofself.hydrodata.index[0], which produced wrong results when the DataFrame index did not start at zero - Fixed
check_mass_balance()raisingTypeErrorwhen called withtime_step=None; now correctly defaults to the full record - Fixed loop-variable leakage in
update()whereself.H_deficitwas set fromself.reservoirs[i]using a post-loopi; now usesself.reservoirs[-1] - Fixed
groupby().mean()FutureWarningin recent Pandas by passingnumeric_only=True - Fixed
t_efold <= 0validation (previously only caught negative values, not zero, which caused division by zero)
Packaging and infrastructure
- Replaced
setup.py/setup.cfgwithpyproject.toml(PEP 517/621) - Replaced manual PyPI upload scripts with GitHub Actions using Trusted Publishers (OIDC — no stored API tokens)
- Added
build-check.ymlworkflow to validate the distribution on every push and pull request - Added
dependabot.ymlfor automated dependency and Actions version updates
Code quality
- Removed dead code: unused instance attributes, unreachable methods, stale commented-out blocks
- Removed development-era comments and inline to-do notes from public-facing code
- Applied PEP 8 style fixes throughout (spacing, parentheses, naming)
- Reorganized Cannon River example into
examples/cannon_river/ - Fixed Chang et al. (2019) citation with verified title and DOI
v2.1.0 — hydroRaVENS
Corrections and refactoring of the Thorntwaite–Chang (2019) evapotranspiration implementation, prompted by a close reading of Chang et al. (2019).
Bug fixes
- Tmin was incorrectly read from the maximum-temperature column; now correctly reads from minimum temperature
- Transcription error in Thornthwaite exponent a: coefficient on I² corrected from 7.72×10⁻⁵ to 7.71×10⁻⁵
Improvements
_compute_Chang_I()and_compute_Chang_a()extracted as proper methods;Buckets()now acceptsT_monthly_normals(array of 12 monthly mean temperatures in °C) to compute the thermal index I from the local climate- Hardcoded site-specific fallback value for I removed;
initialize()now raises a clearValueErrorifThorntwaiteChang2019is selected withoutT_monthly_normalshaving been passed toBuckets() - Calibration coefficient k in the T_ef formula is now an explicit parameter (default 0.69 per Pereira & Pruitt 2004, doi:10.1016/j.agrformet.2004.01.005); use 0.72 for monthly ET per Camargo et al. (1999)
- Piecewise logic replaced with
np.wherefor clarity and correctness - Full NumPy-style docstring added with equation references and DOIs
v2.0.0 — hydroRaVENS
This release marks a complete overhaul of the package, previously distributed as a single-file script called bucketHydrology. The model is now a proper Python package named hydroravens, installable via pip, with a CSDMS-compliant BMI interface and a command-line entry point.
Breaking changes
- Package renamed from
bucketHydrologytohydroravens; all existing import and calling code must be updated - Model configuration is now driven entirely by a YAML file; the old script-based interface is gone
New features
- CSDMS Basic Model Interface:
initialize(),update(),run(),finalize() - Command-line interface:
hydroravens -y config.yml - Snowpack model with positive-degree-day melt, fully integrated with mass balance
- Evapotranspiration: read from data file or computed via the Thorntwaite–Chang (2019) method
- Water-year ET scaling to enforce P − Q − ET = 0 mass balance
- Nash–Sutcliffe Efficiency (
computeNSE()) - Configurable spin-up cycles
- Subsurface storage tracked as model output
CITATION.cffadded
Infrastructure
- pip-installable via
setup.py - Version number introduced (
2.0.0) - Cannon River included as reference test case and example configuration
Note: version infrastructure and tag created 2026-05-04 and backdated to 2023-11-21 to match the date of the substantive work.