Network model¶
Network model of basins, reaches, reservoirs and junctions.
An element’s type fixes which processes it computes (ELEMENT_PROCESSES),
and the model picks one method per process (METHOD_CLASSES).
- class pyrunoff.utils.model.ElementType(*values)[source]¶
Bases:
StrEnumKind of node an element is in the network.
- class pyrunoff.utils.model.Process(*values)[source]¶
Bases:
StrEnumHydrologic process an element computes with a selectable method.
- class pyrunoff.utils.model.Method(*values)[source]¶
Bases:
StrEnumCalculation method used for a process.
- class pyrunoff.utils.model.BasinOutput(input, excess, total_loss, baseflow, direct_runoff, total_outflow)[source]¶
Bases:
objectResults of routing a basin.
- Parameters:
input (RainfallSeries) – Rainfall on the basin.
excess (RainfallSeries) – Rainfall remaining after losses.
total_loss (RainfallSeries) – Rainfall removed by the loss method.
baseflow (DischargeSeries) – Baseflow from the rainfall loss.
direct_runoff (DischargeSeries) – Runoff from the excess rainfall.
total_outflow (DischargeSeries) – Direct runoff plus baseflow.
- class pyrunoff.utils.model.LossResult(*args, **kwargs)[source]¶
Bases:
ProtocolOutput every loss method’s
route()must return.
- class pyrunoff.utils.model.RoutingResult(*args, **kwargs)[source]¶
Bases:
ProtocolOutput every reach or reservoir routing method’s
route()must return.Methods may add their own fields (e.g. storage for reservoirs).
- class pyrunoff.utils.model.ReachOutput(input, routing_output, total_outflow)[source]¶
Bases:
objectResults of routing a reach.
- Parameters:
input (DischargeSeries) – Total inflow from upstream elements.
routing_output (RoutingResult) – Full output of the routing method.
total_outflow (DischargeSeries) – Routed outflow.
- class pyrunoff.utils.model.ReservoirOutput(input, routing_output, total_outflow)[source]¶
Bases:
objectResults of routing a reservoir.
- Parameters:
input (DischargeSeries) – Total inflow from upstream elements.
routing_output (RoutingResult) – Full output of the routing method (outflow per outlet, storage and elevation).
total_outflow (DischargeSeries) – Sum of outflow across all outlets.
- class pyrunoff.utils.model.JunctionOutput(input, total_outflow)[source]¶
Bases:
objectResults of routing a junction.
- Parameters:
input (DischargeSeries) – Total inflow from upstream elements.
total_outflow (DischargeSeries) – Outflow, equal to the inflow.
- class pyrunoff.utils.model.SinkOutput(input)[source]¶
Bases:
objectResults of routing the sink, which has no outflow.
- Parameters:
input (DischargeSeries) – Total inflow from upstream elements.
- pyrunoff.utils.model.ELEMENT_PROCESSES: dict[ElementType, dict[Process, tuple[Method, ...]]] = {ElementType.BASIN: {Process.BASEFLOW: (Method.LINEAR_RESERVOIR,), Process.LOSS: (Method.INITIAL_CONSTANT, Method.DEFICIT_CONSTANT), Process.TRANSFORM: (Method.CLARK_UH,)}, ElementType.JUNCTION: {}, ElementType.REACH: {Process.ROUTING: (Method.MUSKINGUM,)}, ElementType.RESERVOIR: {Process.ROUTING: (Method.LEVEL_POOL,)}, ElementType.SINK: {}}¶
Processes each element type computes, and the methods allowed for each.
- pyrunoff.utils.model.METHOD_CLASSES: dict[Method, type] = {Method.CLARK_UH: <class 'pyrunoff.transform.clark_uh.ClarkUh'>, Method.DEFICIT_CONSTANT: <class 'pyrunoff.loss.deficit_and_constant.DeficitConstant'>, Method.INITIAL_CONSTANT: <class 'pyrunoff.loss.initial_and_constant.InitialConstant'>, Method.LEVEL_POOL: <class 'pyrunoff.reservoir.level_pool.LevelPool'>, Method.LINEAR_RESERVOIR: <class 'pyrunoff.baseflow.linear_reservoir.LinearReservoir'>, Method.MUSKINGUM: <class 'pyrunoff.reach.muskingum.Muskingum'>}¶
Class implementing each method.
- pyrunoff.utils.model.ElementParams¶
Constructor arguments for a method, keyed by element name, e.g.
loss_params["B1"] = {"initial_loss": 0.5, "constant_loss": 0.1}.
- class pyrunoff.utils.model.Element(name, type, methods=<factory>)[source]¶
Bases:
objectModel element; identity (equality and hash) is its name and type.
- Parameters:
name (str) – Unique element name.
type (ElementType) – Element type.
methods (Mapping[Process, Method]) – Method for every process the element type computes.
- Raises:
ValueError – If a method is invalid or a process has no method.
- class pyrunoff.utils.model.Model(elements, upstream_elements, defaults=<factory>)[source]¶
Bases:
objectNetwork of elements in execution order.
The dictionary form read by
from_dict()and written byto_dict()lists each element once:{ "defaults": {"<element type>": {"<process>": "<method>"}}, "elements": { "<element>": { "type": "<element type>", "downstream": "<element>", "<process>": "<method>" } } }
Every element needs a
type. Exactly one element has nodownstream; it is the model’s sink and itstypemust be"sink". No other element may be a sink.An element’s method for a process is taken from its own entry, otherwise from
defaultsfor its type. Every process of every element must end up with a method;ELEMENT_PROCESSESlists the allowed ones.- Parameters:
- classmethod from_dict(data)[source]¶
Build a model from its dictionary form (see class docstring).
- Parameters:
data (dict) – Model in dictionary form.
- Returns:
The model, with elements in execution order.
- Raises:
ValueError – If there is not exactly one sink, an element has no type, a downstream element is undefined, or a method is invalid or missing.
- Return type:
- to_dict()[source]¶
Return the dictionary form; elements list only methods that differ from
defaults.- Return type:
- route(rainfall, loss_params=None, transform_params=None, baseflow_params=None, reach_params=None, reservoir_params=None)[source]¶
Route rainfall through the model in execution order.
Each element uses the method given in its
Element’smethodsfor each of its processes. Parameters are keyed by element name and passed as given to the class of the method chosen for that element, so each element’s parameters must be consistent with its chosen method and match that class’s constructor (e.g.initial_lossandconstant_lossforinitial_constant,max_deficitandconstant_lossfordeficit_constant; timedeltas for durations).- Parameters:
rainfall (Mapping[str, RainfallSeries]) – Incremental rainfall in inches for each basin, keyed by basin name.
loss_params (Mapping[str, Mapping[str, Any]] | None) – Loss method arguments for each basin.
transform_params (Mapping[str, Mapping[str, Any]] | None) – Transform method arguments for each basin.
baseflow_params (Mapping[str, Mapping[str, Any]] | None) – Baseflow method arguments for each basin.
reach_params (Mapping[str, Mapping[str, Any]] | None) – Routing method arguments for each reach.
reservoir_params (Mapping[str, Mapping[str, Any]] | None) – Routing method arguments for each reservoir.
- Returns:
Results keyed by element name: a
BasinOutput,ReachOutput,ReservoirOutput,JunctionOutputorSinkOutputdepending on the element type.- Raises:
TypeError – If a basin’s rainfall is not a
RainfallSeries.ValueError – If rainfall or parameters are missing for an element, a basin has upstream elements, or another element has none.
- Return type:
dict[str, BasinOutput | ReachOutput | ReservoirOutput | JunctionOutput | SinkOutput]
Read model, parameter and rainfall files for a Model.
- pyrunoff.utils.params.TIME_UNITS = {'hours', 'minutes', 'seconds'}¶
Units accepted for durations, converted to
pandas.Timedelta.
- pyrunoff.utils.params.load_model(path)[source]¶
Read a model file; see
Model.from_dict()for its form.- Parameters:
- Returns:
The model.
- Raises:
ValueError – If the model is invalid.
- Return type:
- pyrunoff.utils.params.load_rainfall(path, model, time_column='timestamp', date_format=None, end=None, end_offset=None)[source]¶
Read incremental rainfall for each of the model’s basins from a CSV file.
The file has a timestamp column and one column of rainfall depths (inches) per basin, named after the basin. Other columns are ignored.
- Parameters:
model (Model) – Model whose basins need rainfall.
time_column (str) – Name of the timestamp column.
date_format (str | None) –
strftimeformat of the timestamps, e.g."%m/%d/%Y %H:%M"; inferred whenNone.end (Timestamp | datetime | None) – Optional timestamp at which every series ends; see
TimeSeries.fix_end().end_offset (Timedelta | timedelta | None) – Optional end relative to the last timestamp in the file: positive adds zero rainfall (e.g. to let hydrographs recede), negative drops the last values; not combined with
end.
- Returns:
Rainfall keyed by basin name, ready for
Model.route().- Raises:
ValueError – If both
endandend_offsetare given, the end is before the first timestamp, the timestamp column is missing or does not matchdate_format, a basin has no column, or a column is invalid.- Return type:
- pyrunoff.utils.params.load_params(path, model)[source]¶
Read a parameter file for
model; seeparse_params().Curve file paths in the parameter file are relative to its directory.
- Parameters:
- Returns:
Parameters keyed by
Model.route()argument name.- Raises:
ValueError – If the parameters are invalid; see
parse_params().- Return type:
- pyrunoff.utils.params.parse_params(data, model, base_dir='.')[source]¶
Convert a parameter dictionary into the arguments of
Model.route().The dictionary groups elements by type, and each element’s parameters by process and method:
{ "basins": { "<basin>": { "basin_area": {"value": 465.4}, "<process>": { "<method>": {"<param>": {"value": 3384, "units": "seconds"}} } } }, "reaches": {"<reach>": {"routing": {"<method>": {...}}}}, "reservoirs": {"<reservoir>": {"routing": {"<method>": {...}}}} }
A parameter is one of:
{"value": v}: the numberv.{"value": v, "units": u}: apandas.Timedeltawhenuis inTIME_UNITS.{"path": p, "<x>_column_name": ..., "<y>_column_name": ...}: a curve read from the CSV filep; anElevationStoragefor elevation and storage columns, aStorageDischargefor storage and discharge columns.Any other dictionary: a dictionary of parameters, e.g. one curve per outlet.
The model chooses each element’s methods; a process may hold parameters for other methods too, so switching methods in the model needs no change here. Only the chosen method’s parameters are read, but every method’s parameter names are checked against its class.
Element-level parameters (
basin_area) are passed to every method of the element whose class takes them, unless the method’s own parameters set them.- Parameters:
- Returns:
Parameters keyed by
Model.route()argument name, so thatmodel.route(rainfall, **parse_params(data, model))runs the model.- Raises:
ValueError – If an element is not in the model or has another type; a section, element key, method or parameter name is unknown; a used parameter is malformed; a process has no parameters for the model’s method; or a parameter a method requires is missing.
- Return type:
Topological ordering of a network described by flow paths.
- class pyrunoff.utils.network.Network(paths, prevent_split=True)[source]¶
Bases:
objectRepresent a directed network described by ordered node paths.
- Parameters:
- Variables:
sorted_nodes – Nodes in topological execution order.
upstream_nodes – Direct upstream parents for each node.
- static toposort(paths, prevent_split=True)[source]¶
Sort nodes topologically and map each node to its direct upstream nodes.
- Parameters:
paths – Paths represented as ordered lists of node names.
prevent_split (bool) – If true, reject nodes with multiple downstream neighbors.
- Returns:
A tuple containing the ordered nodes and upstream-node mapping.
- Raises:
ValueError – If a node diverges while splitting is disabled or the paths contain a cycle.