Methods

Each method is a dataclass whose fields are its parameters; route() runs it. The examples below use the methods on their own. In a network model they are chosen in the model file and supplied with their inputs at run time (see Network models). Units, defaults and constraints for each parameter are in the API reference.

Loss methods

InitialConstant

from pyrunoff.loss import InitialConstant

loss = InitialConstant(
    rainfall_series=rain_series,
    initial_loss=0.2,
    constant_loss=0.25,
)
loss_output = loss.route()

Returns an InitialConstantOutput with excess and total_loss rainfall series.

DeficitConstant

from pyrunoff.loss import DeficitConstant

loss = DeficitConstant(
    rainfall_series=rain_series,
    max_deficit=0.2,
    constant_loss=0.1,
    recovery_time=pd.Timedelta(hours=12),
    initial_deficit=0.2,
)
loss_output = loss.route()

Returns a DeficitConstantOutput with excess, deficit, constant_loss and total_loss series. The deficit recovers during dry periods by default, which requires recovery_time; pass recover_deficit=False to turn recovery off.

Transform methods

ClarkUh

from pyrunoff.transform import ClarkUh

uh = ClarkUh(
    rainfall_series=loss_output.excess,
    basin_area=6236.6,
    tc=pd.Timedelta(hours=2.5),
    storage_r=pd.Timedelta(hours=7.5),
)
runoff = uh.route()

tc is the time of concentration and storage_r the Clark storage coefficient. See route() for returning results at the one-minute computation interval.

Baseflow methods

LinearReservoir

from pyrunoff.baseflow import LinearReservoir

baseflow = LinearReservoir(
    rainfall_series=loss_output.total_loss,
    gw_fraction=0.7,
    k=pd.Timedelta(hours=12),
    basin_area=6236.6,
).route()

Reach routing

Muskingum

import pandas as pd

from pyrunoff.reach import Muskingum
from pyrunoff.utils import DischargeSeries

inflow = DischargeSeries(
    pd.Series(
        [0.0, 5.0, 15.0, 8.0], index=pd.date_range("2024-01-01", periods=4, freq="1h")
    ),
    sorted=True,
)
routed = (
    Muskingum(
        inflow_series=inflow,
        k=pd.Timedelta(hours=2),
        x=0.25,
    )
    .route()
    .total_outflow
)

Reservoir routing

LevelPool

import pandas as pd

from pyrunoff.reservoir import ElevationStorage, LevelPool, StorageDischarge
from pyrunoff.utils import DischargeSeries

inflow = DischargeSeries(
    pd.Series(
        [0.0, 5.0, 15.0, 8.0], index=pd.date_range("2024-01-01", periods=4, freq="1h")
    ),
    sorted=True,
)

storage_curve = ElevationStorage(
    # Elevation is in feet and storage is in acre-feet.
    elevation=pd.Series([650.0, 651.0, 652.0]),
    storage=pd.Series([0.0, 80.0, 200.0]),
)

rating_curve = StorageDischarge(
    # Storage is in acre-feet and discharge is in cubic feet per second.
    storage=pd.Series([0.0, 80.0, 200.0]),
    discharge=pd.Series([0.0, 50.0, 150.0]),
)

reservoir = LevelPool(
    inflow_series=inflow,
    elevation_storage=storage_curve,
    storage_discharges={"outlet": rating_curve},
    initial_storage=0.0,
)
result = reservoir.route()
outlet_flow = result.outflows["outlet"]
total_outflow = result.total_outflow
storage = result.storage
elevation = result.elevation

Returns a LevelPoolOutput. Its outflows field maps each outlet name to a DischargeSeries; total_outflow, storage and elevation are DischargeSeries, StorageSeries and ElevationSeries values. Access the underlying pandas series through each value’s .data attribute.

Performance metrics

nse() returns a Nash–Sutcliffe Efficiency score. kge() returns a KgeResult holding the 2012 Kling–Gupta Efficiency score (kge) and its components (corr_coef, gamma and beta).

import pandas as pd

from pyrunoff.metrics import kge, nse

observed = pd.Series(
    [2.0, 4.0, 6.0], index=pd.date_range("2024-01-01", periods=3, freq="1h")
)
simulated = pd.Series([2.5, 3.5, 6.5], index=observed.index)

nse_score = nse(observed, simulated)
kge_result = kge(observed, simulated)
print(nse_score, kge_result.kge, kge_result.corr_coef)

Set use_low_flow_transform=True to emphasize low-flow performance; low_flow_percentile sets the transform scale.