Getting started¶
Installation¶
We recommend installing with uv for a fast, reproducible Python environment.
The current PyPI release is an alpha release, and requires Python 3.14 or later. pip commands include --pre to select this prerelease.
Recommended: Install with Numba acceleration¶
uv add "pyrunoff[with-numba]"
# or
python -m pip install --pre "pyrunoff[with-numba]"
Numba compiles numerical kernels for faster execution on long time series.
Install without Numba¶
uv add pyrunoff
# or
python -m pip install --pre pyrunoff
Without Numba, the library still works but runs its numerical kernels in Python mode, which may be slower for long simulations.
Core API¶
The library provides:
RainfallSeries,DischargeSeries,ElevationSeries, andStorageSeriesfor time-indexed dataInitialConstantandDeficitConstantloss models, with typed output dataclassesClarkUhfor Clark unit-hydrograph transformationLinearReservoirfor baseflow routingMuskingumfor channel routing, returningMuskingumOutputLevelPoolfor reservoir routing, returningLevelPoolOutputnseandkgemodel-performance metrics inpyrunoff.metricsNetworkfor topological ordering of flow paths inpyrunoff.utils.networkModelfor routing rainfall through a network of basins, reaches, junctions and reservoirs, withload_model,load_paramsandload_rainfallfor reading its inputs from files
The library is designed as a modular toolkit for composing hydrologic routing operations in Python.
Quick start¶
import pandas as pd
from pyrunoff.baseflow import LinearReservoir
from pyrunoff.loss import InitialConstant
from pyrunoff.reach import Muskingum
from pyrunoff.transform import ClarkUh
from pyrunoff.utils import RainfallSeries
# Example rainfall data
rain = pd.Series(
[0.0, 0.8, 1.4, 0.4, 0.0, 0.0],
index=pd.date_range("2024-01-01", periods=6, freq="1h"),
)
rain_series = RainfallSeries(rain, sorted=True)
# 1) Compute losses
loss_model = InitialConstant(
rainfall_series=rain_series,
initial_loss=0.25,
constant_loss=0.15,
)
loss_output = loss_model.route()
# 2) Transform excess precipitation into direct runoff
clark = ClarkUh(
rainfall_series=loss_output.excess,
basin_area=1000.0,
tc=pd.Timedelta(hours=2),
storage_r=pd.Timedelta(hours=3),
)
direct_runoff = clark.route()
# 3) Generate baseflow
baseflow = LinearReservoir(
rainfall_series=loss_output.total_loss,
gw_fraction=0.7,
k=pd.Timedelta(hours=6),
basin_area=1000.0,
).route()
# 4) Route channel flow with Muskingum
routed_flow = (
Muskingum(
inflow_series=direct_runoff,
k=pd.Timedelta(hours=2),
x=0.25,
)
.route()
.total_outflow
)
print(direct_runoff.data)
print(baseflow.data)
print(routed_flow.data)