API Reference#


Core Package#

Top-level package#

The top-level sparsehydro namespace re-exports only a small, stable core API. Everything else is accessed through its parent sub-package so that import paths mirror the package structure:

# Core (top-level)
from sparsehydro import (
    IModel, IUnitHydroComponent, ModelState,
    ScalarParameter, VectorParameter, FieldRecord,
    ModelRegistry, registry,
)

# Everything else via its parent sub-package
from sparsehydro.models import AMMModel, EnsembleModel, SeasonalityModel
from sparsehydro.models.rdii import RDIIModel, IAModel, RTKTriangle
from sparsehydro.models.unithydrograph import (
    GammaUH, NashUH, TriangleUH, SequentialFitter, SequentialFitSummary,
)
from sparsehydro.filters import apply_savgol_filter, compute_thresholds
from sparsehydro.events import detect_events, events_to_dataframe
from sparsehydro.calibration import (
    CalibrationProblem, CalibrationResult,
    MSE, RMSE, NashSutcliffe, KGE, PeakWeightedMSE,
    NSGAIISolver, ScipySolver, PlatypusSolver, ParticleSwarmSolver,
)
from sparsehydro.visualization import plot_timeseries, plot_calibration_dashboard

sparsehydro — interfaces and utilities for parsimonious hydrological models.

Only a small, stable core API is re-exported at the top level. Everything else is intentionally accessed through its parent sub-package so that the public surface stays small and import paths mirror the package structure:

  • Models — sparsehydro.models (plus sparsehydro.models.rdii and sparsehydro.models.unithydrograph)

  • Calibration — sparsehydro.calibration

  • Event detection — sparsehydro.events

  • Stormflow filters — sparsehydro.filters

  • Visualization — sparsehydro.visualization

Example:

from sparsehydro import IModel, ModelState, ScalarParameter
from sparsehydro.models.rdii import RDIIModel
from sparsehydro.calibration import CalibrationProblem, NashSutcliffe
class FieldRecord(name, units='', description='', calibratable=False)[source]

Bases: object

Metadata for a single column in a model’s predict() output DataFrame.

Register one FieldRecord per output column during initialize() so that calibration tooling, notebooks, and downstream consumers can discover what each column contains without inspecting the DataFrame itself.

Parameters:
  • name (str) – Column name exactly as it appears in the predict() output (e.g. "rdii_cfs", "total_cfs").

  • units (str) – Physical units string (e.g. "CFS", "mm", "in"). Use "" for dimensionless or non-physical columns such as "datetime".

  • description (str) – Human-readable explanation of what the field represents.

  • calibratable (bool) – True when this column can serve as the predicted column in a CalibrationProblem — i.e. it is a flow-rate or quantity directly comparable to an observed signal. Diagnostic columns (depth, excess, datetime) should be False.

Example:

from sparsehydro.parameters import FieldRecord

class MyModel(IModel):
    def initialize(self) -> None:
        self.register_output_field(FieldRecord(
            name="datetime",
            description="Simulation time step",
        ))
        self.register_output_field(FieldRecord(
            name="q_cfs",
            units="CFS",
            description="Predicted flow rate",
            calibratable=True,
        ))
        self._state = ModelState.INITIALIZED
calibratable: bool = False
description: str = ''
name: str
units: str = ''
class IModel[source]

Bases: ABC

Abstract interface for a parsimonious hydrological model.

Model name

Every concrete subclass must define a model_name class variable — a non-empty string that uniquely identifies the model type. This is enforced at class-definition time:

class MyModel(IModel):
    model_name = "my-model"
    ...

Attempting to define a concrete subclass without model_name raises TypeError immediately.

Lifecycle

Concrete subclasses must advance self._state as each method completes:

CREATED → INITIALIZED → VALIDATED → PREPARED → PREDICTED → FINALIZED

Parameter registry

Parameters are registered during initialize() via register_scalar_parameter() and register_vector_parameter(). Calibration tools retrieve them by name through get_scalar_parameter() and get_vector_parameter().

Minimal concrete implementation:

class MyModel(IModel):
    model_name = "my-model"

    def initialize(self) -> None:
        self.register_scalar_parameter(
            ScalarParameter("alpha", value=0.3,
                            lower_bound=0.0, upper_bound=1.0)
        )
        self._state = ModelState.INITIALIZED

    def validate(self) -> bool:
        ok = self.parameters_valid()
        if ok:
            self._state = ModelState.VALIDATED
        return ok

    def prepare(self, forcing) -> None:
        self._forcing = forcing
        self._state = ModelState.PREPARED

    def predict(self) -> pd.Series:
        alpha = self.get_scalar_parameter("alpha").value
        self._state = ModelState.PREDICTED
        return pd.Series(self._forcing * alpha)

    def finalize(self) -> None:
        self._state = ModelState.FINALIZED
apply_flat_parameter(name, value)[source]

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)[source]

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

abstractmethod finalize()[source]

Release resources and wrap up computation.

Returns:

Nothing.

Return type:

None

get_output_field(name)[source]

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)[source]

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)[source]

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()[source]

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

abstractmethod initialize(*args, **kwargs)[source]

Set up model structure and register parameters.

Called once before validate(). Implementations register every ScalarParameter and VectorParameter here and advance the state to INITIALIZED.

Parameters:
  • args (Any) – Optional positional configuration defined by the subclass.

  • kwargs (Any) – Optional keyword configuration defined by the subclass.

Returns:

Nothing.

Return type:

None

is_created()[source]

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()[source]

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()[source]

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()[source]

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()[source]

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()[source]

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()[source]

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()[source]

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

abstractmethod predict(*args, **kwargs)[source]

Execute the model and return its outputs.

Parameters:
  • args (Any) – Positional run-time arguments.

  • kwargs (Any) – Keyword run-time arguments.

Returns:

Model outputs, typically with a predicted-flow column.

Return type:

pandas.DataFrame | pandas.Series

abstractmethod prepare(*args, **kwargs)[source]

Load and pre-process forcing/input data.

Parameters:
  • args (Any) – Positional forcing/input data (e.g. a DataFrame of rainfall).

  • kwargs (Any) – Keyword forcing/input options.

Returns:

Nothing.

Return type:

None

read_flat_parameter(name)[source]

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)[source]

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)[source]

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)[source]

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)[source]

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)[source]

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)[source]

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

abstractmethod validate()[source]

Validate the model configuration and parameter bounds.

Implementations should advance the state to VALIDATED when returning True.

Returns:

True if the model is valid and ready for prepare(); False otherwise.

Return type:

bool

property calibratable_output_names: list[str]

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str]

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

class ITorchModel[source]

Bases: IModel, Module

Abstract interface for differentiable parsimonious models.

Inherits from both IModel and torch.nn.Module. Subclasses must implement all five IModel lifecycle methods and forward() — the differentiable computation graph.

The default predict() implementation calls forward() and advances model state to PREDICTED. Override predict() if additional pre/post-processing around forward() is required.

Gradient-tracked parameters should be declared as torch.nn.Parameter attributes so that PyTorch optimisers can discover them via Module.parameters(). The sparsehydro register_scalar_parameter() / register_vector_parameter() registry holds metadata (bounds, units, description) for the same parameters to allow calibration algorithms to apply constraints.

Example:

import torch
import torch.nn as nn
from sparsehydro import ModelState, ScalarParameter
from sparsehydro.models import ITorchModel

class LinearReservoir(ITorchModel):
    def initialize(self) -> None:
        self.k = nn.Parameter(torch.tensor(0.5))
        self.register_scalar_parameter(
            ScalarParameter("k", value=0.5,
                            lower_bound=0.0, upper_bound=1.0)
        )
        self._state = ModelState.INITIALIZED

    def validate(self) -> bool:
        ok = self.parameters_valid()
        if ok:
            self._state = ModelState.VALIDATED
        return ok

    def prepare(self, forcing: torch.Tensor) -> None:
        self._forcing = forcing
        self._state = ModelState.PREPARED

    def forward(self, forcing: torch.Tensor) -> torch.Tensor:
        return self.k * forcing

    def finalize(self) -> None:
        self._state = ModelState.FINALIZED
add_module(name, module)

Add a child module to the current module.

The module can be accessed as an attribute using the given name.

Parameters:
  • name (str) – name of the child module. The child module can be accessed from this module using the given name

  • module (Module) – child module to be added to the module.

apply(fn)

Apply fn recursively to every submodule (as returned by .children()) as well as self.

Typical use includes initializing the parameters of a model (see also torch.nn.init).

Parameters:

fn (Module -> None) – function to be applied to each submodule

Returns:

self

Return type:

Module

Example:

>>> @torch.no_grad()
>>> def init_weights(m):
>>>     print(m)
>>>     if type(m) is nn.Linear:
>>>         m.weight.fill_(1.0)
>>>         print(m.weight)
>>> net = nn.Sequential(nn.Linear(2, 2), nn.Linear(2, 2))
>>> net.apply(init_weights)
Linear(in_features=2, out_features=2, bias=True)
Parameter containing:
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
Linear(in_features=2, out_features=2, bias=True)
Parameter containing:
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
Sequential(
  (0): Linear(in_features=2, out_features=2, bias=True)
  (1): Linear(in_features=2, out_features=2, bias=True)
)
apply_flat_parameter(name, value)

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

bfloat16()

Casts all floating point parameters and buffers to bfloat16 datatype.

Note

This method modifies the module in-place.

Returns:

self

Return type:

Module

buffers(recurse=True)

Return an iterator over module buffers.

Parameters:

recurse (bool) – if True, then yields buffers of this module and all submodules. Otherwise, yields only buffers that are direct members of this module.

Yields:

torch.Tensor – module buffer

Example:

>>> # xdoctest: +SKIP("undefined vars")
>>> for buf in model.buffers():
>>>     print(type(buf), buf.size())
<class 'torch.Tensor'> (20L,)
<class 'torch.Tensor'> (20L, 1L, 5L, 5L)
children()

Return an iterator over immediate children modules.

Yields:

Module – a child module

compile(*args, **kwargs)

Compile this Module’s forward using torch.compile().

This Module’s __call__ method is compiled and all arguments are passed as-is to torch.compile().

See torch.compile() for details on the arguments for this function.

cpu()

Move all model parameters and buffers to the CPU.

Note

This method modifies the module in-place.

Returns:

self

Return type:

Module

cuda(device=None)

Move all model parameters and buffers to the GPU.

This also makes associated parameters and buffers different objects. So it should be called before constructing the optimizer if the module will live on GPU while being optimized.

Note

This method modifies the module in-place.

Parameters:

device (int, optional) – if specified, all parameters will be copied to that device

Returns:

self

Return type:

Module

double()

Casts all floating point parameters and buffers to double datatype.

Note

This method modifies the module in-place.

Returns:

self

Return type:

Module

eval()

Set the module in evaluation mode.

This has an effect only on certain modules. See the documentation of particular modules for details of their behaviors in training/evaluation mode, i.e. whether they are affected, e.g. Dropout, BatchNorm, etc.

This is equivalent with self.train(False).

See Locally disabling gradient computation for a comparison between .eval() and several similar mechanisms that may be confused with it.

Returns:

self

Return type:

Module

extra_repr()

Return the extra representation of the module.

To print customized extra information, you should re-implement this method in your own modules. Both single-line and multi-line strings are acceptable.

abstractmethod finalize()

Release resources and wrap up computation.

Returns:

Nothing.

Return type:

None

float()

Casts all floating point parameters and buffers to float datatype.

Note

This method modifies the module in-place.

Returns:

self

Return type:

Module

abstractmethod forward(*args, **kwargs)[source]

Differentiable forward pass producing the model output.

Subclasses implement the model computation using torch operations so that gradients flow back to the registered torch.nn.Parameter attributes.

Parameters:
  • args (Any) – Positional forcing inputs (e.g. a rainfall tensor).

  • kwargs (Any) – Keyword forcing inputs.

Returns:

The model output tensor with gradient tracking enabled.

Return type:

torch.Tensor

get_buffer(target)

Return the buffer given by target if it exists, otherwise throw an error.

See the docstring for get_submodule for a more detailed explanation of this method’s functionality as well as how to correctly specify target.

Parameters:

target (str) – The fully-qualified string name of the buffer to look for. (See get_submodule for how to specify a fully-qualified string.)

Returns:

The buffer referenced by target

Return type:

torch.Tensor

Raises:

AttributeError – If the target string references an invalid path or resolves to something that is not a buffer

get_extra_state()

Return any extra state to include in the module’s state_dict.

Implement this and a corresponding set_extra_state() for your module if you need to store extra state. This function is called when building the module’s state_dict().

Note that extra state should be picklable to ensure working serialization of the state_dict. We only provide backwards compatibility guarantees for serializing Tensors; other objects may break backwards compatibility if their serialized pickled form changes.

Returns:

Any extra state to store in the module’s state_dict

Return type:

object

get_output_field(name)

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_parameter(target)

Return the parameter given by target if it exists, otherwise throw an error.

See the docstring for get_submodule for a more detailed explanation of this method’s functionality as well as how to correctly specify target.

Parameters:

target (str) – The fully-qualified string name of the Parameter to look for. (See get_submodule for how to specify a fully-qualified string.)

Returns:

The Parameter referenced by target

Return type:

torch.nn.Parameter

Raises:

AttributeError – If the target string references an invalid path or resolves to something that is not an nn.Parameter

get_scalar_parameter(name)

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_submodule(target)

Return the submodule given by target if it exists, otherwise throw an error.

For example, let’s say you have an nn.Module A that looks like this:

A(
    (net_b): Module(
        (net_c): Module(
            (conv): Conv2d(16, 33, kernel_size=(3, 3), stride=(2, 2))
        )
        (linear): Linear(in_features=100, out_features=200, bias=True)
    )
)

(The diagram shows an nn.Module A. A which has a nested submodule net_b, which itself has two submodules net_c and linear. net_c then has a submodule conv.)

To check whether or not we have the linear submodule, we would call get_submodule("net_b.linear"). To check whether we have the conv submodule, we would call get_submodule("net_b.net_c.conv").

The runtime of get_submodule is bounded by the degree of module nesting in target. A query against named_modules achieves the same result, but it is O(N) in the number of transitive modules. So, for a simple check to see if some submodule exists, get_submodule should always be used.

Parameters:

target (str) – The fully-qualified string name of the submodule to look for. (See above example for how to specify a fully-qualified string.)

Returns:

The submodule referenced by target

Return type:

torch.nn.Module

Raises:

AttributeError – If at any point along the path resulting from the target string the (sub)path resolves to a non-existent attribute name or an object that is not an instance of nn.Module.

get_vector_parameter(name)

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

half()

Casts all floating point parameters and buffers to half datatype.

Note

This method modifies the module in-place.

Returns:

self

Return type:

Module

inequality_constraints()

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

abstractmethod initialize(*args, **kwargs)

Set up model structure and register parameters.

Called once before validate(). Implementations register every ScalarParameter and VectorParameter here and advance the state to INITIALIZED.

Parameters:
  • args (Any) – Optional positional configuration defined by the subclass.

  • kwargs (Any) – Optional keyword configuration defined by the subclass.

Returns:

Nothing.

Return type:

None

ipu(device=None)

Move all model parameters and buffers to the IPU.

This also makes associated parameters and buffers different objects. So it should be called before constructing the optimizer if the module will live on IPU while being optimized.

Note

This method modifies the module in-place.

Parameters:

device (int, optional) – if specified, all parameters will be copied to that device

Returns:

self

Return type:

Module

is_created()

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

load_state_dict(state_dict, strict=True, assign=False)

Copy parameters and buffers from state_dict into this module and its descendants.

If strict is True, then the keys of state_dict must exactly match the keys returned by this module’s state_dict() function.

Warning

If assign is True the optimizer must be created after the call to load_state_dict unless get_swap_module_params_on_conversion() is True.

Parameters:
  • state_dict (dict) – a dict containing parameters and persistent buffers.

  • strict (bool, optional) – whether to strictly enforce that the keys in state_dict match the keys returned by this module’s state_dict() function. Default: True

  • assign (bool, optional) – When set to False, the properties of the tensors in the current module are preserved whereas setting it to True preserves properties of the Tensors in the state dict. The only exception is the requires_grad field of Parameter for which the value from the module is preserved. Default: False

Returns:

  • missing_keys is a list of str containing any keys that are expected

    by this module but missing from the provided state_dict.

  • unexpected_keys is a list of str containing the keys that are not

    expected by this module but present in the provided state_dict.

Return type:

NamedTuple with missing_keys and unexpected_keys fields

Note

If a parameter or buffer is registered as None and its corresponding key exists in state_dict, load_state_dict() will raise a RuntimeError.

modules(remove_duplicate=True)

Return an iterator over all modules in the network.

Parameters:

remove_duplicate (bool) – whether to remove the duplicated module instances in the result or not.

Yields:

Module – a module in the network

Note

Duplicate modules are returned only once by default. In the following example, l will be returned only once.

Example:

>>> l = nn.Linear(2, 2)
>>> net = nn.Sequential(l, l)
>>> for idx, m in enumerate(net.modules()):
...     print(idx, '->', m)

0 -> Sequential(
  (0): Linear(in_features=2, out_features=2, bias=True)
  (1): Linear(in_features=2, out_features=2, bias=True)
)
1 -> Linear(in_features=2, out_features=2, bias=True)
mtia(device=None)

Move all model parameters and buffers to the MTIA.

This also makes associated parameters and buffers different objects. So it should be called before constructing the optimizer if the module will live on MTIA while being optimized.

Note

This method modifies the module in-place.

Parameters:

device (int, optional) – if specified, all parameters will be copied to that device

Returns:

self

Return type:

Module

named_buffers(prefix='', recurse=True, remove_duplicate=True)

Return an iterator over module buffers, yielding both the name of the buffer as well as the buffer itself.

Parameters:
  • prefix (str) – prefix to prepend to all buffer names.

  • recurse (bool, optional) – if True, then yields buffers of this module and all submodules. Otherwise, yields only buffers that are direct members of this module. Defaults to True.

  • remove_duplicate (bool, optional) – whether to remove the duplicated buffers in the result. Defaults to True.

Yields:

(str, torch.Tensor) – Tuple containing the name and buffer

Example:

>>> # xdoctest: +SKIP("undefined vars")
>>> for name, buf in self.named_buffers():
>>>     if name in ['running_var']:
>>>         print(buf.size())
named_children()

Return an iterator over immediate children modules, yielding both the name of the module as well as the module itself.

Yields:

(str, Module) – Tuple containing a name and child module

Example:

>>> # xdoctest: +SKIP("undefined vars")
>>> for name, module in model.named_children():
>>>     if name in ['conv4', 'conv5']:
>>>         print(module)
named_modules(memo=None, prefix='', remove_duplicate=True)

Return an iterator over all modules in the network, yielding both the name of the module as well as the module itself.

Parameters:
  • memo (set[Module] | None) – a memo to store the set of modules already added to the result

  • prefix (str) – a prefix that will be added to the name of the module

  • remove_duplicate (bool) – whether to remove the duplicated module instances in the result or not

Yields:

(str, Module) – Tuple of name and module

Note

Duplicate modules are returned only once. In the following example, l will be returned only once.

Example:

>>> l = nn.Linear(2, 2)
>>> net = nn.Sequential(l, l)
>>> for idx, m in enumerate(net.named_modules()):
...     print(idx, '->', m)

0 -> ('', Sequential(
  (0): Linear(in_features=2, out_features=2, bias=True)
  (1): Linear(in_features=2, out_features=2, bias=True)
))
1 -> ('0', Linear(in_features=2, out_features=2, bias=True))
named_parameters(prefix='', recurse=True, remove_duplicate=True)

Return an iterator over module parameters, yielding both the name of the parameter as well as the parameter itself.

Parameters:
  • prefix (str) – prefix to prepend to all parameter names.

  • recurse (bool) – if True, then yields parameters of this module and all submodules. Otherwise, yields only parameters that are direct members of this module.

  • remove_duplicate (bool, optional) – whether to remove the duplicated parameters in the result. Defaults to True.

Yields:

(str, Parameter) – Tuple containing the name and parameter

Example:

>>> # xdoctest: +SKIP("undefined vars")
>>> for name, param in self.named_parameters():
>>>     if name in ['bias']:
>>>         print(param.size())
output_field_metadata()

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters(recurse=True)

Return an iterator over module parameters.

This is typically passed to an optimizer.

Parameters:

recurse (bool) – if True, then yields parameters of this module and all submodules. Otherwise, yields only parameters that are direct members of this module.

Yields:

Parameter – module parameter

Example:

>>> # xdoctest: +SKIP("undefined vars")
>>> for param in model.parameters():
>>>     print(type(param), param.size())
<class 'torch.Tensor'> (20L,)
<class 'torch.Tensor'> (20L, 1L, 5L, 5L)
parameters_valid()

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict(*args, **kwargs)[source]

Run the differentiable forward pass and advance model state.

Delegates to forward() and sets the model state to PREDICTED.

Parameters:
  • args (Any) – Positional forcing inputs forwarded to forward().

  • kwargs (Any) – Keyword forcing inputs forwarded to forward().

Returns:

The output tensor returned by forward().

Return type:

torch.Tensor

abstractmethod prepare(*args, **kwargs)

Load and pre-process forcing/input data.

Parameters:
  • args (Any) – Positional forcing/input data (e.g. a DataFrame of rainfall).

  • kwargs (Any) – Keyword forcing/input options.

Returns:

Nothing.

Return type:

None

read_flat_parameter(name)

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_backward_hook(hook)

Register a backward hook on the module.

This function is deprecated in favor of register_full_backward_hook() and the behavior of this function will change in future versions.

Returns:

a handle that can be used to remove the added hook by calling handle.remove()

Return type:

torch.utils.hooks.RemovableHandle

register_buffer(name, tensor, persistent=True)

Add a buffer to the module.

This is typically used to register a buffer that should not be considered a model parameter. For example, BatchNorm’s running_mean is not a parameter, but is part of the module’s state. Buffers, by default, are persistent and will be saved alongside parameters. This behavior can be changed by setting persistent to False. The only difference between a persistent buffer and a non-persistent buffer is that the latter will not be a part of this module’s state_dict.

Buffers can be accessed as attributes using given names.

Parameters:
  • name (str) – name of the buffer. The buffer can be accessed from this module using the given name

  • tensor (Tensor or None) – buffer to be registered. If None, then operations that run on buffers, such as cuda, are ignored. If None, the buffer is not included in the module’s state_dict.

  • persistent (bool) – whether the buffer is part of this module’s state_dict.

Example:

>>> # xdoctest: +SKIP("undefined vars")
>>> self.register_buffer('running_mean', torch.zeros(num_features))
register_forward_hook(hook, *, prepend=False, with_kwargs=False, always_call=False)

Register a forward hook on the module.

The hook will be called every time after forward() has computed an output.

If with_kwargs is False or not specified, the input contains only the positional arguments given to the module. Keyword arguments won’t be passed to the hooks and only to the forward. The hook can modify the output. It can modify the input inplace but it will not have effect on forward since this is called after forward() is called. The hook should have the following signature:

hook(module, args, output) -> None or modified output

If with_kwargs is True, the forward hook will be passed the kwargs given to the forward function and be expected to return the output possibly modified. The hook should have the following signature:

hook(module, args, kwargs, output) -> None or modified output
Parameters:
  • hook (Callable) – The user defined hook to be registered.

  • prepend (bool) – If True, the provided hook will be fired before all existing forward hooks on this torch.nn.Module. Otherwise, the provided hook will be fired after all existing forward hooks on this torch.nn.Module. Note that global forward hooks registered with register_module_forward_hook() will fire before all hooks registered by this method. Default: False

  • with_kwargs (bool) – If True, the hook will be passed the kwargs given to the forward function. Default: False

  • always_call (bool) – If True the hook will be run regardless of whether an exception is raised while calling the Module. Default: False

Returns:

a handle that can be used to remove the added hook by calling handle.remove()

Return type:

torch.utils.hooks.RemovableHandle

register_forward_pre_hook(hook, *, prepend=False, with_kwargs=False)

Register a forward pre-hook on the module.

The hook will be called every time before forward() is invoked.

If with_kwargs is false or not specified, the input contains only the positional arguments given to the module. Keyword arguments won’t be passed to the hooks and only to the forward. The hook can modify the input. User can either return a tuple or a single modified value in the hook. We will wrap the value into a tuple if a single value is returned (unless that value is already a tuple). The hook should have the following signature:

hook(module, args) -> None or modified input

If with_kwargs is true, the forward pre-hook will be passed the kwargs given to the forward function. And if the hook modifies the input, both the args and kwargs should be returned. The hook should have the following signature:

hook(module, args, kwargs) -> None or a tuple of modified input and kwargs
Parameters:
  • hook (Callable) – The user defined hook to be registered.

  • prepend (bool) – If true, the provided hook will be fired before all existing forward_pre hooks on this torch.nn.Module. Otherwise, the provided hook will be fired after all existing forward_pre hooks on this torch.nn.Module. Note that global forward_pre hooks registered with register_module_forward_pre_hook() will fire before all hooks registered by this method. Default: False

  • with_kwargs (bool) – If true, the hook will be passed the kwargs given to the forward function. Default: False

Returns:

a handle that can be used to remove the added hook by calling handle.remove()

Return type:

torch.utils.hooks.RemovableHandle

register_full_backward_hook(hook, prepend=False)

Register a backward hook on the module.

The hook will be called every time the gradients with respect to a module are computed, and its firing rules are as follows:

  1. Ordinarily, the hook fires when the gradients are computed with respect to the module inputs.

  2. If none of the module inputs require gradients, the hook will fire when the gradients are computed with respect to module outputs.

  3. If none of the module outputs require gradients, then the hooks will not fire.

The hook should have the following signature:

hook(module, grad_input, grad_output) -> tuple(Tensor) or None

The grad_input and grad_output are tuples that contain the gradients with respect to the inputs and outputs respectively. The hook should not modify its arguments, but it can optionally return a new gradient with respect to the input that will be used in place of grad_input in subsequent computations. grad_input will only correspond to the inputs given as positional arguments and all kwarg arguments are ignored. Entries in grad_input and grad_output will be None for all non-Tensor arguments.

For technical reasons, when this hook is applied to a Module, its forward function will receive a view of each Tensor passed to the Module. Similarly the caller will receive a view of each Tensor returned by the Module’s forward function.

Warning

Modifying inputs or outputs inplace is not allowed when using backward hooks and will raise an error.

Parameters:
  • hook (Callable) – The user-defined hook to be registered.

  • prepend (bool) – If true, the provided hook will be fired before all existing backward hooks on this torch.nn.Module. Otherwise, the provided hook will be fired after all existing backward hooks on this torch.nn.Module. Note that global backward hooks registered with register_module_full_backward_hook() will fire before all hooks registered by this method.

Returns:

a handle that can be used to remove the added hook by calling handle.remove()

Return type:

torch.utils.hooks.RemovableHandle

register_full_backward_pre_hook(hook, prepend=False)

Register a backward pre-hook on the module.

The hook will be called every time the gradients for the module are computed. The hook should have the following signature:

hook(module, grad_output) -> tuple[Tensor, ...], Tensor or None

The grad_output is a tuple. The hook should not modify its arguments, but it can optionally return a new gradient with respect to the output that will be used in place of grad_output in subsequent computations. Entries in grad_output will be None for all non-Tensor arguments.

For technical reasons, when this hook is applied to a Module, its forward function will receive a view of each Tensor passed to the Module. Similarly the caller will receive a view of each Tensor returned by the Module’s forward function.

Warning

Modifying inputs inplace is not allowed when using backward hooks and will raise an error.

Parameters:
  • hook (Callable) – The user-defined hook to be registered.

  • prepend (bool) – If true, the provided hook will be fired before all existing backward_pre hooks on this torch.nn.Module. Otherwise, the provided hook will be fired after all existing backward_pre hooks on this torch.nn.Module. Note that global backward_pre hooks registered with register_module_full_backward_pre_hook() will fire before all hooks registered by this method.

Returns:

a handle that can be used to remove the added hook by calling handle.remove()

Return type:

torch.utils.hooks.RemovableHandle

register_inequality_constraint(record)

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_load_state_dict_post_hook(hook)

Register a post-hook to be run after module’s load_state_dict() is called.

It should have the following signature::

hook(module, incompatible_keys) -> None

The module argument is the current module that this hook is registered on, and the incompatible_keys argument is a NamedTuple consisting of attributes missing_keys and unexpected_keys. missing_keys is a list of str containing the missing keys and unexpected_keys is a list of str containing the unexpected keys.

The given incompatible_keys can be modified inplace if needed.

Note that the checks performed when calling load_state_dict() with strict=True are affected by modifications the hook makes to missing_keys or unexpected_keys, as expected. Additions to either set of keys will result in an error being thrown when strict=True, and clearing out both missing and unexpected keys will avoid an error.

Returns:

a handle that can be used to remove the added hook by calling handle.remove()

Return type:

torch.utils.hooks.RemovableHandle

register_load_state_dict_pre_hook(hook)

Register a pre-hook to be run before module’s load_state_dict() is called.

It should have the following signature::

hook(module, state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs) -> None # noqa: B950

Parameters:

hook (Callable) – Callable hook that will be invoked before loading the state dict.

register_module(name, module)

Alias for add_module().

register_output_field(field)

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_parameter(name, param)

Add a parameter to the module.

The parameter can be accessed as an attribute using given name.

Parameters:
  • name (str) – name of the parameter. The parameter can be accessed from this module using the given name

  • param (Parameter or None) – parameter to be added to the module. If None, then operations that run on parameters, such as cuda, are ignored. If None, the parameter is not included in the module’s state_dict.

register_scalar_parameter(param)

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_state_dict_post_hook(hook)

Register a post-hook for the state_dict() method.

It should have the following signature::

hook(module, state_dict, prefix, local_metadata) -> None

The registered hooks can modify the state_dict inplace.

register_state_dict_pre_hook(hook)

Register a pre-hook for the state_dict() method.

It should have the following signature::

hook(module, prefix, keep_vars) -> None

The registered hooks can be used to perform pre-processing before the state_dict call is made.

register_vector_parameter(param)

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

requires_grad_(requires_grad=True)

Change if autograd should record operations on parameters in this module.

This method sets the parameters’ requires_grad attributes in-place.

This method is helpful for freezing part of the module for finetuning or training parts of a model individually (e.g., GAN training).

See Locally disabling gradient computation for a comparison between .requires_grad_() and several similar mechanisms that may be confused with it.

Parameters:

requires_grad (bool) – whether autograd should record operations on parameters in this module. Default: True.

Returns:

self

Return type:

Module

set_extra_state(state)

Set extra state contained in the loaded state_dict.

This function is called from load_state_dict() to handle any extra state found within the state_dict. Implement this function and a corresponding get_extra_state() for your module if you need to store extra state within its state_dict.

Parameters:

state (dict) – Extra state from the state_dict

set_submodule(target, module, strict=False)

Set the submodule given by target if it exists, otherwise throw an error.

Note

If strict is set to False (default), the method will replace an existing submodule or create a new submodule if the parent module exists. If strict is set to True, the method will only attempt to replace an existing submodule and throw an error if the submodule does not exist.

For example, let’s say you have an nn.Module A that looks like this:

A(
    (net_b): Module(
        (net_c): Module(
            (conv): Conv2d(3, 3, 3)
        )
        (linear): Linear(3, 3)
    )
)

(The diagram shows an nn.Module A. A has a nested submodule net_b, which itself has two submodules net_c and linear. net_c then has a submodule conv.)

To override the Conv2d with a new submodule Linear, you could call set_submodule("net_b.net_c.conv", nn.Linear(1, 1)) where strict could be True or False

To add a new submodule Conv2d to the existing net_b module, you would call set_submodule("net_b.conv", nn.Conv2d(1, 1, 1)).

In the above if you set strict=True and call set_submodule("net_b.conv", nn.Conv2d(1, 1, 1), strict=True), an AttributeError will be raised because net_b does not have a submodule named conv.

Parameters:
  • target (str) – The fully-qualified string name of the submodule to look for. (See above example for how to specify a fully-qualified string.)

  • module (Module) – The module to set the submodule to.

  • strict (bool) – If False, the method will replace an existing submodule or create a new submodule if the parent module exists. If True, the method will only attempt to replace an existing submodule and throw an error if the submodule doesn’t already exist.

Raises:
  • ValueError – If the target string is empty or if module is not an instance of nn.Module.

  • AttributeError – If at any point along the path resulting from the target string the (sub)path resolves to a non-existent attribute name or an object that is not an instance of nn.Module.

share_memory()

See torch.Tensor.share_memory_().

state_dict(*args, destination=None, prefix='', keep_vars=False)

Return a dictionary containing references to the whole state of the module.

Both parameters and persistent buffers (e.g. running averages) are included. Keys are corresponding parameter and buffer names. Parameters and buffers set to None are not included.

Note

The returned object is a shallow copy. It contains references to the module’s parameters and buffers.

Warning

Currently state_dict() also accepts positional arguments for destination, prefix and keep_vars in order. However, this is being deprecated and keyword arguments will be enforced in future releases.

Warning

Please avoid the use of argument destination as it is not designed for end-users.

Parameters:
  • destination (dict, optional) – If provided, the state of module will be updated into the dict and the same object is returned. Otherwise, an OrderedDict will be created and returned. Default: None.

  • prefix (str, optional) – a prefix added to parameter and buffer names to compose the keys in state_dict. Default: ''.

  • keep_vars (bool, optional) – by default the Tensor s returned in the state dict are detached from autograd. If it’s set to True, detaching will not be performed. Default: False.

Returns:

a dictionary containing a whole state of the module

Return type:

dict

Example:

>>> # xdoctest: +SKIP("undefined vars")
>>> module.state_dict().keys()
['bias', 'weight']
to(*args, **kwargs)

Move and/or cast the parameters and buffers.

This can be called as

to(device=None, dtype=None, non_blocking=False)
to(dtype, non_blocking=False)
to(tensor, non_blocking=False)
to(memory_format=torch.channels_last)

Its signature is similar to torch.Tensor.to(), but only accepts floating point or complex dtypes. In addition, this method will only cast the floating point or complex parameters and buffers to dtype (if given). The integral parameters and buffers will be moved device, if that is given, but with dtypes unchanged. When non_blocking is set, it tries to convert/move asynchronously with respect to the host if possible, e.g., moving CPU Tensors with pinned memory to CUDA devices.

See below for examples.

Note

This method modifies the module in-place.

Parameters:
  • device (torch.device) – the desired device of the parameters and buffers in this module

  • dtype (torch.dtype) – the desired floating point or complex dtype of the parameters and buffers in this module

  • tensor (torch.Tensor) – Tensor whose dtype and device are the desired dtype and device for all parameters and buffers in this module

  • memory_format (torch.memory_format) – the desired memory format for 4D parameters and buffers in this module (keyword only argument)

Returns:

self

Return type:

Module

Examples:

>>> # xdoctest: +IGNORE_WANT("non-deterministic")
>>> linear = nn.Linear(2, 2)
>>> linear.weight
Parameter containing:
tensor([[ 0.1913, -0.3420],
        [-0.5113, -0.2325]])
>>> linear.to(torch.double)
Linear(in_features=2, out_features=2, bias=True)
>>> linear.weight
Parameter containing:
tensor([[ 0.1913, -0.3420],
        [-0.5113, -0.2325]], dtype=torch.float64)
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_CUDA1)
>>> gpu1 = torch.device("cuda:1")
>>> linear.to(gpu1, dtype=torch.half, non_blocking=True)
Linear(in_features=2, out_features=2, bias=True)
>>> linear.weight
Parameter containing:
tensor([[ 0.1914, -0.3420],
        [-0.5112, -0.2324]], dtype=torch.float16, device='cuda:1')
>>> cpu = torch.device("cpu")
>>> linear.to(cpu)
Linear(in_features=2, out_features=2, bias=True)
>>> linear.weight
Parameter containing:
tensor([[ 0.1914, -0.3420],
        [-0.5112, -0.2324]], dtype=torch.float16)

>>> linear = nn.Linear(2, 2, bias=None).to(torch.cdouble)
>>> linear.weight
Parameter containing:
tensor([[ 0.3741+0.j,  0.2382+0.j],
        [ 0.5593+0.j, -0.4443+0.j]], dtype=torch.complex128)
>>> linear(torch.ones(3, 2, dtype=torch.cdouble))
tensor([[0.6122+0.j, 0.1150+0.j],
        [0.6122+0.j, 0.1150+0.j],
        [0.6122+0.j, 0.1150+0.j]], dtype=torch.complex128)
to_empty(*, device, recurse=True)

Move the parameters and buffers to the specified device without copying storage.

Parameters:
  • device (torch.device) – The desired device of the parameters and buffers in this module.

  • recurse (bool) – Whether parameters and buffers of submodules should be recursively moved to the specified device.

Returns:

self

Return type:

Module

train(mode=True)

Set the module in training mode.

This has an effect only on certain modules. See the documentation of particular modules for details of their behaviors in training/evaluation mode, i.e., whether they are affected, e.g. Dropout, BatchNorm, etc.

Parameters:

mode (bool) – whether to set training mode (True) or evaluation mode (False). Default: True.

Returns:

self

Return type:

Module

type(dst_type)

Casts all parameters and buffers to dst_type.

Note

This method modifies the module in-place.

Parameters:

dst_type (type or string) – the desired type

Returns:

self

Return type:

Module

abstractmethod validate()

Validate the model configuration and parameter bounds.

Implementations should advance the state to VALIDATED when returning True.

Returns:

True if the model is valid and ready for prepare(); False otherwise.

Return type:

bool

xpu(device=None)

Move all model parameters and buffers to the XPU.

This also makes associated parameters and buffers different objects. So it should be called before constructing optimizer if the module will live on XPU while being optimized.

Note

This method modifies the module in-place.

Parameters:

device (int, optional) – if specified, all parameters will be copied to that device

Returns:

self

Return type:

Module

zero_grad(set_to_none=True)

Reset gradients of all model parameters.

See similar function under torch.optim.Optimizer for more context.

Parameters:

set_to_none (bool) – instead of setting to zero, set the grads to None. See torch.optim.Optimizer.zero_grad() for details.

T_destination = ~T_destination
property calibratable_output_names: list[str]

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

call_super_init: bool = False
dump_patches: bool = False
property inequality_constraint_descriptions: list[str]

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str]

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

training: bool
property vector_parameter_names: list[str]

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

class IUnitHydroComponent[source]

Bases: IModel, ABC

Abstract base for unit hydrograph components used within RDIIModel.

Extends IModel with a single additional method, get_kernel(), that returns a normalized ordinate array suitable for convolution with a rainfall-excess series.

Amplitude parameter

Many UH models carry a parameter that scales the total response volume (R for RTK triangles, A for Nash/Gamma UH shapes). When a component is embedded in RDIIModel, that composite manages the fraction R_i separately and re-registers only the shape parameters. Declare the name of the amplitude/scaling parameter as a class variable so the composite can exclude it:

class MyUH(IUnitHydroComponent):
    _amplitude_param_name = "A"   # or "R", or None if none
apply_flat_parameter(name, value)

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

abstractmethod finalize()

Release resources and wrap up computation.

Returns:

Nothing.

Return type:

None

abstractmethod get_kernel(dt_hours, n_steps=None)[source]

Return normalized unit hydrograph ordinates.

The returned array satisfies:

np.sum(ordinates) * dt_hours ≈ 1.0
Parameters:
  • dt_hours (float) – Time-step size [hr] of the forcing data.

  • n_steps (int | None) – If provided, trim or zero-pad the result to this length.

Returns:

1-D ordinate array [1/hr].

Return type:

numpy.ndarray

get_output_field(name)

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

abstractmethod initialize(*args, **kwargs)

Set up model structure and register parameters.

Called once before validate(). Implementations register every ScalarParameter and VectorParameter here and advance the state to INITIALIZED.

Parameters:
  • args (Any) – Optional positional configuration defined by the subclass.

  • kwargs (Any) – Optional keyword configuration defined by the subclass.

Returns:

Nothing.

Return type:

None

is_created()

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

abstractmethod predict(*args, **kwargs)

Execute the model and return its outputs.

Parameters:
  • args (Any) – Positional run-time arguments.

  • kwargs (Any) – Keyword run-time arguments.

Returns:

Model outputs, typically with a predicted-flow column.

Return type:

pandas.DataFrame | pandas.Series

abstractmethod prepare(*args, **kwargs)

Load and pre-process forcing/input data.

Parameters:
  • args (Any) – Positional forcing/input data (e.g. a DataFrame of rainfall).

  • kwargs (Any) – Keyword forcing/input options.

Returns:

Nothing.

Return type:

None

read_flat_parameter(name)

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

abstractmethod validate()

Validate the model configuration and parameter bounds.

Implementations should advance the state to VALIDATED when returning True.

Returns:

True if the model is valid and ready for prepare(); False otherwise.

Return type:

bool

property calibratable_output_names: list[str]

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str]

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

class ModelRegistry[source]

Bases: object

Central registry for tracking compatible parsimonious model classes.

A model class is considered compatible if it:

  1. Is a concrete (non-abstract) subclass of IModel.

  2. Defines a non-empty model_name class variable.

The registry can be used directly as a class decorator:

registry = ModelRegistry()

@registry.register
class LinearReservoir(IModel):
    model_name = "linear-reservoir"
    ...

model = registry.create("linear-reservoir")
create(name, *args, **kwargs)[source]

Instantiate the model class registered under name.

All positional and keyword arguments are forwarded to the model constructor.

Parameters:

name (str) – The model_name of the model to instantiate.

Returns:

A new instance of the registered model.

Return type:

IModel

Raises:

KeyError – If no model with name is registered.

get(name)[source]

Return the model class registered under name.

Parameters:

name (str) – The model_name of the desired model.

Returns:

The registered model class.

Return type:

type[IModel]

Raises:

KeyError – If no model with name is registered.

is_registered(name)[source]

Return True if a model with name is registered.

Parameters:

name (str) – Model name to check.

Return type:

bool

names()[source]

Return a sorted list of all registered model names.

Returns:

Sorted list of model_name strings.

Return type:

list[str]

register(model_cls)[source]

Register a compatible model class.

May be used as a class decorator.

Parameters:

model_cls (type[IModel]) – The model class to register. Must be a concrete subclass of IModel that defines a non-empty model_name class variable.

Returns:

The model class unchanged (enables decorator use).

Return type:

type[IModel]

Raises:
  • TypeError – If model_cls is not a concrete IModel subclass or does not define a valid model_name.

  • ValueError – If a model with the same name is already registered.

unregister(name)[source]

Remove the model registered under name.

Parameters:

name (str) – The model_name of the model to remove.

Raises:

KeyError – If no model with name is registered.

class ModelState(*values)[source]

Bases: Enum

Enumeration of the six lifecycle states for a parsimonious model.

States follow a strict progression:

CREATED → INITIALIZED → VALIDATED → PREPARED → PREDICTED → FINALIZED

Concrete IModel implementations are responsible for advancing _state as each lifecycle method completes.

Variables:
  • CREATED – Object has been instantiated; no parameters registered yet.

  • INITIALIZEDinitialize() has completed; parameters are registered and model structure is set up.

  • VALIDATEDvalidate() returned True; all parameters are within their specified bounds.

  • PREPAREDprepare() has completed; forcing/input data are loaded and pre-processed.

  • PREDICTEDpredict() has completed; model outputs are available.

  • FINALIZEDfinalize() has completed; resources have been released.

CREATED = 'created'
FINALIZED = 'finalized'
INITIALIZED = 'initialized'
PREDICTED = 'predicted'
PREPARED = 'prepared'
VALIDATED = 'validated'
class ScalarParameter(name, value, lower_bound, upper_bound, units='', description='', calibrate=True)[source]

Bases: object

A named scalar parameter with lower and upper bounds.

Parameters:
  • name (str) – Unique identifier for the parameter within a model.

  • value (float) – Current parameter value.

  • lower_bound (float) – Minimum permissible value (inclusive).

  • upper_bound (float) – Maximum permissible value (inclusive).

  • units (str) – Physical units (informational only).

  • description (str) – Human-readable description (informational only).

Raises:

ValueError – If lower_bound > upper_bound.

Example:

p = ScalarParameter("k", value=0.5, lower_bound=0.0, upper_bound=1.0)
assert p.is_valid()
assert p.normalize() == 0.5
clamp()[source]

Return a copy of this parameter with value clamped to the bounds.

Returns:

New ScalarParameter with value in [lower_bound, upper_bound].

Return type:

ScalarParameter

is_valid()[source]

Return True if value lies within [lower_bound, upper_bound].

Returns:

True when the value satisfies the bounds constraint.

Return type:

bool

normalize()[source]

Return value mapped linearly to [0, 1] within the bounds.

Returns 0.0 when lower_bound == upper_bound.

Returns:

Normalized value in [0, 1].

Return type:

float

update(*, value=None, lower_bound=None, upper_bound=None, units=None, description=None, calibrate=None)[source]

Update one or more mutable attributes in-place.

Only the keyword arguments you supply are changed; others are left untouched. Raises ValueError if the resulting bounds are invalid (lower_bound > upper_bound).

Parameters:
  • value (float | None) – New parameter value.

  • lower_bound (float | None) – New lower bound.

  • upper_bound (float | None) – New upper bound.

  • units (str | None) – New units string (e.g. "in", "m/s").

  • description (str | None) – New human-readable description.

  • calibrate (bool | None) – New calibration flag.

Raises:

ValueError – If lower_bound > upper_bound after the update.

calibrate: bool = True

When False the parameter is held fixed and excluded from the calibration search space. Its value is still applied during predict() but the optimizer will never modify it.

description: str = ''
lower_bound: float
name: str
units: str = ''
upper_bound: float
value: float
class VectorParameter(name, values, lower_bounds, upper_bounds, units='', description='', calibrate=True)[source]

Bases: object

A named vector parameter with element-wise lower and upper bounds.

A scalar supplied for lower_bounds or upper_bounds is broadcast to match the length of values.

Parameters:
  • name (str) – Unique identifier for the parameter within a model.

  • values (numpy.ndarray) – 1-D array of current parameter values.

  • lower_bounds (numpy.ndarray) – 1-D array of lower bounds, one per element. A scalar is broadcast to match the length of values.

  • upper_bounds (numpy.ndarray) – 1-D array of upper bounds, one per element. A scalar is broadcast to match the length of values.

  • units (str) – Physical units (informational only).

  • description (str) – Human-readable description (informational only).

  • calibrate (bool) – When False the parameter is held fixed and excluded from the calibration search space.

Raises:

ValueError – If values is not 1-D, if the bounds arrays do not match the length of values after broadcasting, or if any lower_bound > upper_bound.

Example:

import numpy as np
p = VectorParameter("beta", values=[0.2, 0.8],
                    lower_bounds=0.0, upper_bounds=1.0)
assert p.is_valid()
np.testing.assert_allclose(p.normalize(), [0.2, 0.8])
clamp()[source]

Return a copy with all values clamped element-wise to their bounds.

Returns:

New VectorParameter with every value within its bounds.

Return type:

VectorParameter

is_valid()[source]

Return True if all values lie within their respective bounds.

Returns:

True when every element satisfies its bounds constraint.

Return type:

bool

normalize()[source]

Return values mapped element-wise to [0, 1] within the bounds.

Elements with lower_bound == upper_bound are mapped to 0.0.

Returns:

Array of normalized values, each in [0, 1].

Return type:

numpy.ndarray

update(*, values=None, lower_bounds=None, upper_bounds=None, units=None, description=None, calibrate=None)[source]

Update one or more mutable attributes in-place.

Only the keyword arguments you supply are changed; others are left untouched. Scalar bounds are broadcast to the vector length. Raises ValueError if the resulting bounds or shape are invalid.

Parameters:
  • values (numpy.ndarray | None) – New values array (must match current length).

  • lower_bounds (numpy.ndarray | None) – New lower bounds (scalar broadcast supported).

  • upper_bounds (numpy.ndarray | None) – New upper bounds (scalar broadcast supported).

  • units (str | None) – New units string.

  • description (str | None) – New human-readable description.

  • calibrate (bool | None) – New calibration flag.

Raises:

ValueError – If the resulting configuration is invalid.

calibrate: bool = True

When False the parameter is held fixed and excluded from the calibration search space. Its values are still applied during predict() but the optimizer will never modify them.

description: str = ''
lower_bounds: ndarray
name: str
property size: int

Number of elements in the parameter vector.

Return type:

int

units: str = ''
upper_bounds: ndarray
values: ndarray

Enumerations#

Enumerations for tracking model lifecycle state in sparsehydro.

class ModelState(*values)[source]#

Bases: Enum

Enumeration of the six lifecycle states for a parsimonious model.

States follow a strict progression:

CREATED → INITIALIZED → VALIDATED → PREPARED → PREDICTED → FINALIZED

Concrete IModel implementations are responsible for advancing _state as each lifecycle method completes.

Variables:
  • CREATED – Object has been instantiated; no parameters registered yet.

  • INITIALIZEDinitialize() has completed; parameters are registered and model structure is set up.

  • VALIDATEDvalidate() returned True; all parameters are within their specified bounds.

  • PREPAREDprepare() has completed; forcing/input data are loaded and pre-processed.

  • PREDICTEDpredict() has completed; model outputs are available.

  • FINALIZEDfinalize() has completed; resources have been released.

CREATED = 'created'#
FINALIZED = 'finalized'#
INITIALIZED = 'initialized'#
PREDICTED = 'predicted'#
PREPARED = 'prepared'#
VALIDATED = 'validated'#

Parameters#

Parameters are the connective tissue between the model physics and the calibration engine. Every numeric quantity that may be optimised must be registered with the model via a ScalarParameter (single value) or VectorParameter (array).

Setting calibrate=False on a ScalarParameter freezes that parameter at its current value — it is excluded from the optimisation search space but still applied during predict():

p = ScalarParameter("area_acres", value=250.0,
                    lower_bound=1.0, upper_bound=100_000.0,
                    calibrate=False)   # held fixed; not optimised

Typed parameter classes with boundary enforcement for sparsehydro models.

Parameters are the primary calibration handles exposed by a model. Each parameter carries its name, current value(s), and the permissible range so that calibration algorithms can operate in a well-defined search space.

class ConstraintRecord(name, description='')[source]#

Bases: object

Metadata for a single inequality constraint registered by a model.

Complements ScalarParameter for the constraint side of the optimisation problem. The residual values themselves are returned by inequality_constraints(); this class carries only the identity of each constraint so that solvers and notebooks can display meaningful labels.

Parameters:
  • name (str) – Short machine-readable identifier (e.g. "sum_R_leq_1").

  • description (str) – Human-readable description of what the constraint enforces (e.g. "Sum of R_i fractions 1.0").

description: str = ''#
name: str#
class FieldRecord(name, units='', description='', calibratable=False)[source]#

Bases: object

Metadata for a single column in a model’s predict() output DataFrame.

Register one FieldRecord per output column during initialize() so that calibration tooling, notebooks, and downstream consumers can discover what each column contains without inspecting the DataFrame itself.

Parameters:
  • name (str) – Column name exactly as it appears in the predict() output (e.g. "rdii_cfs", "total_cfs").

  • units (str) – Physical units string (e.g. "CFS", "mm", "in"). Use "" for dimensionless or non-physical columns such as "datetime".

  • description (str) – Human-readable explanation of what the field represents.

  • calibratable (bool) – True when this column can serve as the predicted column in a CalibrationProblem — i.e. it is a flow-rate or quantity directly comparable to an observed signal. Diagnostic columns (depth, excess, datetime) should be False.

Example:

from sparsehydro.parameters import FieldRecord

class MyModel(IModel):
    def initialize(self) -> None:
        self.register_output_field(FieldRecord(
            name="datetime",
            description="Simulation time step",
        ))
        self.register_output_field(FieldRecord(
            name="q_cfs",
            units="CFS",
            description="Predicted flow rate",
            calibratable=True,
        ))
        self._state = ModelState.INITIALIZED
calibratable: bool = False#
description: str = ''#
name: str#
units: str = ''#
class ScalarParameter(name, value, lower_bound, upper_bound, units='', description='', calibrate=True)[source]#

Bases: object

A named scalar parameter with lower and upper bounds.

Parameters:
  • name (str) – Unique identifier for the parameter within a model.

  • value (float) – Current parameter value.

  • lower_bound (float) – Minimum permissible value (inclusive).

  • upper_bound (float) – Maximum permissible value (inclusive).

  • units (str) – Physical units (informational only).

  • description (str) – Human-readable description (informational only).

Raises:

ValueError – If lower_bound > upper_bound.

Example:

p = ScalarParameter("k", value=0.5, lower_bound=0.0, upper_bound=1.0)
assert p.is_valid()
assert p.normalize() == 0.5
clamp()[source]#

Return a copy of this parameter with value clamped to the bounds.

Returns:

New ScalarParameter with value in [lower_bound, upper_bound].

Return type:

ScalarParameter

is_valid()[source]#

Return True if value lies within [lower_bound, upper_bound].

Returns:

True when the value satisfies the bounds constraint.

Return type:

bool

normalize()[source]#

Return value mapped linearly to [0, 1] within the bounds.

Returns 0.0 when lower_bound == upper_bound.

Returns:

Normalized value in [0, 1].

Return type:

float

update(*, value=None, lower_bound=None, upper_bound=None, units=None, description=None, calibrate=None)[source]#

Update one or more mutable attributes in-place.

Only the keyword arguments you supply are changed; others are left untouched. Raises ValueError if the resulting bounds are invalid (lower_bound > upper_bound).

Parameters:
  • value (float | None) – New parameter value.

  • lower_bound (float | None) – New lower bound.

  • upper_bound (float | None) – New upper bound.

  • units (str | None) – New units string (e.g. "in", "m/s").

  • description (str | None) – New human-readable description.

  • calibrate (bool | None) – New calibration flag.

Raises:

ValueError – If lower_bound > upper_bound after the update.

calibrate: bool = True#

When False the parameter is held fixed and excluded from the calibration search space. Its value is still applied during predict() but the optimizer will never modify it.

description: str = ''#
lower_bound: float#
name: str#
units: str = ''#
upper_bound: float#
value: float#
class VectorParameter(name, values, lower_bounds, upper_bounds, units='', description='', calibrate=True)[source]#

Bases: object

A named vector parameter with element-wise lower and upper bounds.

A scalar supplied for lower_bounds or upper_bounds is broadcast to match the length of values.

Parameters:
  • name (str) – Unique identifier for the parameter within a model.

  • values (numpy.ndarray) – 1-D array of current parameter values.

  • lower_bounds (numpy.ndarray) – 1-D array of lower bounds, one per element. A scalar is broadcast to match the length of values.

  • upper_bounds (numpy.ndarray) – 1-D array of upper bounds, one per element. A scalar is broadcast to match the length of values.

  • units (str) – Physical units (informational only).

  • description (str) – Human-readable description (informational only).

  • calibrate (bool) – When False the parameter is held fixed and excluded from the calibration search space.

Raises:

ValueError – If values is not 1-D, if the bounds arrays do not match the length of values after broadcasting, or if any lower_bound > upper_bound.

Example:

import numpy as np
p = VectorParameter("beta", values=[0.2, 0.8],
                    lower_bounds=0.0, upper_bounds=1.0)
assert p.is_valid()
np.testing.assert_allclose(p.normalize(), [0.2, 0.8])
clamp()[source]#

Return a copy with all values clamped element-wise to their bounds.

Returns:

New VectorParameter with every value within its bounds.

Return type:

VectorParameter

is_valid()[source]#

Return True if all values lie within their respective bounds.

Returns:

True when every element satisfies its bounds constraint.

Return type:

bool

normalize()[source]#

Return values mapped element-wise to [0, 1] within the bounds.

Elements with lower_bound == upper_bound are mapped to 0.0.

Returns:

Array of normalized values, each in [0, 1].

Return type:

numpy.ndarray

update(*, values=None, lower_bounds=None, upper_bounds=None, units=None, description=None, calibrate=None)[source]#

Update one or more mutable attributes in-place.

Only the keyword arguments you supply are changed; others are left untouched. Scalar bounds are broadcast to the vector length. Raises ValueError if the resulting bounds or shape are invalid.

Parameters:
  • values (numpy.ndarray | None) – New values array (must match current length).

  • lower_bounds (numpy.ndarray | None) – New lower bounds (scalar broadcast supported).

  • upper_bounds (numpy.ndarray | None) – New upper bounds (scalar broadcast supported).

  • units (str | None) – New units string.

  • description (str | None) – New human-readable description.

  • calibrate (bool | None) – New calibration flag.

Raises:

ValueError – If the resulting configuration is invalid.

calibrate: bool = True#

When False the parameter is held fixed and excluded from the calibration search space. Its values are still applied during predict() but the optimizer will never modify them.

description: str = ''#
lower_bounds: ndarray#
name: str#
property size: int#

Number of elements in the parameter vector.

Return type:

int

units: str = ''#
upper_bounds: ndarray#
values: ndarray#

Model Interface#

All physical models in sparsehydro implement IModel. The lifecycle enforces a consistent prepare → predict → finalize pattern and keeps the calibration engine decoupled from model internals.

IUnitHydroComponent extends IModel with a get_kernel() method. Any model implementing this interface can be used as a component inside RDIIModel.

Abstract base interfaces for parsimonious hydrological models.

All concrete models must inherit from IModel and implement the five lifecycle methods. The class also provides a built-in parameter registry so that calibration algorithms can discover and manipulate named parameters without knowing the internal model structure.

class IModel[source]#

Bases: ABC

Abstract interface for a parsimonious hydrological model.

Model name

Every concrete subclass must define a model_name class variable — a non-empty string that uniquely identifies the model type. This is enforced at class-definition time:

class MyModel(IModel):
    model_name = "my-model"
    ...

Attempting to define a concrete subclass without model_name raises TypeError immediately.

Lifecycle

Concrete subclasses must advance self._state as each method completes:

CREATED → INITIALIZED → VALIDATED → PREPARED → PREDICTED → FINALIZED

Parameter registry

Parameters are registered during initialize() via register_scalar_parameter() and register_vector_parameter(). Calibration tools retrieve them by name through get_scalar_parameter() and get_vector_parameter().

Minimal concrete implementation:

class MyModel(IModel):
    model_name = "my-model"

    def initialize(self) -> None:
        self.register_scalar_parameter(
            ScalarParameter("alpha", value=0.3,
                            lower_bound=0.0, upper_bound=1.0)
        )
        self._state = ModelState.INITIALIZED

    def validate(self) -> bool:
        ok = self.parameters_valid()
        if ok:
            self._state = ModelState.VALIDATED
        return ok

    def prepare(self, forcing) -> None:
        self._forcing = forcing
        self._state = ModelState.PREPARED

    def predict(self) -> pd.Series:
        alpha = self.get_scalar_parameter("alpha").value
        self._state = ModelState.PREDICTED
        return pd.Series(self._forcing * alpha)

    def finalize(self) -> None:
        self._state = ModelState.FINALIZED
apply_flat_parameter(name, value)[source]#

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)[source]#

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

abstractmethod finalize()[source]#

Release resources and wrap up computation.

Returns:

Nothing.

Return type:

None

get_output_field(name)[source]#

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)[source]#

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)[source]#

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()[source]#

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

abstractmethod initialize(*args, **kwargs)[source]#

Set up model structure and register parameters.

Called once before validate(). Implementations register every ScalarParameter and VectorParameter here and advance the state to INITIALIZED.

Parameters:
  • args (Any) – Optional positional configuration defined by the subclass.

  • kwargs (Any) – Optional keyword configuration defined by the subclass.

Returns:

Nothing.

Return type:

None

is_created()[source]#

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()[source]#

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()[source]#

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()[source]#

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()[source]#

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()[source]#

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()[source]#

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()[source]#

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

abstractmethod predict(*args, **kwargs)[source]#

Execute the model and return its outputs.

Parameters:
  • args (Any) – Positional run-time arguments.

  • kwargs (Any) – Keyword run-time arguments.

Returns:

Model outputs, typically with a predicted-flow column.

Return type:

pandas.DataFrame | pandas.Series

abstractmethod prepare(*args, **kwargs)[source]#

Load and pre-process forcing/input data.

Parameters:
  • args (Any) – Positional forcing/input data (e.g. a DataFrame of rainfall).

  • kwargs (Any) – Keyword forcing/input options.

Returns:

Nothing.

Return type:

None

read_flat_parameter(name)[source]#

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)[source]#

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)[source]#

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)[source]#

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)[source]#

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)[source]#

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)[source]#

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

abstractmethod validate()[source]#

Validate the model configuration and parameter bounds.

Implementations should advance the state to VALIDATED when returning True.

Returns:

True if the model is valid and ready for prepare(); False otherwise.

Return type:

bool

property calibratable_output_names: list[str]#

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]#

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]#

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str]#

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]#

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]#

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]#

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState#

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]#

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

class IUnitHydroComponent[source]#

Bases: IModel, ABC

Abstract base for unit hydrograph components used within RDIIModel.

Extends IModel with a single additional method, get_kernel(), that returns a normalized ordinate array suitable for convolution with a rainfall-excess series.

Amplitude parameter

Many UH models carry a parameter that scales the total response volume (R for RTK triangles, A for Nash/Gamma UH shapes). When a component is embedded in RDIIModel, that composite manages the fraction R_i separately and re-registers only the shape parameters. Declare the name of the amplitude/scaling parameter as a class variable so the composite can exclude it:

class MyUH(IUnitHydroComponent):
    _amplitude_param_name = "A"   # or "R", or None if none
apply_flat_parameter(name, value)#

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)#

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

abstractmethod finalize()#

Release resources and wrap up computation.

Returns:

Nothing.

Return type:

None

abstractmethod get_kernel(dt_hours, n_steps=None)[source]#

Return normalized unit hydrograph ordinates.

The returned array satisfies:

np.sum(ordinates) * dt_hours ≈ 1.0
Parameters:
  • dt_hours (float) – Time-step size [hr] of the forcing data.

  • n_steps (int | None) – If provided, trim or zero-pad the result to this length.

Returns:

1-D ordinate array [1/hr].

Return type:

numpy.ndarray

get_output_field(name)#

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)#

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)#

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()#

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

abstractmethod initialize(*args, **kwargs)#

Set up model structure and register parameters.

Called once before validate(). Implementations register every ScalarParameter and VectorParameter here and advance the state to INITIALIZED.

Parameters:
  • args (Any) – Optional positional configuration defined by the subclass.

  • kwargs (Any) – Optional keyword configuration defined by the subclass.

Returns:

Nothing.

Return type:

None

is_created()#

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()#

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()#

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()#

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()#

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()#

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()#

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()#

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

abstractmethod predict(*args, **kwargs)#

Execute the model and return its outputs.

Parameters:
  • args (Any) – Positional run-time arguments.

  • kwargs (Any) – Keyword run-time arguments.

Returns:

Model outputs, typically with a predicted-flow column.

Return type:

pandas.DataFrame | pandas.Series

abstractmethod prepare(*args, **kwargs)#

Load and pre-process forcing/input data.

Parameters:
  • args (Any) – Positional forcing/input data (e.g. a DataFrame of rainfall).

  • kwargs (Any) – Keyword forcing/input options.

Returns:

Nothing.

Return type:

None

read_flat_parameter(name)#

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)#

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)#

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)#

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)#

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)#

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)#

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

abstractmethod validate()#

Validate the model configuration and parameter bounds.

Implementations should advance the state to VALIDATED when returning True.

Returns:

True if the model is valid and ready for prepare(); False otherwise.

Return type:

bool

property calibratable_output_names: list[str]#

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]#

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]#

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str]#

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]#

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]#

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]#

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState#

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]#

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

Model Registry#

Model registration service for sparsehydro.

ModelRegistry tracks compatible IModel implementations and lets calibration frameworks discover and instantiate models by name without importing them directly.

A module-level default registry instance is provided as registry. Models can self-register at definition time using it as a decorator:

from sparsehydro.registry import registry

@registry.register
class LinearReservoir(IModel):
    model_name = "linear-reservoir"
    ...
class ModelRegistry[source]#

Bases: object

Central registry for tracking compatible parsimonious model classes.

A model class is considered compatible if it:

  1. Is a concrete (non-abstract) subclass of IModel.

  2. Defines a non-empty model_name class variable.

The registry can be used directly as a class decorator:

registry = ModelRegistry()

@registry.register
class LinearReservoir(IModel):
    model_name = "linear-reservoir"
    ...

model = registry.create("linear-reservoir")
create(name, *args, **kwargs)[source]#

Instantiate the model class registered under name.

All positional and keyword arguments are forwarded to the model constructor.

Parameters:

name (str) – The model_name of the model to instantiate.

Returns:

A new instance of the registered model.

Return type:

IModel

Raises:

KeyError – If no model with name is registered.

get(name)[source]#

Return the model class registered under name.

Parameters:

name (str) – The model_name of the desired model.

Returns:

The registered model class.

Return type:

type[IModel]

Raises:

KeyError – If no model with name is registered.

is_registered(name)[source]#

Return True if a model with name is registered.

Parameters:

name (str) – Model name to check.

Return type:

bool

names()[source]#

Return a sorted list of all registered model names.

Returns:

Sorted list of model_name strings.

Return type:

list[str]

register(model_cls)[source]#

Register a compatible model class.

May be used as a class decorator.

Parameters:

model_cls (type[IModel]) – The model class to register. Must be a concrete subclass of IModel that defines a non-empty model_name class variable.

Returns:

The model class unchanged (enables decorator use).

Return type:

type[IModel]

Raises:
  • TypeError – If model_cls is not a concrete IModel subclass or does not define a valid model_name.

  • ValueError – If a model with the same name is already registered.

unregister(name)[source]#

Remove the model registered under name.

Parameters:

name (str) – The model_name of the model to remove.

Raises:

KeyError – If no model with name is registered.

registry: ModelRegistry = ModelRegistry(['amm', 'ensemble', 'rdii', 'seasonality'])#

Default module-level registry. Import and use this instance directly rather than creating your own unless you need isolation.

PyTorch Interface#

PyTorch-compatible model interface for gradient-based parameter estimation.

ITorchModel combines the sparsehydro IModel lifecycle with torch.nn.Module, enabling automatic differentiation through the model computation so that parameters can be optimised with gradient-based methods (e.g. Adam, L-BFGS).

PyTorch is an optional dependency. If it is not installed, importing this module defines a placeholder class that raises ImportError on instantiation, preserving the package’s ability to run without torch.

Install with:

pip install sparsehydro[torch]
class ITorchModel[source]#

Bases: IModel, Module

Abstract interface for differentiable parsimonious models.

Inherits from both IModel and torch.nn.Module. Subclasses must implement all five IModel lifecycle methods and forward() — the differentiable computation graph.

The default predict() implementation calls forward() and advances model state to PREDICTED. Override predict() if additional pre/post-processing around forward() is required.

Gradient-tracked parameters should be declared as torch.nn.Parameter attributes so that PyTorch optimisers can discover them via Module.parameters(). The sparsehydro register_scalar_parameter() / register_vector_parameter() registry holds metadata (bounds, units, description) for the same parameters to allow calibration algorithms to apply constraints.

Example:

import torch
import torch.nn as nn
from sparsehydro import ModelState, ScalarParameter
from sparsehydro.models import ITorchModel

class LinearReservoir(ITorchModel):
    def initialize(self) -> None:
        self.k = nn.Parameter(torch.tensor(0.5))
        self.register_scalar_parameter(
            ScalarParameter("k", value=0.5,
                            lower_bound=0.0, upper_bound=1.0)
        )
        self._state = ModelState.INITIALIZED

    def validate(self) -> bool:
        ok = self.parameters_valid()
        if ok:
            self._state = ModelState.VALIDATED
        return ok

    def prepare(self, forcing: torch.Tensor) -> None:
        self._forcing = forcing
        self._state = ModelState.PREPARED

    def forward(self, forcing: torch.Tensor) -> torch.Tensor:
        return self.k * forcing

    def finalize(self) -> None:
        self._state = ModelState.FINALIZED
add_module(name, module)#

Add a child module to the current module.

The module can be accessed as an attribute using the given name.

Parameters:
  • name (str) – name of the child module. The child module can be accessed from this module using the given name

  • module (Module) – child module to be added to the module.

apply(fn)#

Apply fn recursively to every submodule (as returned by .children()) as well as self.

Typical use includes initializing the parameters of a model (see also torch.nn.init).

Parameters:

fn (Module -> None) – function to be applied to each submodule

Returns:

self

Return type:

Module

Example:

>>> @torch.no_grad()
>>> def init_weights(m):
>>>     print(m)
>>>     if type(m) is nn.Linear:
>>>         m.weight.fill_(1.0)
>>>         print(m.weight)
>>> net = nn.Sequential(nn.Linear(2, 2), nn.Linear(2, 2))
>>> net.apply(init_weights)
Linear(in_features=2, out_features=2, bias=True)
Parameter containing:
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
Linear(in_features=2, out_features=2, bias=True)
Parameter containing:
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
Sequential(
  (0): Linear(in_features=2, out_features=2, bias=True)
  (1): Linear(in_features=2, out_features=2, bias=True)
)
apply_flat_parameter(name, value)#

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)#

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

bfloat16()#

Casts all floating point parameters and buffers to bfloat16 datatype.

Note

This method modifies the module in-place.

Returns:

self

Return type:

Module

buffers(recurse=True)#

Return an iterator over module buffers.

Parameters:

recurse (bool) – if True, then yields buffers of this module and all submodules. Otherwise, yields only buffers that are direct members of this module.

Yields:

torch.Tensor – module buffer

Example:

>>> # xdoctest: +SKIP("undefined vars")
>>> for buf in model.buffers():
>>>     print(type(buf), buf.size())
<class 'torch.Tensor'> (20L,)
<class 'torch.Tensor'> (20L, 1L, 5L, 5L)
children()#

Return an iterator over immediate children modules.

Yields:

Module – a child module

compile(*args, **kwargs)#

Compile this Module’s forward using torch.compile().

This Module’s __call__ method is compiled and all arguments are passed as-is to torch.compile().

See torch.compile() for details on the arguments for this function.

cpu()#

Move all model parameters and buffers to the CPU.

Note

This method modifies the module in-place.

Returns:

self

Return type:

Module

cuda(device=None)#

Move all model parameters and buffers to the GPU.

This also makes associated parameters and buffers different objects. So it should be called before constructing the optimizer if the module will live on GPU while being optimized.

Note

This method modifies the module in-place.

Parameters:

device (int, optional) – if specified, all parameters will be copied to that device

Returns:

self

Return type:

Module

double()#

Casts all floating point parameters and buffers to double datatype.

Note

This method modifies the module in-place.

Returns:

self

Return type:

Module

eval()#

Set the module in evaluation mode.

This has an effect only on certain modules. See the documentation of particular modules for details of their behaviors in training/evaluation mode, i.e. whether they are affected, e.g. Dropout, BatchNorm, etc.

This is equivalent with self.train(False).

See Locally disabling gradient computation for a comparison between .eval() and several similar mechanisms that may be confused with it.

Returns:

self

Return type:

Module

extra_repr()#

Return the extra representation of the module.

To print customized extra information, you should re-implement this method in your own modules. Both single-line and multi-line strings are acceptable.

abstractmethod finalize()#

Release resources and wrap up computation.

Returns:

Nothing.

Return type:

None

float()#

Casts all floating point parameters and buffers to float datatype.

Note

This method modifies the module in-place.

Returns:

self

Return type:

Module

abstractmethod forward(*args, **kwargs)[source]#

Differentiable forward pass producing the model output.

Subclasses implement the model computation using torch operations so that gradients flow back to the registered torch.nn.Parameter attributes.

Parameters:
  • args (Any) – Positional forcing inputs (e.g. a rainfall tensor).

  • kwargs (Any) – Keyword forcing inputs.

Returns:

The model output tensor with gradient tracking enabled.

Return type:

torch.Tensor

get_buffer(target)#

Return the buffer given by target if it exists, otherwise throw an error.

See the docstring for get_submodule for a more detailed explanation of this method’s functionality as well as how to correctly specify target.

Parameters:

target (str) – The fully-qualified string name of the buffer to look for. (See get_submodule for how to specify a fully-qualified string.)

Returns:

The buffer referenced by target

Return type:

torch.Tensor

Raises:

AttributeError – If the target string references an invalid path or resolves to something that is not a buffer

get_extra_state()#

Return any extra state to include in the module’s state_dict.

Implement this and a corresponding set_extra_state() for your module if you need to store extra state. This function is called when building the module’s state_dict().

Note that extra state should be picklable to ensure working serialization of the state_dict. We only provide backwards compatibility guarantees for serializing Tensors; other objects may break backwards compatibility if their serialized pickled form changes.

Returns:

Any extra state to store in the module’s state_dict

Return type:

object

get_output_field(name)#

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_parameter(target)#

Return the parameter given by target if it exists, otherwise throw an error.

See the docstring for get_submodule for a more detailed explanation of this method’s functionality as well as how to correctly specify target.

Parameters:

target (str) – The fully-qualified string name of the Parameter to look for. (See get_submodule for how to specify a fully-qualified string.)

Returns:

The Parameter referenced by target

Return type:

torch.nn.Parameter

Raises:

AttributeError – If the target string references an invalid path or resolves to something that is not an nn.Parameter

get_scalar_parameter(name)#

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_submodule(target)#

Return the submodule given by target if it exists, otherwise throw an error.

For example, let’s say you have an nn.Module A that looks like this:

A(
    (net_b): Module(
        (net_c): Module(
            (conv): Conv2d(16, 33, kernel_size=(3, 3), stride=(2, 2))
        )
        (linear): Linear(in_features=100, out_features=200, bias=True)
    )
)

(The diagram shows an nn.Module A. A which has a nested submodule net_b, which itself has two submodules net_c and linear. net_c then has a submodule conv.)

To check whether or not we have the linear submodule, we would call get_submodule("net_b.linear"). To check whether we have the conv submodule, we would call get_submodule("net_b.net_c.conv").

The runtime of get_submodule is bounded by the degree of module nesting in target. A query against named_modules achieves the same result, but it is O(N) in the number of transitive modules. So, for a simple check to see if some submodule exists, get_submodule should always be used.

Parameters:

target (str) – The fully-qualified string name of the submodule to look for. (See above example for how to specify a fully-qualified string.)

Returns:

The submodule referenced by target

Return type:

torch.nn.Module

Raises:

AttributeError – If at any point along the path resulting from the target string the (sub)path resolves to a non-existent attribute name or an object that is not an instance of nn.Module.

get_vector_parameter(name)#

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

half()#

Casts all floating point parameters and buffers to half datatype.

Note

This method modifies the module in-place.

Returns:

self

Return type:

Module

inequality_constraints()#

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

abstractmethod initialize(*args, **kwargs)#

Set up model structure and register parameters.

Called once before validate(). Implementations register every ScalarParameter and VectorParameter here and advance the state to INITIALIZED.

Parameters:
  • args (Any) – Optional positional configuration defined by the subclass.

  • kwargs (Any) – Optional keyword configuration defined by the subclass.

Returns:

Nothing.

Return type:

None

ipu(device=None)#

Move all model parameters and buffers to the IPU.

This also makes associated parameters and buffers different objects. So it should be called before constructing the optimizer if the module will live on IPU while being optimized.

Note

This method modifies the module in-place.

Parameters:

device (int, optional) – if specified, all parameters will be copied to that device

Returns:

self

Return type:

Module

is_created()#

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()#

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()#

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()#

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()#

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()#

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

load_state_dict(state_dict, strict=True, assign=False)#

Copy parameters and buffers from state_dict into this module and its descendants.

If strict is True, then the keys of state_dict must exactly match the keys returned by this module’s state_dict() function.

Warning

If assign is True the optimizer must be created after the call to load_state_dict unless get_swap_module_params_on_conversion() is True.

Parameters:
  • state_dict (dict) – a dict containing parameters and persistent buffers.

  • strict (bool, optional) – whether to strictly enforce that the keys in state_dict match the keys returned by this module’s state_dict() function. Default: True

  • assign (bool, optional) – When set to False, the properties of the tensors in the current module are preserved whereas setting it to True preserves properties of the Tensors in the state dict. The only exception is the requires_grad field of Parameter for which the value from the module is preserved. Default: False

Returns:

  • missing_keys is a list of str containing any keys that are expected

    by this module but missing from the provided state_dict.

  • unexpected_keys is a list of str containing the keys that are not

    expected by this module but present in the provided state_dict.

Return type:

NamedTuple with missing_keys and unexpected_keys fields

Note

If a parameter or buffer is registered as None and its corresponding key exists in state_dict, load_state_dict() will raise a RuntimeError.

modules(remove_duplicate=True)#

Return an iterator over all modules in the network.

Parameters:

remove_duplicate (bool) – whether to remove the duplicated module instances in the result or not.

Yields:

Module – a module in the network

Note

Duplicate modules are returned only once by default. In the following example, l will be returned only once.

Example:

>>> l = nn.Linear(2, 2)
>>> net = nn.Sequential(l, l)
>>> for idx, m in enumerate(net.modules()):
...     print(idx, '->', m)

0 -> Sequential(
  (0): Linear(in_features=2, out_features=2, bias=True)
  (1): Linear(in_features=2, out_features=2, bias=True)
)
1 -> Linear(in_features=2, out_features=2, bias=True)
mtia(device=None)#

Move all model parameters and buffers to the MTIA.

This also makes associated parameters and buffers different objects. So it should be called before constructing the optimizer if the module will live on MTIA while being optimized.

Note

This method modifies the module in-place.

Parameters:

device (int, optional) – if specified, all parameters will be copied to that device

Returns:

self

Return type:

Module

named_buffers(prefix='', recurse=True, remove_duplicate=True)#

Return an iterator over module buffers, yielding both the name of the buffer as well as the buffer itself.

Parameters:
  • prefix (str) – prefix to prepend to all buffer names.

  • recurse (bool, optional) – if True, then yields buffers of this module and all submodules. Otherwise, yields only buffers that are direct members of this module. Defaults to True.

  • remove_duplicate (bool, optional) – whether to remove the duplicated buffers in the result. Defaults to True.

Yields:

(str, torch.Tensor) – Tuple containing the name and buffer

Example:

>>> # xdoctest: +SKIP("undefined vars")
>>> for name, buf in self.named_buffers():
>>>     if name in ['running_var']:
>>>         print(buf.size())
named_children()#

Return an iterator over immediate children modules, yielding both the name of the module as well as the module itself.

Yields:

(str, Module) – Tuple containing a name and child module

Example:

>>> # xdoctest: +SKIP("undefined vars")
>>> for name, module in model.named_children():
>>>     if name in ['conv4', 'conv5']:
>>>         print(module)
named_modules(memo=None, prefix='', remove_duplicate=True)#

Return an iterator over all modules in the network, yielding both the name of the module as well as the module itself.

Parameters:
  • memo (set[Module] | None) – a memo to store the set of modules already added to the result

  • prefix (str) – a prefix that will be added to the name of the module

  • remove_duplicate (bool) – whether to remove the duplicated module instances in the result or not

Yields:

(str, Module) – Tuple of name and module

Note

Duplicate modules are returned only once. In the following example, l will be returned only once.

Example:

>>> l = nn.Linear(2, 2)
>>> net = nn.Sequential(l, l)
>>> for idx, m in enumerate(net.named_modules()):
...     print(idx, '->', m)

0 -> ('', Sequential(
  (0): Linear(in_features=2, out_features=2, bias=True)
  (1): Linear(in_features=2, out_features=2, bias=True)
))
1 -> ('0', Linear(in_features=2, out_features=2, bias=True))
named_parameters(prefix='', recurse=True, remove_duplicate=True)#

Return an iterator over module parameters, yielding both the name of the parameter as well as the parameter itself.

Parameters:
  • prefix (str) – prefix to prepend to all parameter names.

  • recurse (bool) – if True, then yields parameters of this module and all submodules. Otherwise, yields only parameters that are direct members of this module.

  • remove_duplicate (bool, optional) – whether to remove the duplicated parameters in the result. Defaults to True.

Yields:

(str, Parameter) – Tuple containing the name and parameter

Example:

>>> # xdoctest: +SKIP("undefined vars")
>>> for name, param in self.named_parameters():
>>>     if name in ['bias']:
>>>         print(param.size())
output_field_metadata()#

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters(recurse=True)#

Return an iterator over module parameters.

This is typically passed to an optimizer.

Parameters:

recurse (bool) – if True, then yields parameters of this module and all submodules. Otherwise, yields only parameters that are direct members of this module.

Yields:

Parameter – module parameter

Example:

>>> # xdoctest: +SKIP("undefined vars")
>>> for param in model.parameters():
>>>     print(type(param), param.size())
<class 'torch.Tensor'> (20L,)
<class 'torch.Tensor'> (20L, 1L, 5L, 5L)
parameters_valid()#

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict(*args, **kwargs)[source]#

Run the differentiable forward pass and advance model state.

Delegates to forward() and sets the model state to PREDICTED.

Parameters:
  • args (Any) – Positional forcing inputs forwarded to forward().

  • kwargs (Any) – Keyword forcing inputs forwarded to forward().

Returns:

The output tensor returned by forward().

Return type:

torch.Tensor

abstractmethod prepare(*args, **kwargs)#

Load and pre-process forcing/input data.

Parameters:
  • args (Any) – Positional forcing/input data (e.g. a DataFrame of rainfall).

  • kwargs (Any) – Keyword forcing/input options.

Returns:

Nothing.

Return type:

None

read_flat_parameter(name)#

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_backward_hook(hook)#

Register a backward hook on the module.

This function is deprecated in favor of register_full_backward_hook() and the behavior of this function will change in future versions.

Returns:

a handle that can be used to remove the added hook by calling handle.remove()

Return type:

torch.utils.hooks.RemovableHandle

register_buffer(name, tensor, persistent=True)#

Add a buffer to the module.

This is typically used to register a buffer that should not be considered a model parameter. For example, BatchNorm’s running_mean is not a parameter, but is part of the module’s state. Buffers, by default, are persistent and will be saved alongside parameters. This behavior can be changed by setting persistent to False. The only difference between a persistent buffer and a non-persistent buffer is that the latter will not be a part of this module’s state_dict.

Buffers can be accessed as attributes using given names.

Parameters:
  • name (str) – name of the buffer. The buffer can be accessed from this module using the given name

  • tensor (Tensor or None) – buffer to be registered. If None, then operations that run on buffers, such as cuda, are ignored. If None, the buffer is not included in the module’s state_dict.

  • persistent (bool) – whether the buffer is part of this module’s state_dict.

Example:

>>> # xdoctest: +SKIP("undefined vars")
>>> self.register_buffer('running_mean', torch.zeros(num_features))
register_forward_hook(hook, *, prepend=False, with_kwargs=False, always_call=False)#

Register a forward hook on the module.

The hook will be called every time after forward() has computed an output.

If with_kwargs is False or not specified, the input contains only the positional arguments given to the module. Keyword arguments won’t be passed to the hooks and only to the forward. The hook can modify the output. It can modify the input inplace but it will not have effect on forward since this is called after forward() is called. The hook should have the following signature:

hook(module, args, output) -> None or modified output

If with_kwargs is True, the forward hook will be passed the kwargs given to the forward function and be expected to return the output possibly modified. The hook should have the following signature:

hook(module, args, kwargs, output) -> None or modified output
Parameters:
  • hook (Callable) – The user defined hook to be registered.

  • prepend (bool) – If True, the provided hook will be fired before all existing forward hooks on this torch.nn.Module. Otherwise, the provided hook will be fired after all existing forward hooks on this torch.nn.Module. Note that global forward hooks registered with register_module_forward_hook() will fire before all hooks registered by this method. Default: False

  • with_kwargs (bool) – If True, the hook will be passed the kwargs given to the forward function. Default: False

  • always_call (bool) – If True the hook will be run regardless of whether an exception is raised while calling the Module. Default: False

Returns:

a handle that can be used to remove the added hook by calling handle.remove()

Return type:

torch.utils.hooks.RemovableHandle

register_forward_pre_hook(hook, *, prepend=False, with_kwargs=False)#

Register a forward pre-hook on the module.

The hook will be called every time before forward() is invoked.

If with_kwargs is false or not specified, the input contains only the positional arguments given to the module. Keyword arguments won’t be passed to the hooks and only to the forward. The hook can modify the input. User can either return a tuple or a single modified value in the hook. We will wrap the value into a tuple if a single value is returned (unless that value is already a tuple). The hook should have the following signature:

hook(module, args) -> None or modified input

If with_kwargs is true, the forward pre-hook will be passed the kwargs given to the forward function. And if the hook modifies the input, both the args and kwargs should be returned. The hook should have the following signature:

hook(module, args, kwargs) -> None or a tuple of modified input and kwargs
Parameters:
  • hook (Callable) – The user defined hook to be registered.

  • prepend (bool) – If true, the provided hook will be fired before all existing forward_pre hooks on this torch.nn.Module. Otherwise, the provided hook will be fired after all existing forward_pre hooks on this torch.nn.Module. Note that global forward_pre hooks registered with register_module_forward_pre_hook() will fire before all hooks registered by this method. Default: False

  • with_kwargs (bool) – If true, the hook will be passed the kwargs given to the forward function. Default: False

Returns:

a handle that can be used to remove the added hook by calling handle.remove()

Return type:

torch.utils.hooks.RemovableHandle

register_full_backward_hook(hook, prepend=False)#

Register a backward hook on the module.

The hook will be called every time the gradients with respect to a module are computed, and its firing rules are as follows:

  1. Ordinarily, the hook fires when the gradients are computed with respect to the module inputs.

  2. If none of the module inputs require gradients, the hook will fire when the gradients are computed with respect to module outputs.

  3. If none of the module outputs require gradients, then the hooks will not fire.

The hook should have the following signature:

hook(module, grad_input, grad_output) -> tuple(Tensor) or None

The grad_input and grad_output are tuples that contain the gradients with respect to the inputs and outputs respectively. The hook should not modify its arguments, but it can optionally return a new gradient with respect to the input that will be used in place of grad_input in subsequent computations. grad_input will only correspond to the inputs given as positional arguments and all kwarg arguments are ignored. Entries in grad_input and grad_output will be None for all non-Tensor arguments.

For technical reasons, when this hook is applied to a Module, its forward function will receive a view of each Tensor passed to the Module. Similarly the caller will receive a view of each Tensor returned by the Module’s forward function.

Warning

Modifying inputs or outputs inplace is not allowed when using backward hooks and will raise an error.

Parameters:
  • hook (Callable) – The user-defined hook to be registered.

  • prepend (bool) – If true, the provided hook will be fired before all existing backward hooks on this torch.nn.Module. Otherwise, the provided hook will be fired after all existing backward hooks on this torch.nn.Module. Note that global backward hooks registered with register_module_full_backward_hook() will fire before all hooks registered by this method.

Returns:

a handle that can be used to remove the added hook by calling handle.remove()

Return type:

torch.utils.hooks.RemovableHandle

register_full_backward_pre_hook(hook, prepend=False)#

Register a backward pre-hook on the module.

The hook will be called every time the gradients for the module are computed. The hook should have the following signature:

hook(module, grad_output) -> tuple[Tensor, ...], Tensor or None

The grad_output is a tuple. The hook should not modify its arguments, but it can optionally return a new gradient with respect to the output that will be used in place of grad_output in subsequent computations. Entries in grad_output will be None for all non-Tensor arguments.

For technical reasons, when this hook is applied to a Module, its forward function will receive a view of each Tensor passed to the Module. Similarly the caller will receive a view of each Tensor returned by the Module’s forward function.

Warning

Modifying inputs inplace is not allowed when using backward hooks and will raise an error.

Parameters:
  • hook (Callable) – The user-defined hook to be registered.

  • prepend (bool) – If true, the provided hook will be fired before all existing backward_pre hooks on this torch.nn.Module. Otherwise, the provided hook will be fired after all existing backward_pre hooks on this torch.nn.Module. Note that global backward_pre hooks registered with register_module_full_backward_pre_hook() will fire before all hooks registered by this method.

Returns:

a handle that can be used to remove the added hook by calling handle.remove()

Return type:

torch.utils.hooks.RemovableHandle

register_inequality_constraint(record)#

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_load_state_dict_post_hook(hook)#

Register a post-hook to be run after module’s load_state_dict() is called.

It should have the following signature::

hook(module, incompatible_keys) -> None

The module argument is the current module that this hook is registered on, and the incompatible_keys argument is a NamedTuple consisting of attributes missing_keys and unexpected_keys. missing_keys is a list of str containing the missing keys and unexpected_keys is a list of str containing the unexpected keys.

The given incompatible_keys can be modified inplace if needed.

Note that the checks performed when calling load_state_dict() with strict=True are affected by modifications the hook makes to missing_keys or unexpected_keys, as expected. Additions to either set of keys will result in an error being thrown when strict=True, and clearing out both missing and unexpected keys will avoid an error.

Returns:

a handle that can be used to remove the added hook by calling handle.remove()

Return type:

torch.utils.hooks.RemovableHandle

register_load_state_dict_pre_hook(hook)#

Register a pre-hook to be run before module’s load_state_dict() is called.

It should have the following signature::

hook(module, state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs) -> None # noqa: B950

Parameters:

hook (Callable) – Callable hook that will be invoked before loading the state dict.

register_module(name, module)#

Alias for add_module().

register_output_field(field)#

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_parameter(name, param)#

Add a parameter to the module.

The parameter can be accessed as an attribute using given name.

Parameters:
  • name (str) – name of the parameter. The parameter can be accessed from this module using the given name

  • param (Parameter or None) – parameter to be added to the module. If None, then operations that run on parameters, such as cuda, are ignored. If None, the parameter is not included in the module’s state_dict.

register_scalar_parameter(param)#

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_state_dict_post_hook(hook)#

Register a post-hook for the state_dict() method.

It should have the following signature::

hook(module, state_dict, prefix, local_metadata) -> None

The registered hooks can modify the state_dict inplace.

register_state_dict_pre_hook(hook)#

Register a pre-hook for the state_dict() method.

It should have the following signature::

hook(module, prefix, keep_vars) -> None

The registered hooks can be used to perform pre-processing before the state_dict call is made.

register_vector_parameter(param)#

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)#

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)#

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

requires_grad_(requires_grad=True)#

Change if autograd should record operations on parameters in this module.

This method sets the parameters’ requires_grad attributes in-place.

This method is helpful for freezing part of the module for finetuning or training parts of a model individually (e.g., GAN training).

See Locally disabling gradient computation for a comparison between .requires_grad_() and several similar mechanisms that may be confused with it.

Parameters:

requires_grad (bool) – whether autograd should record operations on parameters in this module. Default: True.

Returns:

self

Return type:

Module

set_extra_state(state)#

Set extra state contained in the loaded state_dict.

This function is called from load_state_dict() to handle any extra state found within the state_dict. Implement this function and a corresponding get_extra_state() for your module if you need to store extra state within its state_dict.

Parameters:

state (dict) – Extra state from the state_dict

set_submodule(target, module, strict=False)#

Set the submodule given by target if it exists, otherwise throw an error.

Note

If strict is set to False (default), the method will replace an existing submodule or create a new submodule if the parent module exists. If strict is set to True, the method will only attempt to replace an existing submodule and throw an error if the submodule does not exist.

For example, let’s say you have an nn.Module A that looks like this:

A(
    (net_b): Module(
        (net_c): Module(
            (conv): Conv2d(3, 3, 3)
        )
        (linear): Linear(3, 3)
    )
)

(The diagram shows an nn.Module A. A has a nested submodule net_b, which itself has two submodules net_c and linear. net_c then has a submodule conv.)

To override the Conv2d with a new submodule Linear, you could call set_submodule("net_b.net_c.conv", nn.Linear(1, 1)) where strict could be True or False

To add a new submodule Conv2d to the existing net_b module, you would call set_submodule("net_b.conv", nn.Conv2d(1, 1, 1)).

In the above if you set strict=True and call set_submodule("net_b.conv", nn.Conv2d(1, 1, 1), strict=True), an AttributeError will be raised because net_b does not have a submodule named conv.

Parameters:
  • target (str) – The fully-qualified string name of the submodule to look for. (See above example for how to specify a fully-qualified string.)

  • module (Module) – The module to set the submodule to.

  • strict (bool) – If False, the method will replace an existing submodule or create a new submodule if the parent module exists. If True, the method will only attempt to replace an existing submodule and throw an error if the submodule doesn’t already exist.

Raises:
  • ValueError – If the target string is empty or if module is not an instance of nn.Module.

  • AttributeError – If at any point along the path resulting from the target string the (sub)path resolves to a non-existent attribute name or an object that is not an instance of nn.Module.

share_memory()#

See torch.Tensor.share_memory_().

state_dict(*args, destination=None, prefix='', keep_vars=False)#

Return a dictionary containing references to the whole state of the module.

Both parameters and persistent buffers (e.g. running averages) are included. Keys are corresponding parameter and buffer names. Parameters and buffers set to None are not included.

Note

The returned object is a shallow copy. It contains references to the module’s parameters and buffers.

Warning

Currently state_dict() also accepts positional arguments for destination, prefix and keep_vars in order. However, this is being deprecated and keyword arguments will be enforced in future releases.

Warning

Please avoid the use of argument destination as it is not designed for end-users.

Parameters:
  • destination (dict, optional) – If provided, the state of module will be updated into the dict and the same object is returned. Otherwise, an OrderedDict will be created and returned. Default: None.

  • prefix (str, optional) – a prefix added to parameter and buffer names to compose the keys in state_dict. Default: ''.

  • keep_vars (bool, optional) – by default the Tensor s returned in the state dict are detached from autograd. If it’s set to True, detaching will not be performed. Default: False.

Returns:

a dictionary containing a whole state of the module

Return type:

dict

Example:

>>> # xdoctest: +SKIP("undefined vars")
>>> module.state_dict().keys()
['bias', 'weight']
to(*args, **kwargs)#

Move and/or cast the parameters and buffers.

This can be called as

to(device=None, dtype=None, non_blocking=False)
to(dtype, non_blocking=False)
to(tensor, non_blocking=False)
to(memory_format=torch.channels_last)

Its signature is similar to torch.Tensor.to(), but only accepts floating point or complex dtypes. In addition, this method will only cast the floating point or complex parameters and buffers to dtype (if given). The integral parameters and buffers will be moved device, if that is given, but with dtypes unchanged. When non_blocking is set, it tries to convert/move asynchronously with respect to the host if possible, e.g., moving CPU Tensors with pinned memory to CUDA devices.

See below for examples.

Note

This method modifies the module in-place.

Parameters:
  • device (torch.device) – the desired device of the parameters and buffers in this module

  • dtype (torch.dtype) – the desired floating point or complex dtype of the parameters and buffers in this module

  • tensor (torch.Tensor) – Tensor whose dtype and device are the desired dtype and device for all parameters and buffers in this module

  • memory_format (torch.memory_format) – the desired memory format for 4D parameters and buffers in this module (keyword only argument)

Returns:

self

Return type:

Module

Examples:

>>> # xdoctest: +IGNORE_WANT("non-deterministic")
>>> linear = nn.Linear(2, 2)
>>> linear.weight
Parameter containing:
tensor([[ 0.1913, -0.3420],
        [-0.5113, -0.2325]])
>>> linear.to(torch.double)
Linear(in_features=2, out_features=2, bias=True)
>>> linear.weight
Parameter containing:
tensor([[ 0.1913, -0.3420],
        [-0.5113, -0.2325]], dtype=torch.float64)
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_CUDA1)
>>> gpu1 = torch.device("cuda:1")
>>> linear.to(gpu1, dtype=torch.half, non_blocking=True)
Linear(in_features=2, out_features=2, bias=True)
>>> linear.weight
Parameter containing:
tensor([[ 0.1914, -0.3420],
        [-0.5112, -0.2324]], dtype=torch.float16, device='cuda:1')
>>> cpu = torch.device("cpu")
>>> linear.to(cpu)
Linear(in_features=2, out_features=2, bias=True)
>>> linear.weight
Parameter containing:
tensor([[ 0.1914, -0.3420],
        [-0.5112, -0.2324]], dtype=torch.float16)

>>> linear = nn.Linear(2, 2, bias=None).to(torch.cdouble)
>>> linear.weight
Parameter containing:
tensor([[ 0.3741+0.j,  0.2382+0.j],
        [ 0.5593+0.j, -0.4443+0.j]], dtype=torch.complex128)
>>> linear(torch.ones(3, 2, dtype=torch.cdouble))
tensor([[0.6122+0.j, 0.1150+0.j],
        [0.6122+0.j, 0.1150+0.j],
        [0.6122+0.j, 0.1150+0.j]], dtype=torch.complex128)
to_empty(*, device, recurse=True)#

Move the parameters and buffers to the specified device without copying storage.

Parameters:
  • device (torch.device) – The desired device of the parameters and buffers in this module.

  • recurse (bool) – Whether parameters and buffers of submodules should be recursively moved to the specified device.

Returns:

self

Return type:

Module

train(mode=True)#

Set the module in training mode.

This has an effect only on certain modules. See the documentation of particular modules for details of their behaviors in training/evaluation mode, i.e., whether they are affected, e.g. Dropout, BatchNorm, etc.

Parameters:

mode (bool) – whether to set training mode (True) or evaluation mode (False). Default: True.

Returns:

self

Return type:

Module

type(dst_type)#

Casts all parameters and buffers to dst_type.

Note

This method modifies the module in-place.

Parameters:

dst_type (type or string) – the desired type

Returns:

self

Return type:

Module

abstractmethod validate()#

Validate the model configuration and parameter bounds.

Implementations should advance the state to VALIDATED when returning True.

Returns:

True if the model is valid and ready for prepare(); False otherwise.

Return type:

bool

xpu(device=None)#

Move all model parameters and buffers to the XPU.

This also makes associated parameters and buffers different objects. So it should be called before constructing optimizer if the module will live on XPU while being optimized.

Note

This method modifies the module in-place.

Parameters:

device (int, optional) – if specified, all parameters will be copied to that device

Returns:

self

Return type:

Module

zero_grad(set_to_none=True)#

Reset gradients of all model parameters.

See similar function under torch.optim.Optimizer for more context.

Parameters:

set_to_none (bool) – instead of setting to zero, set the grads to None. See torch.optim.Optimizer.zero_grad() for details.

T_destination = ~T_destination#
property calibratable_output_names: list[str]#

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

call_super_init: bool = False#
dump_patches: bool = False#
property inequality_constraint_descriptions: list[str]#

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]#

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str]#

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]#

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]#

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]#

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState#

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

training: bool#
property vector_parameter_names: list[str]#

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]


Visualization#

The sparsehydro.visualization package provides interactive, browser-ready Plotly charts for time-series diagnostics, calibration result exploration, and RDII component analysis. All functions require the optional plotly dependency:

pip install plotly

All public names are importable directly from sparsehydro.visualization or from the top-level sparsehydro namespace.

sparsehydro.visualization — interactive Plotly charts for hydrological models.

Public API#

Name

Description

plot_timeseries() plot_residuals_scatter() plot_cumulative_volume() plot_calibration_timeseries() plot_ensemble_members_vs_observed() plot_one_to_one_band() VisualizationModel

Rainfall + observed/predicted dual-axis subplots Obs-vs-pred scatter, residual bars, autocorrelation Cumulative sums + volume error 2-row dashboard: exogenous + pred/obs + 1v1 scatter Each ensemble member vs. observed, plus combined 1:1 scatter with a CIWEM-style proportional band IModel wrapper for time-series plots

plot_pareto_evolution() plot_parallel_coordinates() plot_objective_convergence() plot_parameter_distributions() plot_sensitivity_heatmap() plot_pareto_scatter_matrix() plot_splom()

Animated Pareto front with generation slider Parallel-axis trade-off explorer Best-value line + percentile band per generation Violin grid of Pareto parameter spread Parameter–objective Pearson correlation heatmap SPLOM of all objectives SPLOM of all solutions with non-dominated highlighted

plot_rtk_shape() plot_rdii_components()

Unit hydrograph shape per RTKTriangle Stacked per-triangle RDII contributions

plot_calibration_dashboard()

Multi-panel offline HTML dashboard

All functions require the optional plotly dependency:

pip install plotly

RDII-specific functions additionally require:

pip install sparsehydro[rdii]
class VisualizationModel(title='Model Time Series', rainfall_label='Rainfall [mm]', flow_label='Flow')[source]

Bases: IModel

General-purpose visualization model for any IModel output.

Wraps plot_timeseries(), plot_pareto_evolution(), and plot_parallel_coordinates() behind the standard IModel lifecycle.

Column names for the input DataFrame are specified at prepare() time, making this model compatible with any model’s output format.

predict() returns the input DataFrame unchanged so the model can be composed in a pipeline. Figures are available as read-only properties afterward:

viz.timeseries_figure    # always generated
viz.pareto_figure        # generated when calibration_result is supplied
viz.parallel_figure      # generated when calibration_result is supplied
Parameters:
  • title (str) – Base title used across all figures.

  • rainfall_label (str) – Y-axis label for the rainfall panel.

  • flow_label (str) – Y-axis label for the flow panel.

apply_flat_parameter(name, value)

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]

Release stored data and figures and advance to FINALIZED.

get_output_field(name)

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

initialize()[source]

Advance to INITIALIZED.

is_created()

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict()[source]

Generate all applicable figures and return the input DataFrame.

Returns:

The DataFrame supplied to prepare() (unchanged).

Raises:

RuntimeError – If prepare() has not been called.

Return type:

DataFrame

prepare(data, datetime_col='datetime', predicted_col='predicted', observed_col=None, rainfall_col=None, calibration_result=None)[source]

Load model output data and configure column mapping.

Parameters:
  • data (pandas.DataFrame) – Any model’s output DataFrame.

  • datetime_col (str) – Column name for the time axis.

  • predicted_col (str) – Column name for the predicted output signal.

  • observed_col (str or None) – Column name for observed data, or None to omit.

  • rainfall_col (str or None) – Column name for rainfall forcing, or None to omit.

  • calibration_result (CalibrationResult or None) – When provided, predict() also generates Pareto-evolution and parallel-coordinates figures.

Raises:

ValueError – If required columns are absent.

read_flat_parameter(name)

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]

Validate and advance to VALIDATED.

Returns:

Always True.

Return type:

bool

property calibratable_output_names: list[str]

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name = 'visualization'

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property parallel_figure: go.Figure | None

Parallel-coordinates trade-off explorer, or None when no result was supplied.

property pareto_figure: go.Figure | None

Animated Pareto-front evolution, or None when no result was supplied.

property scalar_parameter_names: list[str]

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property timeseries_figure: go.Figure | None

Dual-axis rainfall/flow time series, or None before predict().

property vector_parameter_names: list[str]

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

plot_calibration_dashboard(result, timeseries_df=None, datetime_col='datetime', predicted_col='predicted', observed_col=None, rainfall_col=None, flow_label='Flow', title='Calibration Dashboard', output_path=None, use_cdn=True)[source]

Build a multi-panel calibration dashboard and write it to an HTML file.

Because plotly.graph_objects.Frame objects (used by plot_pareto_evolution()) and go.Parcoords traces cannot be embedded in a shared make_subplots grid, each sub-figure is serialised individually with plotly.io.to_html(full_html=False) and the sections are joined in an HTML template with a single Plotly CDN <script> tag.

Panels (shown when data is available):

  1. Time series — if timeseries_df is supplied.

  2. Objective convergence — always shown.

  3. Pareto front evolution (animated) — requires ≥ 1 history record.

  4. Parameter distributions — always shown.

  5. Parallel coordinates — always shown.

Parameters:
  • result (CalibrationResult) – Calibration result.

  • timeseries_df (pandas.DataFrame or None) – Optional model-output DataFrame.

  • datetime_col (str) – Datetime column name in timeseries_df.

  • predicted_col (str) – Predicted-flow column name in timeseries_df.

  • observed_col (str or None) – Observed-flow column name, or None to omit.

  • rainfall_col (str or None) – Rainfall column name, or None to omit zeros.

  • flow_label (str) – Y-axis label for flow panels.

  • title (str) – Dashboard heading.

  • output_path (str or None) – File path for the HTML output. Pass None to skip writing.

  • use_cdn (bool) – Include Plotly via CDN <script> tag when True; inline the full Plotly bundle when False (larger file, fully offline).

Returns:

The objective-convergence figure (for interactive notebook use; the full dashboard is only available in the HTML file).

Return type:

plotly.graph_objects.Figure

plot_cumulative_volume(datetime, observed, predicted, title='Cumulative Volume', flow_label='Flow')[source]

Two-panel cumulative volume comparison.

Row 1 — Cumulative sums of observed and predicted with a shaded fill between the two lines, highlighting volume discrepancy.

Row 2 — Cumulative volume error (obs_cumsum − pred_cumsum) with a zero-reference line.

Parameters:
  • datetime (array-like) – Time axis values.

  • observed (numpy.ndarray) – Observed values.

  • predicted (numpy.ndarray) – Predicted values.

  • title (str) – Figure title.

  • flow_label (str) – Units label for volume axis.

Returns:

Plotly Figure with 2 rows.

Return type:

plotly.graph_objects.Figure

plot_data_explorer(df, event_id_col='event_id', datetime_col='datetime', train_event_ids=None, val_event_ids=None, variables=None, rainfall_cols=None, title='Data Explorer')[source]

Interactive multi-panel data explorer with train/validation event highlighting.

One subplot row is created per variable in variables, all sharing the same X-axis. Rainfall columns are rendered as inverted bar charts (bars grow downward); all other variables are rendered as lines. When train_event_ids or val_event_ids are supplied, the corresponding event time spans are shaded in blue and orange respectively.

Parameters:
  • df (pandas.DataFrame) – Input DataFrame containing a datetime column and at least one numeric variable column.

  • event_id_col (str) – Column name that identifies individual events.

  • datetime_col (str) – Column name for the datetime axis.

  • train_event_ids (collections.abc.Iterable or None) – Iterable of event IDs to shade as training data (blue, rgba(0,120,215,0.10)).

  • val_event_ids (collections.abc.Iterable or None) – Iterable of event IDs to shade as validation data (orange, rgba(230,115,0,0.10)).

  • variables (dict[str, tuple[str, str]] or None) – {col_name: (axis_label, units)} mapping describing which columns to plot and how to label them. When None all numeric columns (excluding event_id_col and datetime_col) are included with their column names as labels.

  • rainfall_cols (collections.abc.Iterable[str] or None) – Column names that should be rendered as inverted bar charts (rainfall-style).

  • title (str) – Figure title.

Returns:

Plotly Figure with N rows (one per variable), shared X-axis.

Return type:

plotly.graph_objects.Figure

plot_effective_area(events, fitted_areas=None, calibrated_areas=None, title=None)[source]

Bar chart comparing observed, fitted, and calibrated effective area per event.

Parameters:
  • events (list[EventRecord]) – Source of observed Ae and event duration.

  • fitted_areas (list[float] | None) – Integrated fitted Ae = sum(Q_pred)/sum(rain) per event (SequentialFitSummary.fitted_effective_areas).

  • calibrated_areas (list[float] | None) – Direct calibrated A parameter per event (SequentialFitSummary.calibrated_areas()). For single models this is the A value; for ensembles it is the sum of all component *_A parameters.

  • title (str | None) – Figure title; auto-generated when omitted.

Returns:

Plotly bar-chart Figure of effective area per event.

Return type:

plotly.graph_objects.Figure

plot_ensemble_components(datetime, rainfall, observed, pred_df, aliases, output_name='ensemble_output', pareto_predictions=None, confidence_percentiles=(10, 90), component_labels=None, observed_label='Observed', rainfall_label='Rainfall [mm]', flow_label='Flow', title='Ensemble Components')[source]

Multi-panel figure: rainfall | component signals | combined + Pareto band.

Three rows sharing a common X-axis (two when rainfall is None):

  • Row 1 — Rainfall bars (inverted axis). Omitted when rainfall is None.

  • Row 2 — Individual component signals, one filled-area trace per alias. Components share a common Y-axis so their magnitudes can be compared directly (not stacked).

  • Row 3 — Combined predicted signal (dashed), observed (solid black), and an optional Pareto uncertainty band (shaded IQR between confidence_percentiles). Component outlines (thin dotted) are also repeated here to show each contribution in context.

Parameters:
  • datetime (array-like) – 1-D time axis aligned with observed.

  • rainfall (numpy.ndarray or None) – Rainfall array, or None to omit the top panel.

  • observed (numpy.ndarray) – 1-D observed flow array.

  • pred_df (pandas.DataFrame) – Output of predict(), containing {alias}_output columns and output_name.

  • aliases (list[str]) – List of alias strings (e.g. ["rdii", "seas"]).

  • output_name (str) – Column name for the combined output in pred_df.

  • pareto_predictions (numpy.ndarray or None) – Array of shape (n_solutions, n_timesteps) of combined-output predictions for all Pareto-front solutions. Produced by collect_pareto_predictions(). When supplied, a shaded band is drawn in Row 3.

  • confidence_percentiles (tuple) – (lower_pct, upper_pct) for the band.

  • component_labels (dict or None) – {alias: display_label} overrides. Missing aliases default to the alias string (title-cased).

  • observed_label (str) – Legend label for the observed trace.

  • rainfall_label (str) – Rainfall panel label.

  • flow_label (str) – Y-axis label for component and combined panels.

  • title (str) – Figure title.

Returns:

Plotly Figure with 2–3 rows, shared X-axis.

Return type:

plotly.graph_objects.Figure

plot_ensemble_members_vs_observed(datetime, observed, pred_df, aliases, output_name='ensemble_output', rainfall=None, component_labels=None, observed_label='Observed', rainfall_label='Rainfall [mm]', flow_label='Flow', title='Ensemble Members vs Observed')[source]

Small-multiples grid: each ensemble member vs. the observed target, plus combined.

One row per alias overlays that component’s {alias}_output series with the observed target, followed by a final row for the combined output_name series vs. observed. This differs from plot_ensemble_components(), which overlays members with each other (not against observed) and only shows the combined series vs. observed — here every row repeats the observed trace so each member’s individual fit can be judged directly.

Parameters:
  • datetime (array-like) – 1-D time axis aligned with observed.

  • observed (numpy.ndarray) – 1-D observed flow array.

  • pred_df (pandas.DataFrame) – Output of predict(), containing {alias}_output columns and output_name.

  • aliases (list[str]) – List of alias strings — one row per alias.

  • output_name (str) – Column name for the combined output in pred_df.

  • rainfall (numpy.ndarray or None) – Optional rainfall array for a shared top panel.

  • component_labels (dict or None) – {alias: display_label} overrides. Missing aliases default to the alias string (title-cased).

  • observed_label (str) – Legend label for the observed trace.

  • rainfall_label (str) – Rainfall panel label.

  • flow_label (str) – Y-axis label for all flow panels.

  • title (str) – Figure title.

Returns:

Plotly Figure with one row per member, one combined row, and an optional leading rainfall row — all sharing the X-axis.

Return type:

plotly.graph_objects.Figure

plot_ensemble_timeseries(datetime, rainfall_mm, observed, pred_df, aliases, output_name='ensemble_output', observed_label='Observed', rainfall_label='Rainfall [mm]', title='Ensemble Components')[source]

Two-panel ensemble component breakdown.

Row 1 (25%) — Rainfall bars with an inverted Y-axis. Omitted entirely when rainfall_mm is None.

Row 2 (75%) — Observed flow (black solid line), total predicted (crimson dashed line), and one stacked area per alias showing each component’s individual contribution.

Parameters:
  • datetime (array-like) – Time axis aligned with observed.

  • rainfall_mm (numpy.ndarray or None) – Rainfall depth array, or None to skip the top panel.

  • observed (numpy.ndarray) – 1-D array of observed flow values.

  • pred_df (pandas.DataFrame) – Output of predict() containing {alias}_output columns and the output_name column.

  • aliases (list[str]) – List of alias strings matching the EnsembleModel’s aliases attribute (e.g. ["rdii", "sanitary"]).

  • output_name (str) – Column name for the combined output in pred_df.

  • observed_label (str) – Legend label for the observed trace.

  • rainfall_label (str) – Y-axis label and legend label for rainfall.

  • title (str) – Figure title.

Returns:

Plotly Figure with 1–2 rows.

Return type:

plotly.graph_objects.Figure

plot_event_detection(filter_result, events, title='Event Detection sg_0 with Detected Events')[source]

Single panel: sg_0 + peak markers + event shading.

Parameters:
  • filter_result (FilterResult) – Savitzky-Golay filter output with the sg_0 signal.

  • events (list[EventRecord]) – Detected events to mark and shade.

  • title (str) – Figure title.

Returns:

Single-panel Plotly Figure of sg_0 with event markers.

Return type:

plotly.graph_objects.Figure

plot_filter_signals(filter_result, title='Savitzky-Golay Filter Signals')[source]

Three-panel figure: sg_0, sg_1, sg_2 with threshold lines.

Parameters:
  • filter_result (FilterResult) – Savitzky-Golay filter output with signals and thresholds.

  • title (str) – Figure title.

Returns:

Three-row Plotly Figure of the smoothed signal and derivatives.

Return type:

plotly.graph_objects.Figure

plot_objective_convergence(result, title='Objective Convergence')[source]

Per-objective convergence plot with best-value line and percentile band.

One subplot row per objective. Each row shows:

  • A solid line of the best value achieved at each generation.

  • A shaded 10th–90th percentile band across the Pareto population.

Parameters:
  • result (CalibrationResult) – Calibration result with per-generation history.

  • title (str) – Figure title.

Returns:

Plotly Figure with one row per objective.

Return type:

plotly.graph_objects.Figure

plot_one_to_one_band(observed, predicted, band_pct=10.0, title='1:1 Comparison', observed_label='Observed', predicted_label='Predicted', flow_label='Flow')[source]

CIWEM-style 1:1 scatter with a proportional +/- band tolerance wedge.

Draws the observed-vs-predicted point cloud, a dashed 45 degree “perfect fit” line, and a shaded wedge bounded by y = (1 - band_pct/100)*x and y = (1 + band_pct/100)*x — a band that starts at the origin and widens proportionally with magnitude, per common CIWEM-style flow-model acceptance criteria. This differs from the tolerance_angles option on plot_calibration_timeseries(), which draws angular offsets from the 45 degree line rather than a fixed percentage of the value.

Parameters:
  • observed (numpy.ndarray) – 1-D observed values.

  • predicted (numpy.ndarray) – 1-D predicted values, same length as observed.

  • band_pct (float) – Tolerance band half-width as a percentage of value (e.g. 10.0 draws the wedge between +/-10% of the 1:1 line).

  • title (str) – Figure title.

  • observed_label (str) – X-axis label.

  • predicted_label (str) – Y-axis label.

  • flow_label (str) – Units/quantity label appended to axis titles.

Returns:

Plotly Figure with the 1:1 scatter and tolerance band.

Return type:

plotly.graph_objects.Figure

plot_parallel_coordinates(result, color_by=None, title='Pareto Front Parallel Coordinates', use_final_pareto_only=True)[source]

Parallel-axis trade-off explorer for Pareto solutions.

Each line represents one solution. Axes are the calibrated parameters followed by each objective (in display form). Drag the endpoints of any axis to filter solutions.

Parameters:
  • result (CalibrationResult) – Calibration result.

  • color_by (str or None) – Objective name to use for line colour. Defaults to first objective.

  • title (str) – Figure title.

  • use_final_pareto_only (bool) – Plot only the final Pareto front when True; plot all final-generation solutions when False.

Returns:

Plotly Figure with go.Parcoords trace.

Return type:

plotly.graph_objects.Figure

plot_parameter_distributions(result, use_final_pareto_only=True, title='Parameter Distributions (Pareto Solutions)')[source]

Grid of violin plots showing the spread of calibrated parameters.

Each violin shows the distribution of a parameter across Pareto solutions, with a box-and-whisker overlay and a jittered scatter of individual points.

Parameters:
  • result (CalibrationResult) – Calibration result.

  • use_final_pareto_only (bool) – Use only the final Pareto front when True; use all history solutions when False.

  • title (str) – Figure title.

Returns:

Plotly Figure with a grid of violin traces.

Return type:

plotly.graph_objects.Figure

plot_parameter_evolution(summary, title='Parameter Evolution Across Fitted Events')[source]

One subplot per shape parameter, colored by NSE with rolling mean.

Parameters:
Returns:

Plotly Figure with one subplot per shape parameter.

Return type:

plotly.graph_objects.Figure

plot_pareto_evolution(result, x_obj=0, y_obj=1, title='Pareto Front Evolution')[source]

Animated scatter showing all solutions and the Pareto front per generation.

A slider at the bottom navigates between generations. A Play/Pause button animates the evolution automatically.

Parameters:
  • result (CalibrationResult) – Calibration result with per-generation history.

  • x_obj (int or str) – X-axis objective — zero-based index or objective name.

  • y_obj (int or str) – Y-axis objective — zero-based index or objective name.

  • title (str) – Figure title.

Returns:

Plotly Figure with animation frames and slider.

Return type:

plotly.graph_objects.Figure

plot_pareto_scatter_matrix(result, title='Pareto Scatter Matrix')[source]

Scatter-plot matrix (SPLOM) of all objectives.

Each off-diagonal cell is a scatter of one objective vs another. Points are coloured by the first objective. Useful for exploring trade-off structure when there are three or more objectives.

Parameters:
Returns:

Plotly Figure with go.Splom trace.

Return type:

plotly.graph_objects.Figure

plot_rainfall_flow_with_events(rain_stormflow, events, title='Rainfall and Stormflow with Detected Events', rain_label='Rainfall (mm/hr)', flow_label='Stormflow (cfs)')[source]

Two-panel timeseries: top = inverted rainfall bars, bottom = stormflow.

Transparent colored bands highlight each event on both panels.

Parameters:
  • rain_stormflow (pandas.DataFrame) – Frame with datetime, rain, stormflow.

  • events (list[EventRecord]) – Detected events to highlight.

  • title (str) – Figure title.

  • rain_label (str) – Y-axis label for the rainfall panel.

  • flow_label (str) – Y-axis label for the stormflow panel.

Returns:

Two-row Plotly Figure with rainfall and stormflow panels.

Return type:

plotly.graph_objects.Figure

plot_rdii_components(result_df, title='RDII Components', rainfall_label='Rainfall [mm]')[source]

Stacked RDII component traces alongside rainfall.

The DataFrame must contain a datetime column (or similar time index) and any number of columns named rdii_component_N (N = 0, 1, 2, …). A rainfall_mm column is optional; if absent, no rainfall panel is shown.

Parameters:
  • result_df (pandas.DataFrame) – DataFrame produced by an RDIIModel run. Must contain rdii_component_N columns.

  • title (str) – Figure title.

  • rainfall_label (str) – Y-axis label for the rainfall panel.

Returns:

Plotly Figure with 2 rows (rainfall + stacked components) when rainfall is available, or 1 row otherwise.

Return type:

plotly.graph_objects.Figure

plot_residuals_scatter(datetime, observed, predicted, title='Residual Diagnostics', flow_label='Flow')[source]

Three-panel residual diagnostic plot.

Row 1 — Observed vs predicted scatter with a 1:1 diagonal line.

Row 2 — Residual (observed − predicted) bar chart, coloured red (over-prediction) / blue (under-prediction).

Row 3 — Residual autocorrelation bars at lags 0–30, showing systematic bias structure.

Parameters:
  • datetime (array-like) – Time axis for the residual bar chart.

  • observed (numpy.ndarray) – Observed values.

  • predicted (numpy.ndarray) – Predicted values.

  • title (str) – Figure title.

  • flow_label (str) – Axis label used for observed / predicted axes.

Returns:

Plotly Figure with 3 rows.

Return type:

plotly.graph_objects.Figure

plot_rtk_shape(triangles, dt_hours=1.0, title='RTK Unit Hydrograph Shapes')[source]

Plot the triangular unit hydrograph shape for each RTKTriangle.

Useful for sanity-checking T (time-to-peak) and K (recession ratio) before calibration.

Parameters:
Returns:

Plotly Figure — one filled trace per triangle.

Return type:

plotly.graph_objects.Figure

plot_sensitivity_heatmap(result, title='Parameter–Objective Sensitivity (Pearson r)')[source]

Heatmap of absolute Pearson correlation between parameters and objectives.

Rows = objectives, columns = parameters. Cell colour = Pearson r on a RdBu diverging colorscale centred at 0. Numeric annotation on each cell.

Parameters:
Returns:

Plotly Figure with go.Heatmap trace.

Return type:

plotly.graph_objects.Figure

plot_sequential_fit(summary, rain_stormflow, events=None, title='Sequential Unit Hydrograph Fitting')[source]

Three-row panel: rainfall / observed+predicted / residual.

Parameters:
Returns:

Three-row Plotly Figure with rainfall, flow, and residual panels.

Return type:

plotly.graph_objects.Figure

plot_splom(result, space='objectives', title='SPLOM Non-Dominated Solutions Highlighted')[source]

Scatter-plot matrix highlighting non-dominated vs dominated solutions.

Draws the full final-generation population as a SPLOM. Dominated solutions are shown in grey at low opacity; non-dominated (Pareto-front) solutions are overlaid in orange at full opacity.

Parameters:
  • result (CalibrationResult) – Calibration result with per-generation history.

  • space (str) – Which dimensions to display — "objectives" (default) or "parameters".

  • title (str) – Figure title.

Returns:

Plotly Figure with two go.Splom traces.

Return type:

plotly.graph_objects.Figure

Raises:

ValueError – If space is not "objectives" or "parameters".

plot_timeseries(datetime, rainfall_mm, observed_flow, predicted_flow, title='Model Time Series', rainfall_label='Rainfall [mm]', flow_label='Flow')[source]

Dual-axis time series: rainfall (top) and flow (bottom).

The rainfall subplot uses an inverted Y-axis (bars grow downward) and shares the X-axis with the flow subplot.

Parameters:
  • datetime (array-like) – Time axis values (array-like of dates or timestamps).

  • rainfall_mm (numpy.ndarray) – Rainfall depth per time step [mm].

  • observed_flow (array-like or None) – Observed flow values, or None to omit.

  • predicted_flow (numpy.ndarray) – Model-predicted output [same units as observed].

  • title (str) – Figure title.

  • rainfall_label (str) – Y-axis label for the rainfall panel.

  • flow_label (str) – Y-axis label for the flow panel.

Returns:

Plotly Figure with 2 rows, shared X-axis.

Return type:

plotly.graph_objects.Figure

Time-Series Plots#

Time-domain interactive plots and VisualizationModel.

Public API (all conditional on plotly being installed):

class VisualizationModel(title='Model Time Series', rainfall_label='Rainfall [mm]', flow_label='Flow')[source]#

Bases: IModel

General-purpose visualization model for any IModel output.

Wraps plot_timeseries(), plot_pareto_evolution(), and plot_parallel_coordinates() behind the standard IModel lifecycle.

Column names for the input DataFrame are specified at prepare() time, making this model compatible with any model’s output format.

predict() returns the input DataFrame unchanged so the model can be composed in a pipeline. Figures are available as read-only properties afterward:

viz.timeseries_figure    # always generated
viz.pareto_figure        # generated when calibration_result is supplied
viz.parallel_figure      # generated when calibration_result is supplied
Parameters:
  • title (str) – Base title used across all figures.

  • rainfall_label (str) – Y-axis label for the rainfall panel.

  • flow_label (str) – Y-axis label for the flow panel.

apply_flat_parameter(name, value)#

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)#

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]#

Release stored data and figures and advance to FINALIZED.

get_output_field(name)#

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)#

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)#

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()#

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

initialize()[source]#

Advance to INITIALIZED.

is_created()#

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()#

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()#

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()#

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()#

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()#

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()#

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()#

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict()[source]#

Generate all applicable figures and return the input DataFrame.

Returns:

The DataFrame supplied to prepare() (unchanged).

Raises:

RuntimeError – If prepare() has not been called.

Return type:

DataFrame

prepare(data, datetime_col='datetime', predicted_col='predicted', observed_col=None, rainfall_col=None, calibration_result=None)[source]#

Load model output data and configure column mapping.

Parameters:
  • data (pandas.DataFrame) – Any model’s output DataFrame.

  • datetime_col (str) – Column name for the time axis.

  • predicted_col (str) – Column name for the predicted output signal.

  • observed_col (str or None) – Column name for observed data, or None to omit.

  • rainfall_col (str or None) – Column name for rainfall forcing, or None to omit.

  • calibration_result (CalibrationResult or None) – When provided, predict() also generates Pareto-evolution and parallel-coordinates figures.

Raises:

ValueError – If required columns are absent.

read_flat_parameter(name)#

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)#

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)#

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)#

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)#

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)#

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)#

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]#

Validate and advance to VALIDATED.

Returns:

Always True.

Return type:

bool

property calibratable_output_names: list[str]#

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]#

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]#

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name = 'visualization'#

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]#

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]#

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property parallel_figure: go.Figure | None#

Parallel-coordinates trade-off explorer, or None when no result was supplied.

property pareto_figure: go.Figure | None#

Animated Pareto-front evolution, or None when no result was supplied.

property scalar_parameter_names: list[str]#

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState#

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property timeseries_figure: go.Figure | None#

Dual-axis rainfall/flow time series, or None before predict().

property vector_parameter_names: list[str]#

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

plot_calibration_timeseries(datetime, observed, predicted, exogenous=None, pareto_predictions=None, confidence_percentiles=(25, 75), tolerance_angles=None, rainfall_label='Rainfall', observed_label='Observed', predicted_label='Predicted', title='Calibration Time Series')[source]#

Two-row calibration dashboard with linked time axes.

Row 1 (full width) — Exogenous inputs. Every entry in exogenous is normalised to [0, 1] and overlaid on a single shared y-axis. The legend label for each trace includes the original value range and units (e.g. Rainfall [0-12.3 mm]). Traces whose label contains “rain” or “precip” (case-insensitive) are rendered as bars; everything else is a line.

Row 2 Left — Predicted vs Observed time series. If pareto_predictions is supplied, a shaded IQR band (between confidence_percentiles) is drawn around the predicted line.

Row 2 Right — 1v1 scatter of observed vs predicted. When pareto_predictions is supplied, vertical box-whiskers summarise the Pareto range at each time step. A dashed 45° “perfect fit” line is always drawn. Optional tolerance_angles draw additional lines radiating from the origin at 45° +/- theta.

The x-axes of row 1 and row 2-left are linked: zooming or panning either panel pans the other.

Parameters:
  • datetime (array-like) – 1-D datetime-like array aligned with observed / predicted.

  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (best solution).

  • exogenous (dict[str, tuple[numpy.ndarray, str]] or None) – {label: (values_array, units_string)} mapping. All traces are normalised to [0, 1] on a shared y-axis. Rainfall-like traces (label contains “rain” / “precip”) are plotted as bars.

  • pareto_predictions (numpy.ndarray or None) – Array of shape (n_solutions, n_timesteps) containing all Pareto-front predictions. Used for the IQR band and scatter box-whiskers.

  • confidence_percentiles (tuple) – (lower_pct, upper_pct) for the IQR band.

  • tolerance_angles (list[float] or None) – Angles in degrees from the 45° line. For each θ two lines are drawn at slopes tan(45° ± θ).

  • rainfall_label (str) – String to match when auto-detecting rainfall traces.

  • observed_label (str) – Legend label for the observed trace.

  • predicted_label (str) – Legend label for the predicted trace.

  • title (str) – Figure title.

Returns:

Plotly Figure.

Return type:

plotly.graph_objects.Figure

plot_cumulative_volume(datetime, observed, predicted, title='Cumulative Volume', flow_label='Flow')[source]#

Two-panel cumulative volume comparison.

Row 1 — Cumulative sums of observed and predicted with a shaded fill between the two lines, highlighting volume discrepancy.

Row 2 — Cumulative volume error (obs_cumsum − pred_cumsum) with a zero-reference line.

Parameters:
  • datetime (array-like) – Time axis values.

  • observed (numpy.ndarray) – Observed values.

  • predicted (numpy.ndarray) – Predicted values.

  • title (str) – Figure title.

  • flow_label (str) – Units label for volume axis.

Returns:

Plotly Figure with 2 rows.

Return type:

plotly.graph_objects.Figure

plot_data_explorer(df, event_id_col='event_id', datetime_col='datetime', train_event_ids=None, val_event_ids=None, variables=None, rainfall_cols=None, title='Data Explorer')[source]#

Interactive multi-panel data explorer with train/validation event highlighting.

One subplot row is created per variable in variables, all sharing the same X-axis. Rainfall columns are rendered as inverted bar charts (bars grow downward); all other variables are rendered as lines. When train_event_ids or val_event_ids are supplied, the corresponding event time spans are shaded in blue and orange respectively.

Parameters:
  • df (pandas.DataFrame) – Input DataFrame containing a datetime column and at least one numeric variable column.

  • event_id_col (str) – Column name that identifies individual events.

  • datetime_col (str) – Column name for the datetime axis.

  • train_event_ids (collections.abc.Iterable or None) – Iterable of event IDs to shade as training data (blue, rgba(0,120,215,0.10)).

  • val_event_ids (collections.abc.Iterable or None) – Iterable of event IDs to shade as validation data (orange, rgba(230,115,0,0.10)).

  • variables (dict[str, tuple[str, str]] or None) – {col_name: (axis_label, units)} mapping describing which columns to plot and how to label them. When None all numeric columns (excluding event_id_col and datetime_col) are included with their column names as labels.

  • rainfall_cols (collections.abc.Iterable[str] or None) – Column names that should be rendered as inverted bar charts (rainfall-style).

  • title (str) – Figure title.

Returns:

Plotly Figure with N rows (one per variable), shared X-axis.

Return type:

plotly.graph_objects.Figure

plot_ensemble_components(datetime, rainfall, observed, pred_df, aliases, output_name='ensemble_output', pareto_predictions=None, confidence_percentiles=(10, 90), component_labels=None, observed_label='Observed', rainfall_label='Rainfall [mm]', flow_label='Flow', title='Ensemble Components')[source]#

Multi-panel figure: rainfall | component signals | combined + Pareto band.

Three rows sharing a common X-axis (two when rainfall is None):

  • Row 1 — Rainfall bars (inverted axis). Omitted when rainfall is None.

  • Row 2 — Individual component signals, one filled-area trace per alias. Components share a common Y-axis so their magnitudes can be compared directly (not stacked).

  • Row 3 — Combined predicted signal (dashed), observed (solid black), and an optional Pareto uncertainty band (shaded IQR between confidence_percentiles). Component outlines (thin dotted) are also repeated here to show each contribution in context.

Parameters:
  • datetime (array-like) – 1-D time axis aligned with observed.

  • rainfall (numpy.ndarray or None) – Rainfall array, or None to omit the top panel.

  • observed (numpy.ndarray) – 1-D observed flow array.

  • pred_df (pandas.DataFrame) – Output of predict(), containing {alias}_output columns and output_name.

  • aliases (list[str]) – List of alias strings (e.g. ["rdii", "seas"]).

  • output_name (str) – Column name for the combined output in pred_df.

  • pareto_predictions (numpy.ndarray or None) – Array of shape (n_solutions, n_timesteps) of combined-output predictions for all Pareto-front solutions. Produced by collect_pareto_predictions(). When supplied, a shaded band is drawn in Row 3.

  • confidence_percentiles (tuple) – (lower_pct, upper_pct) for the band.

  • component_labels (dict or None) – {alias: display_label} overrides. Missing aliases default to the alias string (title-cased).

  • observed_label (str) – Legend label for the observed trace.

  • rainfall_label (str) – Rainfall panel label.

  • flow_label (str) – Y-axis label for component and combined panels.

  • title (str) – Figure title.

Returns:

Plotly Figure with 2–3 rows, shared X-axis.

Return type:

plotly.graph_objects.Figure

plot_ensemble_members_vs_observed(datetime, observed, pred_df, aliases, output_name='ensemble_output', rainfall=None, component_labels=None, observed_label='Observed', rainfall_label='Rainfall [mm]', flow_label='Flow', title='Ensemble Members vs Observed')[source]#

Small-multiples grid: each ensemble member vs. the observed target, plus combined.

One row per alias overlays that component’s {alias}_output series with the observed target, followed by a final row for the combined output_name series vs. observed. This differs from plot_ensemble_components(), which overlays members with each other (not against observed) and only shows the combined series vs. observed — here every row repeats the observed trace so each member’s individual fit can be judged directly.

Parameters:
  • datetime (array-like) – 1-D time axis aligned with observed.

  • observed (numpy.ndarray) – 1-D observed flow array.

  • pred_df (pandas.DataFrame) – Output of predict(), containing {alias}_output columns and output_name.

  • aliases (list[str]) – List of alias strings — one row per alias.

  • output_name (str) – Column name for the combined output in pred_df.

  • rainfall (numpy.ndarray or None) – Optional rainfall array for a shared top panel.

  • component_labels (dict or None) – {alias: display_label} overrides. Missing aliases default to the alias string (title-cased).

  • observed_label (str) – Legend label for the observed trace.

  • rainfall_label (str) – Rainfall panel label.

  • flow_label (str) – Y-axis label for all flow panels.

  • title (str) – Figure title.

Returns:

Plotly Figure with one row per member, one combined row, and an optional leading rainfall row — all sharing the X-axis.

Return type:

plotly.graph_objects.Figure

plot_ensemble_timeseries(datetime, rainfall_mm, observed, pred_df, aliases, output_name='ensemble_output', observed_label='Observed', rainfall_label='Rainfall [mm]', title='Ensemble Components')[source]#

Two-panel ensemble component breakdown.

Row 1 (25%) — Rainfall bars with an inverted Y-axis. Omitted entirely when rainfall_mm is None.

Row 2 (75%) — Observed flow (black solid line), total predicted (crimson dashed line), and one stacked area per alias showing each component’s individual contribution.

Parameters:
  • datetime (array-like) – Time axis aligned with observed.

  • rainfall_mm (numpy.ndarray or None) – Rainfall depth array, or None to skip the top panel.

  • observed (numpy.ndarray) – 1-D array of observed flow values.

  • pred_df (pandas.DataFrame) – Output of predict() containing {alias}_output columns and the output_name column.

  • aliases (list[str]) – List of alias strings matching the EnsembleModel’s aliases attribute (e.g. ["rdii", "sanitary"]).

  • output_name (str) – Column name for the combined output in pred_df.

  • observed_label (str) – Legend label for the observed trace.

  • rainfall_label (str) – Y-axis label and legend label for rainfall.

  • title (str) – Figure title.

Returns:

Plotly Figure with 1–2 rows.

Return type:

plotly.graph_objects.Figure

plot_one_to_one_band(observed, predicted, band_pct=10.0, title='1:1 Comparison', observed_label='Observed', predicted_label='Predicted', flow_label='Flow')[source]#

CIWEM-style 1:1 scatter with a proportional +/- band tolerance wedge.

Draws the observed-vs-predicted point cloud, a dashed 45 degree “perfect fit” line, and a shaded wedge bounded by y = (1 - band_pct/100)*x and y = (1 + band_pct/100)*x — a band that starts at the origin and widens proportionally with magnitude, per common CIWEM-style flow-model acceptance criteria. This differs from the tolerance_angles option on plot_calibration_timeseries(), which draws angular offsets from the 45 degree line rather than a fixed percentage of the value.

Parameters:
  • observed (numpy.ndarray) – 1-D observed values.

  • predicted (numpy.ndarray) – 1-D predicted values, same length as observed.

  • band_pct (float) – Tolerance band half-width as a percentage of value (e.g. 10.0 draws the wedge between +/-10% of the 1:1 line).

  • title (str) – Figure title.

  • observed_label (str) – X-axis label.

  • predicted_label (str) – Y-axis label.

  • flow_label (str) – Units/quantity label appended to axis titles.

Returns:

Plotly Figure with the 1:1 scatter and tolerance band.

Return type:

plotly.graph_objects.Figure

plot_residuals_scatter(datetime, observed, predicted, title='Residual Diagnostics', flow_label='Flow')[source]#

Three-panel residual diagnostic plot.

Row 1 — Observed vs predicted scatter with a 1:1 diagonal line.

Row 2 — Residual (observed − predicted) bar chart, coloured red (over-prediction) / blue (under-prediction).

Row 3 — Residual autocorrelation bars at lags 0–30, showing systematic bias structure.

Parameters:
  • datetime (array-like) – Time axis for the residual bar chart.

  • observed (numpy.ndarray) – Observed values.

  • predicted (numpy.ndarray) – Predicted values.

  • title (str) – Figure title.

  • flow_label (str) – Axis label used for observed / predicted axes.

Returns:

Plotly Figure with 3 rows.

Return type:

plotly.graph_objects.Figure

plot_timeseries(datetime, rainfall_mm, observed_flow, predicted_flow, title='Model Time Series', rainfall_label='Rainfall [mm]', flow_label='Flow')[source]#

Dual-axis time series: rainfall (top) and flow (bottom).

The rainfall subplot uses an inverted Y-axis (bars grow downward) and shares the X-axis with the flow subplot.

Parameters:
  • datetime (array-like) – Time axis values (array-like of dates or timestamps).

  • rainfall_mm (numpy.ndarray) – Rainfall depth per time step [mm].

  • observed_flow (array-like or None) – Observed flow values, or None to omit.

  • predicted_flow (numpy.ndarray) – Model-predicted output [same units as observed].

  • title (str) – Figure title.

  • rainfall_label (str) – Y-axis label for the rainfall panel.

  • flow_label (str) – Y-axis label for the flow panel.

Returns:

Plotly Figure with 2 rows, shared X-axis.

Return type:

plotly.graph_objects.Figure

Calibration Result Plots#

Calibration result and optimizer interactive plots.

Public API (all conditional on plotly being installed):

plot_objective_convergence(result, title='Objective Convergence')[source]#

Per-objective convergence plot with best-value line and percentile band.

One subplot row per objective. Each row shows:

  • A solid line of the best value achieved at each generation.

  • A shaded 10th–90th percentile band across the Pareto population.

Parameters:
  • result (CalibrationResult) – Calibration result with per-generation history.

  • title (str) – Figure title.

Returns:

Plotly Figure with one row per objective.

Return type:

plotly.graph_objects.Figure

plot_parallel_coordinates(result, color_by=None, title='Pareto Front Parallel Coordinates', use_final_pareto_only=True)[source]#

Parallel-axis trade-off explorer for Pareto solutions.

Each line represents one solution. Axes are the calibrated parameters followed by each objective (in display form). Drag the endpoints of any axis to filter solutions.

Parameters:
  • result (CalibrationResult) – Calibration result.

  • color_by (str or None) – Objective name to use for line colour. Defaults to first objective.

  • title (str) – Figure title.

  • use_final_pareto_only (bool) – Plot only the final Pareto front when True; plot all final-generation solutions when False.

Returns:

Plotly Figure with go.Parcoords trace.

Return type:

plotly.graph_objects.Figure

plot_parameter_distributions(result, use_final_pareto_only=True, title='Parameter Distributions (Pareto Solutions)')[source]#

Grid of violin plots showing the spread of calibrated parameters.

Each violin shows the distribution of a parameter across Pareto solutions, with a box-and-whisker overlay and a jittered scatter of individual points.

Parameters:
  • result (CalibrationResult) – Calibration result.

  • use_final_pareto_only (bool) – Use only the final Pareto front when True; use all history solutions when False.

  • title (str) – Figure title.

Returns:

Plotly Figure with a grid of violin traces.

Return type:

plotly.graph_objects.Figure

plot_pareto_evolution(result, x_obj=0, y_obj=1, title='Pareto Front Evolution')[source]#

Animated scatter showing all solutions and the Pareto front per generation.

A slider at the bottom navigates between generations. A Play/Pause button animates the evolution automatically.

Parameters:
  • result (CalibrationResult) – Calibration result with per-generation history.

  • x_obj (int or str) – X-axis objective — zero-based index or objective name.

  • y_obj (int or str) – Y-axis objective — zero-based index or objective name.

  • title (str) – Figure title.

Returns:

Plotly Figure with animation frames and slider.

Return type:

plotly.graph_objects.Figure

plot_pareto_scatter_matrix(result, title='Pareto Scatter Matrix')[source]#

Scatter-plot matrix (SPLOM) of all objectives.

Each off-diagonal cell is a scatter of one objective vs another. Points are coloured by the first objective. Useful for exploring trade-off structure when there are three or more objectives.

Parameters:
Returns:

Plotly Figure with go.Splom trace.

Return type:

plotly.graph_objects.Figure

plot_sensitivity_heatmap(result, title='Parameter–Objective Sensitivity (Pearson r)')[source]#

Heatmap of absolute Pearson correlation between parameters and objectives.

Rows = objectives, columns = parameters. Cell colour = Pearson r on a RdBu diverging colorscale centred at 0. Numeric annotation on each cell.

Parameters:
Returns:

Plotly Figure with go.Heatmap trace.

Return type:

plotly.graph_objects.Figure

plot_splom(result, space='objectives', title='SPLOM Non-Dominated Solutions Highlighted')[source]#

Scatter-plot matrix highlighting non-dominated vs dominated solutions.

Draws the full final-generation population as a SPLOM. Dominated solutions are shown in grey at low opacity; non-dominated (Pareto-front) solutions are overlaid in orange at full opacity.

Parameters:
  • result (CalibrationResult) – Calibration result with per-generation history.

  • space (str) – Which dimensions to display — "objectives" (default) or "parameters".

  • title (str) – Figure title.

Returns:

Plotly Figure with two go.Splom traces.

Return type:

plotly.graph_objects.Figure

Raises:

ValueError – If space is not "objectives" or "parameters".

RDII-Specific Plots#

RDII / RTK-specific interactive plots.

Public API (all conditional on plotly being installed):

plot_rdii_components(result_df, title='RDII Components', rainfall_label='Rainfall [mm]')[source]#

Stacked RDII component traces alongside rainfall.

The DataFrame must contain a datetime column (or similar time index) and any number of columns named rdii_component_N (N = 0, 1, 2, …). A rainfall_mm column is optional; if absent, no rainfall panel is shown.

Parameters:
  • result_df (pandas.DataFrame) – DataFrame produced by an RDIIModel run. Must contain rdii_component_N columns.

  • title (str) – Figure title.

  • rainfall_label (str) – Y-axis label for the rainfall panel.

Returns:

Plotly Figure with 2 rows (rainfall + stacked components) when rainfall is available, or 1 row otherwise.

Return type:

plotly.graph_objects.Figure

plot_rtk_shape(triangles, dt_hours=1.0, title='RTK Unit Hydrograph Shapes')[source]#

Plot the triangular unit hydrograph shape for each RTKTriangle.

Useful for sanity-checking T (time-to-peak) and K (recession ratio) before calibration.

Parameters:
Returns:

Plotly Figure — one filled trace per triangle.

Return type:

plotly.graph_objects.Figure

Calibration Dashboard#

Multi-panel calibration dashboard — pure Plotly HTML, no server required.

Single public function:

plot_calibration_dashboard(result, timeseries_df=None, datetime_col='datetime', predicted_col='predicted', observed_col=None, rainfall_col=None, flow_label='Flow', title='Calibration Dashboard', output_path=None, use_cdn=True)[source]#

Build a multi-panel calibration dashboard and write it to an HTML file.

Because plotly.graph_objects.Frame objects (used by plot_pareto_evolution()) and go.Parcoords traces cannot be embedded in a shared make_subplots grid, each sub-figure is serialised individually with plotly.io.to_html(full_html=False) and the sections are joined in an HTML template with a single Plotly CDN <script> tag.

Panels (shown when data is available):

  1. Time series — if timeseries_df is supplied.

  2. Objective convergence — always shown.

  3. Pareto front evolution (animated) — requires ≥ 1 history record.

  4. Parameter distributions — always shown.

  5. Parallel coordinates — always shown.

Parameters:
  • result (CalibrationResult) – Calibration result.

  • timeseries_df (pandas.DataFrame or None) – Optional model-output DataFrame.

  • datetime_col (str) – Datetime column name in timeseries_df.

  • predicted_col (str) – Predicted-flow column name in timeseries_df.

  • observed_col (str or None) – Observed-flow column name, or None to omit.

  • rainfall_col (str or None) – Rainfall column name, or None to omit zeros.

  • flow_label (str) – Y-axis label for flow panels.

  • title (str) – Dashboard heading.

  • output_path (str or None) – File path for the HTML output. Pass None to skip writing.

  • use_cdn (bool) – Include Plotly via CDN <script> tag when True; inline the full Plotly bundle when False (larger file, fully offline).

Returns:

The objective-convergence figure (for interactive notebook use; the full dashboard is only available in the HTML file).

Return type:

plotly.graph_objects.Figure

Unit Hydrograph Plots#

Six interactive Plotly figures for the sequential UH fitting workflow. All functions return plotly.graph_objects.Figure and are importable directly from sparsehydro.visualization or the top-level namespace.

Function

Description

plot_rainfall_flow_with_events()

Two-panel timeseries with event shading bands

plot_filter_signals()

sg_0 / sg_1 / sg_2 with threshold lines

plot_event_detection()

sg_0 + peak markers + event shading

plot_sequential_fit()

Rainfall / obs+pred / residual three-row panel

plot_parameter_evolution()

Fitted params over time, colored by NSE

plot_effective_area()

Bar chart of effective area per event

Plotly visualizations specific to unit hydrograph analysis.

Extends sparsehydro.visualization with six figure builders for the sequential UH fitting workflow. All functions return plotly.graph_objects.Figure.

Functions#

plot_effective_area(events, fitted_areas=None, calibrated_areas=None, title=None)[source]#

Bar chart comparing observed, fitted, and calibrated effective area per event.

Parameters:
  • events (list[EventRecord]) – Source of observed Ae and event duration.

  • fitted_areas (list[float] | None) – Integrated fitted Ae = sum(Q_pred)/sum(rain) per event (SequentialFitSummary.fitted_effective_areas).

  • calibrated_areas (list[float] | None) – Direct calibrated A parameter per event (SequentialFitSummary.calibrated_areas()). For single models this is the A value; for ensembles it is the sum of all component *_A parameters.

  • title (str | None) – Figure title; auto-generated when omitted.

Returns:

Plotly bar-chart Figure of effective area per event.

Return type:

plotly.graph_objects.Figure

plot_event_detection(filter_result, events, title='Event Detection sg_0 with Detected Events')[source]#

Single panel: sg_0 + peak markers + event shading.

Parameters:
  • filter_result (FilterResult) – Savitzky-Golay filter output with the sg_0 signal.

  • events (list[EventRecord]) – Detected events to mark and shade.

  • title (str) – Figure title.

Returns:

Single-panel Plotly Figure of sg_0 with event markers.

Return type:

plotly.graph_objects.Figure

plot_filter_signals(filter_result, title='Savitzky-Golay Filter Signals')[source]#

Three-panel figure: sg_0, sg_1, sg_2 with threshold lines.

Parameters:
  • filter_result (FilterResult) – Savitzky-Golay filter output with signals and thresholds.

  • title (str) – Figure title.

Returns:

Three-row Plotly Figure of the smoothed signal and derivatives.

Return type:

plotly.graph_objects.Figure

plot_parameter_evolution(summary, title='Parameter Evolution Across Fitted Events')[source]#

One subplot per shape parameter, colored by NSE with rolling mean.

Parameters:
Returns:

Plotly Figure with one subplot per shape parameter.

Return type:

plotly.graph_objects.Figure

plot_rainfall_flow_with_events(rain_stormflow, events, title='Rainfall and Stormflow with Detected Events', rain_label='Rainfall (mm/hr)', flow_label='Stormflow (cfs)')[source]#

Two-panel timeseries: top = inverted rainfall bars, bottom = stormflow.

Transparent colored bands highlight each event on both panels.

Parameters:
  • rain_stormflow (pandas.DataFrame) – Frame with datetime, rain, stormflow.

  • events (list[EventRecord]) – Detected events to highlight.

  • title (str) – Figure title.

  • rain_label (str) – Y-axis label for the rainfall panel.

  • flow_label (str) – Y-axis label for the stormflow panel.

Returns:

Two-row Plotly Figure with rainfall and stormflow panels.

Return type:

plotly.graph_objects.Figure

plot_sequential_fit(summary, rain_stormflow, events=None, title='Sequential Unit Hydrograph Fitting')[source]#

Three-row panel: rainfall / observed+predicted / residual.

Parameters:
Returns:

Three-row Plotly Figure with rainfall, flow, and residual panels.

Return type:

plotly.graph_objects.Figure


Stormflow Analysis#

Savitzky-Golay filtering and derivative-based event detection used by the sequential UH fitting workflow.

Filters#

apply_savgol_filter produces three aligned signals from a raw stormflow series. compute_thresholds attaches percentile-based detection thresholds in a single immutable update step.

from sparsehydro import apply_savgol_filter, compute_thresholds

fr = apply_savgol_filter(rain_stormflow_df, window_length=48)
fr = compute_thresholds(fr, sg_0_per=0.15, sg_1_per=0.25, sg_2_per=0.25)
print(fr.thresholds)   # {'sg_0_th': ..., 'sg_1_th': ..., 'sg_2_th': ...}

sparsehydro.filters — Savitzky-Golay filtering for stormflow preprocessing.

Provides a self-contained pipeline for smoothing raw stormflow and computing derivative signals used by the event-detection algorithm in sparsehydro.events.

Public API#

Quick start:

from sparsehydro.filters import apply_savgol_filter, compute_thresholds

result = apply_savgol_filter(rain_stormflow_df, window_length=48)
result = compute_thresholds(result, sg_0_per=0.15, sg_1_per=0.25, sg_2_per=0.25)
print(result.thresholds)
class DryWeatherResult(datetime, flow, smoothed, pattern, baseflow, stormflow, outliers, pattern_name, weekly_patterns=<factory>, points_per_day=0)[source]#

Bases: object

Container for the output of disaggregate_dry_weather().

Variables:
  • datetime (pandas.Series) – Timestamps of the (regularised) series.

  • flow (numpy.ndarray) – Observed flow after missing-value handling.

  • smoothed (numpy.ndarray) – Savitzky-Golay smoothed flow used to build the pattern.

  • pattern (numpy.ndarray) – Per-point base series from the selected weekly pattern before GWI correction (the MATLAB RawBaseFlow).

  • baseflow (numpy.ndarray) – Corrected baseflow (pattern plus interpolated GWI correction).

  • stormflow (numpy.ndarray) – flow - baseflow.

  • outliers (numpy.ndarray) – Boolean mask of storm-affected (outlier) points.

  • pattern_name (str) – Key of the selected weekly pattern (see PATTERN_NAMES).

  • weekly_patterns (dict) – The four candidate weekly patterns as points_per_week-length arrays.

  • points_per_day (int) – Number of samples per day inferred from the timestamps.

to_dataframe()[source]#

Return the disaggregation results as a tidy pandas.DataFrame.

Returns:

Frame with columns datetime, flow, smoothed, pattern, baseflow, stormflow, outlier.

Return type:

pandas.DataFrame

baseflow: ndarray#
datetime: Series#
flow: ndarray#
outliers: ndarray#
pattern: ndarray#
pattern_name: str#
points_per_day: int = 0#
smoothed: ndarray#
stormflow: ndarray#
weekly_patterns: dict[str, ndarray]#
class FilterResult(datetime, raw_flow, sg_0, sg_1, sg_2, thresholds=<factory>)[source]#

Bases: object

Output of apply_savgol_filter().

Variables:
  • datetime (pandas.Series) – Timestamps aligned to the stormflow input.

  • raw_flow (numpy.ndarray) – Original stormflow values (clipped to ≥ 0).

  • sg_0 (numpy.ndarray) – Smoothed signal (Savitzky-Golay 0th-order output).

  • sg_1 (numpy.ndarray) – First derivative of the smoothed signal (slope).

  • sg_2 (numpy.ndarray) – Second derivative of the smoothed signal (curvature).

  • thresholds (dict[str, float]) – Populated by compute_thresholds(). Keys: "sg_0_th", "sg_1_th", "sg_2_th".

to_dataframe()[source]#

Return a DataFrame with columns datetime, raw_flow, sg_0, sg_1, sg_2.

Returns:

Tidy frame combining the timestamps and signal arrays.

Return type:

pandas.DataFrame

datetime: Series#
raw_flow: ndarray#
sg_0: ndarray#
sg_1: ndarray#
sg_2: ndarray#
thresholds: dict[str, float]#
apply_savgol_filter(rain_stormflow, window_length=48, polyorder=2, deriv_factor=1.2)[source]#

Apply Savitzky-Golay smoothing and compute derivative signals.

Parameters:
  • rain_stormflow (pandas.DataFrame) – Must contain columns datetime, rain, stormflow.

  • window_length (int) – Base window for the sg_0 smoother. Windows for sg_1 and sg_2 are scaled by successive powers of deriv_factor.

  • polyorder (int) – Polynomial order for all filter passes.

  • deriv_factor (float) – Multiplier applied to the window length for each derivative pass.

Returns:

Arrays of the same length as rain_stormflow; thresholds is empty until compute_thresholds() is called.

Return type:

FilterResult

compute_thresholds(result, sg_0_per=0.15, sg_1_per=0.25, sg_2_per=0.25)[source]#

Attach percentile-based detection thresholds to result.

Parameters:
  • result (FilterResult) – Output of apply_savgol_filter().

  • sg_0_per (float) – sg_0_th = 95th-percentile(sg_0[sg_0 > 0]) * sg_0_per.

  • sg_1_per (float) – sg_1_th = std(sg_1) * sg_1_per.

  • sg_2_per (float) – sg_2_th = std(sg_2) * sg_2_per.

Returns:

New FilterResult with thresholds populated (immutable update — the original is not modified).

Return type:

FilterResult

disaggregate_dry_weather(df, datetime_col='datetime', flow_col='flow', *, pattern='auto', smooth_window=48, smooth_polyorder=2, missing_value=-999.0, fill_missing_with_baseflow=True)[source]#

Disaggregate a flow time series into baseflow and stormflow.

Parameters:
  • df (pandas.DataFrame) – Input data containing a datetime column and a flow column.

  • datetime_col (str) – Name of the datetime column.

  • flow_col (str) – Name of the flow column.

  • pattern (str) – Weekly pattern to use: "auto" (select by record length, the default), or one of "diff", "median", "weekday_weekend", "one_day".

  • smooth_window (int) – Savitzky-Golay window length applied to the raw flow before pattern generation.

  • smooth_polyorder (int) – Savitzky-Golay polynomial order.

  • missing_value (float or None) – Sentinel value treated as missing (replaced with NaN). Set to None to disable.

  • fill_missing_with_baseflow (bool) – If True, missing/zero flow points are filled with the computed baseflow before stormflow is calculated.

Returns:

The disaggregation results.

Return type:

DryWeatherResult

Raises:

ValueError – If the series has fewer than two points or an irregular timestep cannot be inferred.

generate_weekly_patterns(smoothed, index, points_per_day, step_seconds)[source]#

Generate the four candidate weekly patterns from a smoothed series.

Parameters:
  • smoothed (numpy.ndarray) – Smoothed flow series.

  • index (pandas.DatetimeIndex) – Timestamps aligned with smoothed.

  • points_per_day (int) – Samples per day.

  • step_seconds (float) – Sampling step in seconds.

Returns:

Mapping of pattern key ("diff", "median", "weekday_weekend", "one_day") to a 7 * points_per_day-length weekly pattern array.

Return type:

dict

Event Detection#

detect_events uses scipy.signal.find_peaks on the smoothed signal to identify storm peaks, then walks backward and forward using derivative signals to bound each event. Overlapping events are merged or split at the trough.

Note

height_perc, prom_perc, and width_perc are percentile values in the 0–100 range (not fractions).

from sparsehydro import detect_events, events_to_dataframe

events, filter_result = detect_events(
    rain_stormflow_df,
    height_perc=25.0,
    prom_perc=25.0,
    width_perc=10.0,
)
print(events_to_dataframe(events))

sparsehydro.events — Storm event detection and record structures.

Provides derivative-based segmentation of stormflow timeseries into discrete storm events using Savitzky-Golay signals from sparsehydro.filters.

Public API#

Quick start:

from sparsehydro.events import detect_events, load_events_from_csv

events, filter_result = detect_events(rain_stormflow_df, verbose=True)
# or
events = load_events_from_csv("events_list.csv")
class EventRecord(event_id, start_datetime, end_datetime, peak_datetime, total_rain, total_flow, effective_area, peak_flow, b2b_start=False, b2b_end=False)[source]#

Bases: object

A single detected or imported storm event.

Variables:
  • event_id (int) – Sequential identifier starting at 1.

  • start_datetime (pandas.Timestamp) – Event start timestamp.

  • end_datetime (pandas.Timestamp) – Event end timestamp.

  • peak_datetime (pandas.Timestamp) – Timestamp of the sg_0 peak within the event window.

  • total_rain (float) – Cumulative rain depth over [start, end].

  • total_flow (float) – Cumulative stormflow over [start, end] (clipped to ≥ 0).

  • effective_area (float) – total_flow / total_rain. Zero when total_rain == 0.

  • peak_flow (float) – Maximum stormflow value within the event window.

  • b2b_start (bool) – True if the event starts at a back-to-back trough.

  • b2b_end (bool) – True if the event ends at a back-to-back trough.

duration_hours()[source]#

Return event duration in hours.

Returns:

Duration between start_datetime and end_datetime in hours.

Return type:

float

to_dict()[source]#

Serialize to plain dict.

Returns:

Mapping of every event field to its value.

Return type:

dict

b2b_end: bool = False#
b2b_start: bool = False#
effective_area: float#
end_datetime: Timestamp#
event_id: int#
peak_datetime: Timestamp#
peak_flow: float#
start_datetime: Timestamp#
total_flow: float#
total_rain: float#
detect_events(rain_stormflow, time_range=None, *, back_to_back=True, height_perc=25.0, prom_perc=25.0, width_perc=10.0, distance=48, window_length=48, polyorder=2, deriv_factor=1.2, sg_0_per=0.15, sg_1_per=0.25, sg_2_per=0.25, window_size=72, simp_th=0.5, verbose=False)[source]#

Detect storm events using Savitzky-Golay derivative segmentation.

Parameters:
  • rain_stormflow (pandas.DataFrame) – Must contain datetime, rain, stormflow.

  • time_range (tuple[str, str] | None) – Restrict detection to this (start, end) date range.

  • back_to_back (bool) – When True, keep distinct events separated at troughs.

  • height_perc (float) – Percentile threshold for peak height (0-100).

  • prom_perc (float) – Percentile threshold for peak prominence (0-100).

  • width_perc (float) – Percentile threshold for peak width (0-100).

  • distance (int) – Minimum samples between peaks.

  • window_length (int) – Base Savitzky-Golay window for sg_0.

  • polyorder (int) – Savitzky-Golay polynomial order.

  • deriv_factor (float) – Window multiplier for each successive derivative pass.

  • sg_0_per (float) – Threshold multiplier for the sg_0 boundary signal.

  • sg_1_per (float) – Threshold multiplier for the sg_1 boundary signal.

  • sg_2_per (float) – Threshold multiplier for the sg_2 boundary signal.

  • window_size (int) – Look-ahead/look-back window for boundary walks.

  • simp_th (float) – Height-ratio threshold for merging near-equal adjacent peaks (0-1).

  • verbose (bool) – Print progress diagnostics.

Returns:

Tuple (events, filter_result) where events are the detected EventRecord objects (event_id starts at 1) and filter_result holds the sg signals and computed thresholds for diagnostics.

Return type:

tuple[list[EventRecord], FilterResult]

events_to_dataframe(events)[source]#

Convert a list of EventRecord objects to a DataFrame.

Parameters:

events (list[EventRecord]) – Events to convert (may be empty).

Returns:

One row per event with all event fields as columns.

Return type:

pandas.DataFrame

load_events_from_csv(path)[source]#

Load an events_list.csv as a list of EventRecord objects.

The CSV must have columns event_id, start_date, end_date. Fields not present in the CSV are filled with sentinel values.

Parameters:

path (str or os.PathLike) – Path to the events_list.csv file.

Returns:

Events parsed from the CSV (sentinel values for missing fields).

Return type:

list[EventRecord]


Unit Hydrograph#

sparsehydro.models.unithydrograph — unit hydrograph models.

This subpackage provides:

  • UnitHydrographAdapter — the adapter base that bridges the existing UnitHydrograph class to the IModel lifecycle.

  • create_uh_model() — factory that creates a concrete, registry-compatible subclass for any model registered in UnitHydrograph._registry.

  • register_all_uh_models() — bulk registration helper.

  • GammaUH — Gamma-function UH

  • NashUH — Nash cascade UH

  • TriangleUH — Triangular UH

  • SequentialFitter — sequential event fitting

  • SequentialFitSummary — fitting results

Quick start:

from sparsehydro.models.unithydrograph import GammaUH, SequentialFitter
from sparsehydro.events import detect_events

events, filter_result = detect_events(rain_stormflow_df)
fitter = SequentialFitter(lambda: GammaUH(), rain_stormflow_df, events)
summary = fitter.fit(verbose=True)
print(summary.metrics_summary())
class GammaUH(A=100.0, tt=2.0, tp=5.0)[source]

Bases: IUnitHydroComponent

Gamma-function unit hydrograph.

Shape: f(t) (t/tp)^tt * exp(-t/tp)

Parameters:
  • A (float) – Effective area ratio (stormflow / rain volume). Bounds [0, 1e4].

  • tt (float) – Shape parameter (dimensionless). Bounds [0.01, 50].

  • tp (float) – Scale / time-to-peak in time steps. Bounds [0.01, 500].

apply_flat_parameter(name, value)

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]

Release cached forcing data and advance to FINALIZED.

Returns:

Nothing.

Return type:

None

get_kernel(dt_hours, n_steps=None)[source]

Return the normalized gamma UH ordinate array.

Parameters:
  • dt_hours (float) – Time-step size [hr].

  • n_steps (int | None) – Number of output steps; defaults to the natural support.

Returns:

Normalized UH ordinates [1/hr] such that sum * dt_hours 1.

Return type:

numpy.ndarray

get_output_field(name)

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

initialize()[source]

Register the A, tt, tp scalar parameters and advance to INITIALIZED.

Returns:

Nothing.

Return type:

None

is_created()

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict()[source]

Convolve rainfall with the gamma UH kernel and return predicted flow.

Returns:

DataFrame with columns datetime and Q_pred.

Return type:

pandas.DataFrame

Raises:

RuntimeError – If prepare() has not been called.

prepare(data)[source]

Cache forcing data and coerce the datetime column.

Parameters:

data (pandas.DataFrame) – DataFrame with datetime and rain columns.

Returns:

Nothing.

Return type:

None

read_flat_parameter(name)

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]

Validate parameter bounds and advance to VALIDATED.

Returns:

True if all parameters are within bounds.

Return type:

bool

property calibratable_output_names: list[str]

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str] = 'gamma-uh'

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

class NashUH(A=100.0, n=2.0, k=5.0)[source]

Bases: IUnitHydroComponent

Nash cascade (linear-reservoir) unit hydrograph.

Shape: f(t) t^(n-1) * exp(-t/k)

Parameters:
  • A (float) – Effective area ratio. Bounds [0, 1e4].

  • n (float) – Number of linear reservoirs. Bounds [0.01, 100].

  • k (float) – Storage coefficient in time steps. Bounds [0.01, 500].

apply_flat_parameter(name, value)

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]

Release cached forcing data and advance to FINALIZED.

Returns:

Nothing.

Return type:

None

get_kernel(dt_hours, n_steps=None)[source]

Return the normalized Nash cascade UH ordinate array.

Parameters:
  • dt_hours (float) – Time-step size [hr].

  • n_steps (int | None) – Number of output steps; defaults to the natural support.

Returns:

Normalized UH ordinates [1/hr] such that sum * dt_hours 1.

Return type:

numpy.ndarray

get_output_field(name)

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

initialize()[source]

Register the A, n, k scalar parameters and advance to INITIALIZED.

Returns:

Nothing.

Return type:

None

is_created()

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict()[source]

Convolve rainfall with the Nash cascade kernel and return predicted flow.

Returns:

DataFrame with columns datetime and Q_pred.

Return type:

pandas.DataFrame

Raises:

RuntimeError – If prepare() has not been called.

prepare(data)[source]

Cache forcing data and coerce the datetime column.

Parameters:

data (pandas.DataFrame) – DataFrame with datetime and rain columns.

Returns:

Nothing.

Return type:

None

read_flat_parameter(name)

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]

Validate parameter bounds and advance to VALIDATED.

Returns:

True if all parameters are within bounds.

Return type:

bool

property calibratable_output_names: list[str]

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str] = 'nash-uh'

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

class SequentialFitSummary(events, calibration_results, global_predicted, global_observed, model_class_name, fitted_effective_areas)[source]

Bases: object

Results of a sequential unit hydrograph fitting run.

Variables:
  • events (list[EventRecord]) – Events that were fitted, in chronological order.

  • calibration_results (list[CalibrationResult]) – One CalibrationResult per event. pareto_X[0] holds fitted parameters; objective_display_values()[0] returns [RMSE, NSE, KGE].

  • global_predicted (pandas.DataFrame) – Full-domain accumulated predicted flow. Columns: datetime, Q_pred.

  • global_observed (pandas.DataFrame) – Full-domain stormflow. Columns: datetime, stormflow.

  • model_class_name (str) – Name of the model class produced by model_factory.

  • fitted_effective_areas (list[float]) – Fitted effective area per event: sum(Q_pred) / sum(rain) over the event window. Parallel to events and calibration_results.

calibrated_areas()[source]

Return the calibrated UH area parameter per event.

For a single UH model this is the A parameter. For an ensemble (aliases like fast_A, slow_A) it is the sum of all *_A parameters — consistent with mode="sum" and fixed weights of 1.0.

Returns:

Calibrated total A value per fitted event.

Return type:

list[float]

Raises:

ValueError – If no A-bearing parameter is found in a calibration result.

effective_area_summary()[source]

Return observed and fitted effective area per event.

Columns: event_id, start_datetime, observed_ae, fitted_ae.

Returns:

One row per fitted event comparing observed vs fitted area.

Return type:

pandas.DataFrame

metrics_summary()[source]

Return per-event objective values in display form.

Columns: event_id, then one column per objective name.

Returns:

One row per fitted event with display-form objective values.

Return type:

pandas.DataFrame

parameter_evolution()[source]

Return fitted parameters indexed by event.

Columns: event_id, start_datetime, end_datetime, then one column per calibrated parameter.

Returns:

One row per fitted event with its calibrated parameters.

Return type:

pandas.DataFrame

calibration_results: list[CalibrationResult]
events: list[EventRecord]
fitted_effective_areas: list[float]
global_observed: DataFrame
global_predicted: DataFrame
model_class_name: str
class SequentialFitter(model_factory, rain_stormflow, events, output_column='Q_pred')[source]

Bases: object

Fit an IModel to storm events one by one.

Parameters:
  • model_factory (Callable[[], IModel]) –

    Zero-argument callable returning a fresh IModel in CREATED state. Works with single UH models and EnsembleModel:

    SequentialFitter(lambda: GammaUH(), data, events)
    SequentialFitter(lambda: make_ensemble(), data, events)
    

  • rain_stormflow (pandas.DataFrame) – Full time series with columns datetime, rain, stormflow.

  • events (list[EventRecord]) – Events to fit (sorted internally by start_datetime).

  • output_column (str) – Column name produced by model.predict(). Default "Q_pred".

fit(time_range=None, objectives=None, calibration_objective_index=0, method='Nelder-Mead', smooth_obs=True, verbose=True)[source]

Run the sequential fitting loop.

Parameters:
  • time_range (tuple[str, str] | None) – Restrict fitting to this (start, end) date range.

  • objectives (list[IObjective] | None) – Objectives to evaluate; defaults to [RMSE(), NashSutcliffe(), KGE()].

  • calibration_objective_index (int) – Index of objectives to minimise (default 0 = RMSE).

  • method (str) – scipy.optimize.minimize method, or "differential_evolution" for a global search.

  • smooth_obs (bool) – Apply a light Savitzky-Golay smooth to observed flow within each event.

  • verbose (bool) – Print per-event progress.

Returns:

Summary of the sequential fitting run.

Return type:

SequentialFitSummary

class TriangleUH(A=100.0, tt=50.0, tp=20.0)[source]

Bases: IUnitHydroComponent

Triangular unit hydrograph.

Rising limb 0 → peak at tp; falling limb peak → 0 at tt.

Parameters:
  • A (float) – Effective area ratio. Bounds [0, 1e4].

  • tt (float) – Total UH duration in time steps. Bounds [5, 1000].

  • tp (float) – Time to peak in time steps. Bounds [2, 500]. Must be < tt.

apply_flat_parameter(name, value)

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]

Release cached forcing data and advance to FINALIZED.

Returns:

Nothing.

Return type:

None

get_kernel(dt_hours, n_steps=None)[source]

Return the normalized triangular UH ordinate array.

Parameters:
  • dt_hours (float) – Time-step size [hr].

  • n_steps (int | None) – Number of output steps; defaults to the natural support.

Returns:

Normalized UH ordinates [1/hr]; all zeros when tp >= tt.

Return type:

numpy.ndarray

get_output_field(name)

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

initialize()[source]

Register the A, tt, tp scalar parameters and advance to INITIALIZED.

Returns:

Nothing.

Return type:

None

is_created()

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict()[source]

Convolve rainfall with the triangular UH kernel and return predicted flow.

Returns:

DataFrame with columns datetime and Q_pred.

Return type:

pandas.DataFrame

Raises:

RuntimeError – If prepare() has not been called.

prepare(data)[source]

Cache forcing data and coerce the datetime column.

Parameters:

data (pandas.DataFrame) – DataFrame with datetime and rain columns.

Returns:

Nothing.

Return type:

None

read_flat_parameter(name)

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]

Validate parameter bounds and the tp < tt ordering constraint.

Returns:

True if all parameters are within bounds and tp < tt.

Return type:

bool

property calibratable_output_names: list[str]

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str] = 'triangle-uh'

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

class UnitHydrographAdapter[source]

Bases: IUnitHydroComponent

Adapter base that bridges UnitHydrograph to the IModel lifecycle.

Do not instantiate or register this class directly. Use create_uh_model() or register_all_uh_models() to obtain concrete, registry-compatible subclasses.

Lifecycle mapping

IModel method

Adapter action

initialize

Constructs UnitHydrograph(key), reads _registry to create one ScalarParameter per model parameter.

validate

Delegates to parameters_valid().

prepare

Stores the rain_stormflow DataFrame; syncs ScalarParameter values → _uh.parameters.

predict

Calls _uh.predict(); returns the DataFrame.

finalize

Releases the stored DataFrame.

Parameter synchronisation

ScalarParameter values are the source of truth. They are pushed to _uh.parameters before every predict or fit call. After fit the optimised values are pulled back so both representations stay consistent.

Infinite bounds

UnitHydrograph._registry uses np.inf for unbounded parameters (e.g. A). These are clamped to ±:data:_INF_SUBSTITUTE when creating ScalarParameter objects so that calibration algorithms that require finite bounds always receive them.

apply_flat_parameter(name, value)

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]

Release the stored DataFrame and advance state to FINALIZED.

Returns:

Nothing.

Return type:

None

fit(rain_stormflow, **kwargs)[source]

Calibrate the wrapped UnitHydrograph and sync results back.

Parameters:
  • rain_stormflow (pandas.DataFrame) – Rainfall/stormflow forcing DataFrame.

  • kwargs (Any) – Additional keyword arguments forwarded to the wrapped model’s fit.

Returns:

Mapping of fitted parameter name to value.

Return type:

dict[str, float]

Raises:

RuntimeError – If initialize() has not been called.

get_kernel(dt_hours, n_steps=None)[source]

Return the normalized UH ordinate array for use in a composite model.

Returns get_uh(norm=1) — the UH shape with the A amplitude parameter divided out, so np.sum(result) 1.0.

Note

The dt_hours argument is accepted for API uniformity but does not resample the kernel.

Parameters:
  • dt_hours (float) – Time-step size [hr] (accepted for API uniformity).

  • n_steps (int | None) – Number of output steps; defaults to the natural support.

Returns:

Unit-area UH ordinate array.

Return type:

numpy.ndarray

Raises:

RuntimeError – If initialize() has not been called.

get_output_field(name)

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_uh(max_steps=864, norm=0)[source]

Return the unit hydrograph ordinate array from the wrapped model.

Parameters:
  • max_steps (int) – Maximum number of ordinates to return.

  • norm (int) – Normalisation mode passed to the wrapped model (0 raw, 1 unit-area).

Returns:

UH ordinate array.

Return type:

numpy.ndarray

Raises:

RuntimeError – If initialize() has not been called.

get_vector_parameter(name)

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

initialize()[source]

Construct the wrapped UnitHydrograph and register its parameters.

Returns:

Nothing.

Return type:

None

Raises:

TypeError – If called on the base UnitHydrographAdapter instead of a factory-created subclass.

is_created()

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict(predict_range=None, trim=True)[source]

Convolve stored rainfall with the UH shape and return predicted flow.

Parameters:
  • predict_range (Any) – Optional prediction window forwarded to the wrapped model’s predict.

  • trim (bool) – Whether to trim the convolution output to the input length.

Returns:

Predicted-flow DataFrame from the wrapped model.

Return type:

pandas.DataFrame

Raises:

RuntimeError – If initialize() or prepare() has not been called.

prepare(rain_stormflow, **kwargs)[source]

Store the input DataFrame and sync parameters to the wrapped model.

Parameters:
  • rain_stormflow (pandas.DataFrame) – Rainfall/stormflow forcing DataFrame consumed by the wrapped UnitHydrograph.

  • kwargs (Any) – Reserved for API compatibility; ignored.

Returns:

Nothing.

Return type:

None

read_flat_parameter(name)

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]

Validate that all registered parameters satisfy their bounds.

Returns:

True if all parameters are within bounds.

Return type:

bool

property calibratable_output_names: list[str]

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

property is_fit: bool

True if the wrapped UnitHydrograph has been successfully fitted.

Returns:

Fit status of the wrapped model (False if not yet built).

Return type:

bool

model_name: ClassVar[str] = 'uh-adapter'

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

create_uh_model(uh_model_name)[source]

Create and register a concrete IModel subclass for one UH model.

Parameters:

uh_model_name (str) – Key in UnitHydrograph._registry (e.g. "Nash", "Gamma", "Weibull").

Returns:

Concrete UnitHydrographAdapter subclass.

Return type:

type[UnitHydrographAdapter]

Raises:

KeyError – If uh_model_name is not in UnitHydrograph._registry.

register_all_uh_models()[source]

Create and register adapters for every model in UnitHydrograph._registry.

Call this once after confirming that uh_models is importable:

import sys
sys.path.insert(0, "/path/to/UnitHydrograph/Modeling")
from sparsehydro.models.unithydrograph import register_all_uh_models
register_all_uh_models()

Models already registered in the sparsehydro registry are skipped silently.

Returns:

Mapping of sparsehydro model_name → adapter class.

Return type:

dict[str, type[UnitHydrographAdapter]]

Native UH Models#

Three self-contained IUnitHydroComponent implementations that follow the full SparseHydro lifecycle. All return a DataFrame with a "Q_pred" column so the same column_map works for single models and EnsembleModel composites.

Kernel normalisation: sum(kernel) * dt_hours 1.0

Convolution: Q = convolve(rain, kernel * A * dt)[:n] where A is the effective area ratio (stormflow / rain volume).

Class

Parameters

Kernel shape

GammaUH

A, tt (shape), tp (scale/steps)

(t/tp)^tt · exp(-t/tp), normalised

NashUH

A, n (reservoirs), k (storage)

t^(n-1) · exp(-t/k) / (k^n Γ(n))

TriangleUH

A, tt (total steps), tp (peak)

Piecewise linear; tp < tt

Native IUnitHydroComponent unit hydrograph models.

Provides three self-contained implementations that follow the SparseHydro lifecycle without depending on the legacy UnitHydrograph adapter.

All models return a DataFrame with "Q_pred" as the predicted-flow column, so the same CalibrationProblem.column_map works for both single models and EnsembleModel composites.

Kernel normalisation: sum(get_kernel(dt)) * dt 1.0 (units: [1/hr])

Convolution: Q = convolve(rain, kernel * A * dt)[:n] so A represents the effective area ratio (stormflow / rain volume).

class GammaUH(A=100.0, tt=2.0, tp=5.0)[source]#

Bases: IUnitHydroComponent

Gamma-function unit hydrograph.

Shape: f(t) (t/tp)^tt * exp(-t/tp)

Parameters:
  • A (float) – Effective area ratio (stormflow / rain volume). Bounds [0, 1e4].

  • tt (float) – Shape parameter (dimensionless). Bounds [0.01, 50].

  • tp (float) – Scale / time-to-peak in time steps. Bounds [0.01, 500].

apply_flat_parameter(name, value)#

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)#

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]#

Release cached forcing data and advance to FINALIZED.

Returns:

Nothing.

Return type:

None

get_kernel(dt_hours, n_steps=None)[source]#

Return the normalized gamma UH ordinate array.

Parameters:
  • dt_hours (float) – Time-step size [hr].

  • n_steps (int | None) – Number of output steps; defaults to the natural support.

Returns:

Normalized UH ordinates [1/hr] such that sum * dt_hours 1.

Return type:

numpy.ndarray

get_output_field(name)#

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)#

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)#

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()#

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

initialize()[source]#

Register the A, tt, tp scalar parameters and advance to INITIALIZED.

Returns:

Nothing.

Return type:

None

is_created()#

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()#

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()#

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()#

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()#

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()#

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()#

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()#

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict()[source]#

Convolve rainfall with the gamma UH kernel and return predicted flow.

Returns:

DataFrame with columns datetime and Q_pred.

Return type:

pandas.DataFrame

Raises:

RuntimeError – If prepare() has not been called.

prepare(data)[source]#

Cache forcing data and coerce the datetime column.

Parameters:

data (pandas.DataFrame) – DataFrame with datetime and rain columns.

Returns:

Nothing.

Return type:

None

read_flat_parameter(name)#

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)#

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)#

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)#

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)#

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)#

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)#

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]#

Validate parameter bounds and advance to VALIDATED.

Returns:

True if all parameters are within bounds.

Return type:

bool

property calibratable_output_names: list[str]#

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]#

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]#

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str] = 'gamma-uh'#

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]#

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]#

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]#

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState#

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]#

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

class NashUH(A=100.0, n=2.0, k=5.0)[source]#

Bases: IUnitHydroComponent

Nash cascade (linear-reservoir) unit hydrograph.

Shape: f(t) t^(n-1) * exp(-t/k)

Parameters:
  • A (float) – Effective area ratio. Bounds [0, 1e4].

  • n (float) – Number of linear reservoirs. Bounds [0.01, 100].

  • k (float) – Storage coefficient in time steps. Bounds [0.01, 500].

apply_flat_parameter(name, value)#

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)#

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]#

Release cached forcing data and advance to FINALIZED.

Returns:

Nothing.

Return type:

None

get_kernel(dt_hours, n_steps=None)[source]#

Return the normalized Nash cascade UH ordinate array.

Parameters:
  • dt_hours (float) – Time-step size [hr].

  • n_steps (int | None) – Number of output steps; defaults to the natural support.

Returns:

Normalized UH ordinates [1/hr] such that sum * dt_hours 1.

Return type:

numpy.ndarray

get_output_field(name)#

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)#

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)#

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()#

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

initialize()[source]#

Register the A, n, k scalar parameters and advance to INITIALIZED.

Returns:

Nothing.

Return type:

None

is_created()#

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()#

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()#

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()#

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()#

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()#

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()#

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()#

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict()[source]#

Convolve rainfall with the Nash cascade kernel and return predicted flow.

Returns:

DataFrame with columns datetime and Q_pred.

Return type:

pandas.DataFrame

Raises:

RuntimeError – If prepare() has not been called.

prepare(data)[source]#

Cache forcing data and coerce the datetime column.

Parameters:

data (pandas.DataFrame) – DataFrame with datetime and rain columns.

Returns:

Nothing.

Return type:

None

read_flat_parameter(name)#

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)#

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)#

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)#

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)#

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)#

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)#

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]#

Validate parameter bounds and advance to VALIDATED.

Returns:

True if all parameters are within bounds.

Return type:

bool

property calibratable_output_names: list[str]#

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]#

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]#

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str] = 'nash-uh'#

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]#

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]#

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]#

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState#

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]#

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

class TriangleUH(A=100.0, tt=50.0, tp=20.0)[source]#

Bases: IUnitHydroComponent

Triangular unit hydrograph.

Rising limb 0 → peak at tp; falling limb peak → 0 at tt.

Parameters:
  • A (float) – Effective area ratio. Bounds [0, 1e4].

  • tt (float) – Total UH duration in time steps. Bounds [5, 1000].

  • tp (float) – Time to peak in time steps. Bounds [2, 500]. Must be < tt.

apply_flat_parameter(name, value)#

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)#

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]#

Release cached forcing data and advance to FINALIZED.

Returns:

Nothing.

Return type:

None

get_kernel(dt_hours, n_steps=None)[source]#

Return the normalized triangular UH ordinate array.

Parameters:
  • dt_hours (float) – Time-step size [hr].

  • n_steps (int | None) – Number of output steps; defaults to the natural support.

Returns:

Normalized UH ordinates [1/hr]; all zeros when tp >= tt.

Return type:

numpy.ndarray

get_output_field(name)#

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)#

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)#

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()#

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

initialize()[source]#

Register the A, tt, tp scalar parameters and advance to INITIALIZED.

Returns:

Nothing.

Return type:

None

is_created()#

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()#

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()#

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()#

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()#

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()#

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()#

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()#

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict()[source]#

Convolve rainfall with the triangular UH kernel and return predicted flow.

Returns:

DataFrame with columns datetime and Q_pred.

Return type:

pandas.DataFrame

Raises:

RuntimeError – If prepare() has not been called.

prepare(data)[source]#

Cache forcing data and coerce the datetime column.

Parameters:

data (pandas.DataFrame) – DataFrame with datetime and rain columns.

Returns:

Nothing.

Return type:

None

read_flat_parameter(name)#

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)#

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)#

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)#

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)#

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)#

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)#

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]#

Validate parameter bounds and the tp < tt ordering constraint.

Returns:

True if all parameters are within bounds and tp < tt.

Return type:

bool

property calibratable_output_names: list[str]#

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]#

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]#

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str] = 'triangle-uh'#

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]#

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]#

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]#

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState#

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]#

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

Sequential Fitting#

SequentialFitter fits a fresh model instance to each storm event in chronological order, warm-starting from the previous event’s calibrated parameters. The predicted flow from each fitted event is subtracted from the observed signal before the next event is fitted (residual approach).

The model_factory argument is a zero-argument callable that returns a fresh IModel — this works for both single UH models and EnsembleModel composites:

from sparsehydro.models.unithydrograph import GammaUH, SequentialFitter
from sparsehydro.models import EnsembleModel

# Single model
fitter = SequentialFitter(lambda: GammaUH(), rain_stormflow_df, events)

# Two-component ensemble
def make_ensemble():
    fast = GammaUH(A=80.0, tt=1.5, tp=3.0)
    slow = GammaUH(A=30.0, tt=3.0, tp=20.0)
    ens = EnsembleModel(
        components=[(fast, lambda p: p["Q_pred"].to_numpy()),
                    (slow, lambda p: p["Q_pred"].to_numpy())],
        mode="sum", aliases=["fast", "slow"],
        output_name="Q_pred", normalize_weights=False,
    )
    ens.initialize()
    ens.set_parameter("w_1", value=1.0, calibrate=False)
    ens.set_parameter("w_2", value=1.0, calibrate=False)
    ens.validate()
    return ens

fitter = SequentialFitter(make_ensemble, rain_stormflow_df, events)
summary = fitter.fit(verbose=True)

print(summary.metrics_summary())        # RMSE, NSE, KGE per event
print(summary.parameter_evolution())    # fitted params per event

Sequential event-by-event unit hydrograph fitting.

Uses CalibrationProblem for data preparation and objective evaluation, and constructs a CalibrationResult per event.

Warm starting from the previous event’s fitted parameters is handled by calling scipy.optimize.minimize directly (bypassing ScipySolver, which always restarts from the bounds midpoint).

class SequentialFitSummary(events, calibration_results, global_predicted, global_observed, model_class_name, fitted_effective_areas)[source]#

Bases: object

Results of a sequential unit hydrograph fitting run.

Variables:
  • events (list[EventRecord]) – Events that were fitted, in chronological order.

  • calibration_results (list[CalibrationResult]) – One CalibrationResult per event. pareto_X[0] holds fitted parameters; objective_display_values()[0] returns [RMSE, NSE, KGE].

  • global_predicted (pandas.DataFrame) – Full-domain accumulated predicted flow. Columns: datetime, Q_pred.

  • global_observed (pandas.DataFrame) – Full-domain stormflow. Columns: datetime, stormflow.

  • model_class_name (str) – Name of the model class produced by model_factory.

  • fitted_effective_areas (list[float]) – Fitted effective area per event: sum(Q_pred) / sum(rain) over the event window. Parallel to events and calibration_results.

calibrated_areas()[source]#

Return the calibrated UH area parameter per event.

For a single UH model this is the A parameter. For an ensemble (aliases like fast_A, slow_A) it is the sum of all *_A parameters — consistent with mode="sum" and fixed weights of 1.0.

Returns:

Calibrated total A value per fitted event.

Return type:

list[float]

Raises:

ValueError – If no A-bearing parameter is found in a calibration result.

effective_area_summary()[source]#

Return observed and fitted effective area per event.

Columns: event_id, start_datetime, observed_ae, fitted_ae.

Returns:

One row per fitted event comparing observed vs fitted area.

Return type:

pandas.DataFrame

metrics_summary()[source]#

Return per-event objective values in display form.

Columns: event_id, then one column per objective name.

Returns:

One row per fitted event with display-form objective values.

Return type:

pandas.DataFrame

parameter_evolution()[source]#

Return fitted parameters indexed by event.

Columns: event_id, start_datetime, end_datetime, then one column per calibrated parameter.

Returns:

One row per fitted event with its calibrated parameters.

Return type:

pandas.DataFrame

calibration_results: list[CalibrationResult]#
events: list[EventRecord]#
fitted_effective_areas: list[float]#
global_observed: DataFrame#
global_predicted: DataFrame#
model_class_name: str#
class SequentialFitter(model_factory, rain_stormflow, events, output_column='Q_pred')[source]#

Bases: object

Fit an IModel to storm events one by one.

Parameters:
  • model_factory (Callable[[], IModel]) –

    Zero-argument callable returning a fresh IModel in CREATED state. Works with single UH models and EnsembleModel:

    SequentialFitter(lambda: GammaUH(), data, events)
    SequentialFitter(lambda: make_ensemble(), data, events)
    

  • rain_stormflow (pandas.DataFrame) – Full time series with columns datetime, rain, stormflow.

  • events (list[EventRecord]) – Events to fit (sorted internally by start_datetime).

  • output_column (str) – Column name produced by model.predict(). Default "Q_pred".

fit(time_range=None, objectives=None, calibration_objective_index=0, method='Nelder-Mead', smooth_obs=True, verbose=True)[source]#

Run the sequential fitting loop.

Parameters:
  • time_range (tuple[str, str] | None) – Restrict fitting to this (start, end) date range.

  • objectives (list[IObjective] | None) – Objectives to evaluate; defaults to [RMSE(), NashSutcliffe(), KGE()].

  • calibration_objective_index (int) – Index of objectives to minimise (default 0 = RMSE).

  • method (str) – scipy.optimize.minimize method, or "differential_evolution" for a global search.

  • smooth_obs (bool) – Apply a light Savitzky-Golay smooth to observed flow within each event.

  • verbose (bool) – Print per-event progress.

Returns:

Summary of the sequential fitting run.

Return type:

SequentialFitSummary

Adapter (legacy)#

Adapter that wraps the existing UnitHydrograph class as an IModel.

The UnitHydrograph class (from uh_models.py) has its own internal registry, parameter dict, convolution, and calibration logic. Rather than reimplementing any of that, this module bridges it to the sparsehydro lifecycle and parameter registry via the Adapter pattern.

Usage:

from sparsehydro.models.unithydrograph import register_all_uh_models

# Call once after uh_models is on sys.path
register_all_uh_models()

from sparsehydro.registry import registry
model = registry.create("uh-nash")
model.initialize()
model.validate()
model.prepare(rain_stormflow_df)
result = model.predict()
model.finalize()

UnitHydrograph is imported lazilyimport sparsehydro always succeeds; the error surfaces only when you first call a method that needs the wrapped class. Ensure uh_models.py and its dependencies (data_processing, objective_functions) are on sys.path before calling register_all_uh_models() or create_uh_model().

class UnitHydrographAdapter[source]#

Bases: IUnitHydroComponent

Adapter base that bridges UnitHydrograph to the IModel lifecycle.

Do not instantiate or register this class directly. Use create_uh_model() or register_all_uh_models() to obtain concrete, registry-compatible subclasses.

Lifecycle mapping

IModel method

Adapter action

initialize

Constructs UnitHydrograph(key), reads _registry to create one ScalarParameter per model parameter.

validate

Delegates to parameters_valid().

prepare

Stores the rain_stormflow DataFrame; syncs ScalarParameter values → _uh.parameters.

predict

Calls _uh.predict(); returns the DataFrame.

finalize

Releases the stored DataFrame.

Parameter synchronisation

ScalarParameter values are the source of truth. They are pushed to _uh.parameters before every predict or fit call. After fit the optimised values are pulled back so both representations stay consistent.

Infinite bounds

UnitHydrograph._registry uses np.inf for unbounded parameters (e.g. A). These are clamped to ±:data:_INF_SUBSTITUTE when creating ScalarParameter objects so that calibration algorithms that require finite bounds always receive them.

apply_flat_parameter(name, value)#

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)#

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]#

Release the stored DataFrame and advance state to FINALIZED.

Returns:

Nothing.

Return type:

None

fit(rain_stormflow, **kwargs)[source]#

Calibrate the wrapped UnitHydrograph and sync results back.

Parameters:
  • rain_stormflow (pandas.DataFrame) – Rainfall/stormflow forcing DataFrame.

  • kwargs (Any) – Additional keyword arguments forwarded to the wrapped model’s fit.

Returns:

Mapping of fitted parameter name to value.

Return type:

dict[str, float]

Raises:

RuntimeError – If initialize() has not been called.

get_kernel(dt_hours, n_steps=None)[source]#

Return the normalized UH ordinate array for use in a composite model.

Returns get_uh(norm=1) — the UH shape with the A amplitude parameter divided out, so np.sum(result) 1.0.

Note

The dt_hours argument is accepted for API uniformity but does not resample the kernel.

Parameters:
  • dt_hours (float) – Time-step size [hr] (accepted for API uniformity).

  • n_steps (int | None) – Number of output steps; defaults to the natural support.

Returns:

Unit-area UH ordinate array.

Return type:

numpy.ndarray

Raises:

RuntimeError – If initialize() has not been called.

get_output_field(name)#

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)#

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_uh(max_steps=864, norm=0)[source]#

Return the unit hydrograph ordinate array from the wrapped model.

Parameters:
  • max_steps (int) – Maximum number of ordinates to return.

  • norm (int) – Normalisation mode passed to the wrapped model (0 raw, 1 unit-area).

Returns:

UH ordinate array.

Return type:

numpy.ndarray

Raises:

RuntimeError – If initialize() has not been called.

get_vector_parameter(name)#

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()#

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

initialize()[source]#

Construct the wrapped UnitHydrograph and register its parameters.

Returns:

Nothing.

Return type:

None

Raises:

TypeError – If called on the base UnitHydrographAdapter instead of a factory-created subclass.

is_created()#

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()#

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()#

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()#

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()#

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()#

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()#

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()#

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict(predict_range=None, trim=True)[source]#

Convolve stored rainfall with the UH shape and return predicted flow.

Parameters:
  • predict_range (Any) – Optional prediction window forwarded to the wrapped model’s predict.

  • trim (bool) – Whether to trim the convolution output to the input length.

Returns:

Predicted-flow DataFrame from the wrapped model.

Return type:

pandas.DataFrame

Raises:

RuntimeError – If initialize() or prepare() has not been called.

prepare(rain_stormflow, **kwargs)[source]#

Store the input DataFrame and sync parameters to the wrapped model.

Parameters:
  • rain_stormflow (pandas.DataFrame) – Rainfall/stormflow forcing DataFrame consumed by the wrapped UnitHydrograph.

  • kwargs (Any) – Reserved for API compatibility; ignored.

Returns:

Nothing.

Return type:

None

read_flat_parameter(name)#

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)#

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)#

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)#

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)#

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)#

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)#

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]#

Validate that all registered parameters satisfy their bounds.

Returns:

True if all parameters are within bounds.

Return type:

bool

property calibratable_output_names: list[str]#

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]#

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]#

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

property is_fit: bool#

True if the wrapped UnitHydrograph has been successfully fitted.

Returns:

Fit status of the wrapped model (False if not yet built).

Return type:

bool

model_name: ClassVar[str] = 'uh-adapter'#

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]#

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]#

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]#

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState#

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]#

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

create_uh_model(uh_model_name)[source]#

Create and register a concrete IModel subclass for one UH model.

Parameters:

uh_model_name (str) – Key in UnitHydrograph._registry (e.g. "Nash", "Gamma", "Weibull").

Returns:

Concrete UnitHydrographAdapter subclass.

Return type:

type[UnitHydrographAdapter]

Raises:

KeyError – If uh_model_name is not in UnitHydrograph._registry.

register_all_uh_models()[source]#

Create and register adapters for every model in UnitHydrograph._registry.

Call this once after confirming that uh_models is importable:

import sys
sys.path.insert(0, "/path/to/UnitHydrograph/Modeling")
from sparsehydro.models.unithydrograph import register_all_uh_models
register_all_uh_models()

Models already registered in the sparsehydro registry are skipped silently.

Returns:

Mapping of sparsehydro model_name → adapter class.

Return type:

dict[str, type[UnitHydrographAdapter]]


Antecedent Moisture Model (AMM)#

AMMModel implements the reparameterized Antecedent Moisture Model of Edgren, Czachorski & Gonwa (2024, Journal of Water Management Modeling 32: C525). A single configurable model covers two component types selected via component_type:

  • "standard" — the full three-level wet-weather component (Eqs. 1–11). An antecedent-moisture recursion accumulates a reduced-wetness capture fraction RW whose temperature sensitivity is set by a seasonal hydrologic condition factor (SHCF). Suitable for rainfall runoff or rain-derived infiltration/inflow (RDII).

  • "baseflow" — the two-level baseflow component (Eqs. 1–3, 12–16). Level 2 is omitted and the capture fraction is driven directly from temperature. Suitable for base flow / groundwater infiltration.

Both unit systems are supported via units: "imperial" (rainfall_in, acres, CFS) or "metric" (rainfall_mm). The flow recursion (Eq. 1) is the exact closed-form solution of the underlying linear-reservoir ODE, so the result is invariant to the reporting time step.

The model self-registers under the name "amm" and may be created through the registry:

from sparsehydro.registry import registry

model = registry.create("amm", component_type="standard", units="imperial")
model.initialize()
model.validate()
model.prepare(df)        # columns: datetime, rainfall_in, temperature
result = model.predict() # datetime, amm_cfs, capture_fraction, rw, shcf, map, matemp

The registered parameters depend on component_type:

Parameter

Meaning

Component

area_acres

Catchment area [acres]

both

PAT

Precipitation averaging time [hr]

both

HHL

Hydrograph half-life [hr]

both

TAT

Temperature averaging time [hr]

both

Cold_Temp

Cold-season temperature (Point 1)

both

Hot_Temp

Hot-season temperature (Point 2)

both

RD

Dry-weather capture fraction

standard

AMHL

Antecedent-moisture half-life [hr]

standard

Cold_SHCF

Capture fraction at Cold_Temp

standard

Hot_SHCF

Capture fraction at Hot_Temp

standard

Cold_R

Capture fraction at Cold_Temp

baseflow

Hot_R

Capture fraction at Hot_Temp

baseflow

The constraint Cold_Temp < Hot_Temp is registered as an inequality and is also enforced by validate().

Note

Multiple AMM components (e.g. fast inflow + slow infiltration + baseflow, Figure 5 of the paper) are combined by summing several AMMModel instances with EnsembleModel.

AMMModel — reparameterized Antecedent Moisture Model (AMM).

Implements the reparameterized AMM equations of Edgren, Czachorski & Gonwa (2024, Journal of Water Management Modeling 32: C525, https://doi.org/10.14796/JWMM.C525) as a concrete IModel.

A single configurable AMMModel supports two component types:

  • "standard" — the full three-level wet-weather component (Equations 1–11), used for rainfall runoff or rain-derived infiltration/inflow (RDII).

  • "baseflow" — the two-level baseflow component (Equations 1–3, 12–16), which omits Level 2 and drives the capture fraction directly from temperature. Suitable for base flow / groundwater infiltration.

Multiple components (e.g. fast inflow + slow infiltration + baseflow, Figure 5 of the paper) are combined by summing several AMMModel instances via EnsembleModel.

Equations (standard component)#

Level 1 — flow (Eq. 1):

Q_t = A·(RD + (RW_t + RW_{t-1})/2)·MAP_t·(1 - SF)/Δt + SF·Q_{t-1}

Shape factor (Eq. 2) and antecedent-moisture retention factor (Eq. 6):

SF   = 0.5 ** (Δt / HHL)
AMRF = 0.5 ** (Δt / AMHL)

Moving-average precipitation (Eq. 3, start-of-interval, lagged one step):

MAP_t = mean(P_{t-1}, …, P_{t-N}),   N = PAT/Δt + 1

Level 2 — additional wet-weather capture fraction (Eq. 5):

RW_t = (AMRF - 1)/ln(AMRF)·SHCF_t·MAP_t + AMRF·RW_{t-1}

Level 3 — seasonal hydrologic condition factor (Eqs. 7–11):

L      = 1.2·(Cold_SHCF - Hot_SHCF)
k      = 4.7964 / (Cold_Temp - Hot_Temp)
x0     = (Cold_Temp + Hot_Temp)/2
SHCF_t = L/(1 + exp(-k·(MATemp_t - x0))) + Cold_SHCF - (11/12)·L
MATemp_t = mean(Temp_t, …, Temp_{t-(TAT/Δt)})

Baseflow component (Eqs. 12–16) replaces Level 2/3 with a temperature-driven total capture fraction R_t (Eq. 13) and drops RD:

Q_t = A·((R_t + R_{t-1})/2)·MAP_t·(1 - SF)/Δt + SF·Q_{t-1}
class AMMModel(component_type='standard', units='imperial', output_name='amm_cfs', *, area_acres=100.0, pat_hours=0.0, hhl_hours=2.0, amhl_hours=8.0, rd=0.01, cold_temp=30.0, hot_temp=70.0, cold_value=None, hot_value=None, tat_hours=0.0)[source]#

Bases: IModel

Reparameterized Antecedent Moisture Model component.

Parameters:
  • component_type (str) – "standard" for the three-level wet-weather component (Eqs. 1–11) or "baseflow" for the two-level baseflow component (Eqs. 1–3, 12–16).

  • units (str) – Unit system — "imperial" (inches, acres, CFS; default) or "metric" (mm). Temperature units are unconstrained but cold_temp/hot_temp must match the supplied temperature series.

  • output_name (str) – Column name for the flow output of predict().

  • area_acres (float) – Catchment area [acres].

  • pat_hours (float) – Precipitation averaging time PAT [hr]; TP = PAT + Δt.

  • hhl_hours (float) – Hydrograph half-life HHL [hr].

  • amhl_hours (float) – Antecedent-moisture half-life AMHL [hr] (standard only).

  • rd (float) – Dry-weather capture fraction RD (standard only).

  • cold_temp (float) – Cold-season temperature (Point 1).

  • hot_temp (float) – Hot-season temperature (Point 2).

  • cold_value (float | None) – Cold_SHCF (standard) or Cold_R (baseflow) at Point 1.

  • hot_value (float | None) – Hot_SHCF (standard) or Hot_R (baseflow) at Point 2.

  • tat_hours (float) – Temperature averaging time TAT [hr].

Usage:

from sparsehydro.models.amm import AMMModel

model = AMMModel(component_type="standard", units="imperial")
model.initialize()
model.validate()
model.prepare(df)              # columns: datetime, rainfall_in, temperature
result = model.predict()       # datetime, amm_cfs, capture_fraction, rw, shcf, map, matemp
model.finalize()
apply_flat_parameter(name, value)#

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)#

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]#

Release cached forcing data and advance to FINALIZED.

get_output_field(name)#

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)#

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)#

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()[source]#

Inequality constraint residuals (g 0 is feasible).

Returns [Cold_Temp - Hot_Temp] enforcing Cold_Temp < Hot_Temp.

Returns:

Single-element list [Cold_Temp - Hot_Temp].

Return type:

list[float]

initialize()[source]#

Register parameters, output fields, and constraints.

is_created()#

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()#

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()#

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()#

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()#

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()#

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()#

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()#

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict(*args, **kwargs)[source]#

Run the AMM recursion and return the output time series.

Returns:

DataFrame with columns datetime, {output_name}, capture_fraction, map, matemp and — for the standard component — rw and shcf.

Return type:

pandas.DataFrame

Raises:

RuntimeError – If prepare() has not been called.

prepare(data, **kwargs)[source]#

Load forcing data, infer the time step, and fill temperature.

Parameters:

data (pandas.DataFrame) – DataFrame with columns datetime and rainfall_in (imperial) or rainfall_mm (metric). An optional temperature (or temperature_c) column drives the seasonal sigmoid; when absent it falls back to the midpoint of Cold_Temp and Hot_Temp.

Raises:

ValueError – If required columns are absent or the time step cannot be inferred.

read_flat_parameter(name)#

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)#

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)#

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)#

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)#

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)#

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)#

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]#

Validate parameter bounds and the temperature-ordering constraint.

Returns:

True if all parameters are within bounds and Cold_Temp < Hot_Temp.

Return type:

bool

property calibratable_output_names: list[str]#

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property component_type: str#

Component type — "standard" or "baseflow".

property inequality_constraint_descriptions: list[str]#

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]#

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

property is_standard: bool#

True for the three-level standard wet-weather component.

model_name: ClassVar[str] = 'amm'#

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]#

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]#

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]#

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState#

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property time_to_peak_hours: float#

Derived time to peak TP = PAT + Δt [hr] (Eq. 4).

property vector_parameter_names: list[str]#

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]


RDII#

The sparsehydro.models.rdii subpackage implements the full physics-based Rainfall-Derived Inflow and Infiltration (RDII) modelling chain:

  • Temperature-driven Initial Abstraction recovery/depletion (IAModel) — the wet step integrates the depletion ODE exactly within each timestep (invariant to sub-step refinement; mass-conserving)

  • Optional degree-day snow model (IAModel(snow=True)) — cold-day precipitation is stored as snow-water equivalent and released as melt during warm spells, capturing cold-season melt-driven peak events

  • N triangular RTK unit hydrographs (RTKTriangle)

  • A configurable composite model mixing the IA model with any number of RTK triangles (RDIIModel)

  • area_acres parameter converts depth [mm] → flow [CFS] automatically

  • Calibration via the generic CalibrationProblem — use column_map={"observed": "flow_cfs", "predicted": "rdii_cfs"}

Requires the optional rdii extra:

pip install sparsehydro[rdii]

sparsehydro.models.rdii — RDII physics models.

Classes#

  • IAModel — initial abstraction and rainfall excess

  • RTKTriangle — single triangular RTK unit hydrograph

  • RTKEnsembleModel — additive ensemble of RDIIModels

  • RDIIModel — IA model + N configurable UH components

Helpers#

  • triangular_uh() — compute RTK triangle ordinate array

  • default_rtk_params() — generate initial (R, T, K) tuples

class IAModel(ia_max=None, k0=0.05, kT=0.02, theta=0.1, T_ref=20.0, k_dep=None, T_freeze=0.0, units='imperial', snow=False, snow_T=1.0, snow_ddf=None)[source]

Bases: IModel

Stateful initial-abstraction model implementing the IModel lifecycle.

Constructor arguments seed the initialize() parameter registry. After initialize(), calibratable values live in the scalar-parameter registry and are kept in sync with the instance attributes used by the physics methods.

Parameters:
  • ia_max (float | None) – Maximum abstraction capacity. Defaults to 0.2 in (imperial) or 5.0 mm (metric). Pass None to use the unit-appropriate default.

  • k0 (float) – Base recovery rate constant [1/hr].

  • kT (float) – Temperature-dependent recovery coefficient [1/hr].

  • theta (float) – Temperature sensitivity exponent [1/°C].

  • T_ref (float) – Reference temperature [°C].

  • k_dep (float | None) – Depletion rate constant. Defaults to 7.62 /in (imperial) or 0.3 /mm (metric). Pass None to use the unit-appropriate default.

  • T_freeze (float) – Temperature below which recovery is suppressed [°C].

  • units (str) – Unit system — "imperial" (default, inches) or "metric" (mm).

  • snow (bool) – Enable the degree-day snow model.

  • snow_T (float) – Initial rain/snow threshold & melt base [°C].

  • snow_ddf (float | None) – Initial degree-day factor.

static compute_excess_series(rainfall_mm, dt_hours, temperature, ia_max, k0, kT, theta, T_ref, k_dep, T_freeze, snow_ddf=0.0, snow_T=None)[source]

Compute rainfall excess array for a full time series.

Pure function (no instance state) — safe for parallel optimizer use. ia_avail starts at ia_max (fully saturated capacity).

Parameters:
  • rainfall_mm (numpy.ndarray) – Per-step rainfall depth series.

  • dt_hours (numpy.ndarray) – Per-step interval length series [hr].

  • temperature (numpy.ndarray | None) – Per-step temperature series [°C], or None to use T_ref everywhere.

  • ia_max (float) – Maximum abstraction capacity.

  • k0 (float) – Base recovery rate constant [1/hr].

  • kT (float) – Temperature-dependent recovery coefficient [1/hr].

  • theta (float) – Temperature sensitivity exponent [1/°C].

  • T_ref (float) – Reference temperature [°C].

  • k_dep (float) – Depletion rate constant.

  • T_freeze (float) – Temperature below which recovery is suppressed [°C].

  • snow_ddf (float) – Degree-day snowmelt factor (0.0 disables melt).

  • snow_T (float | None) – Rain/snow threshold [°C], or None to disable snow.

Returns:

Rainfall excess depth series, same length as rainfall_mm.

Return type:

numpy.ndarray

apply_flat_parameter(name, value)

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

compute_excess(rainfall_mm)[source]

Return rainfall excess and deplete ia_avail accordingly.

Parameters:

rainfall_mm (float) – Rainfall depth applied this step.

Returns:

Rainfall excess depth for the step.

Return type:

float

finalize()[source]

Release stored forcing data and advance to FINALIZED.

Returns:

Nothing.

Return type:

None

get_output_field(name)

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

initialize()[source]

Register all IA scalar parameters and advance to INITIALIZED.

Returns:

Nothing.

Return type:

None

is_created()

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict()[source]

Compute rainfall excess for the prepared time series.

Returns:

DataFrame with columns datetime and the unit-specific excess column (p_excess_in or p_excess_mm).

Return type:

pandas.DataFrame

Raises:

RuntimeError – If prepare() has not been called.

prepare(data)[source]

Load forcing data and sync parameters from the registry.

Parameters:

data (pandas.DataFrame) – DataFrame with columns datetime and the unit-specific rainfall column (rainfall_in or rainfall_mm); an optional temperature_c column defaults to T_ref when absent.

Returns:

Nothing.

Return type:

None

Raises:

ValueError – If required columns are absent.

read_flat_parameter(name)

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

recovery_rate(temperature=None)[source]

Compute k_rec(T) = k0 + kT * exp(θ*(T - T_ref)), zeroed below T_freeze.

Parameters:

temperature (float | None) – Air temperature [°C]; defaults to T_ref.

Returns:

Recovery rate constant [1/hr] (0.0 below T_freeze).

Return type:

float

register_inequality_constraint(record)

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

reset()[source]

Reset ia_avail to ia_max (fully recovered state).

Returns:

Nothing.

Return type:

None

step_dry(dt_hours, temperature=None)[source]

Advance ia_avail over a dry interval of dt_hours.

Parameters:
  • dt_hours (float) – Length of the dry interval [hr].

  • temperature (float | None) – Air temperature [°C]; defaults to T_ref.

Returns:

Updated available abstraction capacity ia_avail.

Return type:

float

step_wet(delta_precip_mm)[source]

Deplete ia_avail for a rainfall pulse of delta_precip_mm mm.

Parameters:

delta_precip_mm (float) – Rainfall depth applied this step.

Returns:

Updated available abstraction capacity ia_avail.

Return type:

float

validate()[source]

Validate parameter bounds and physical constraint T_freeze < T_ref.

Returns:

True if all parameters are within bounds and T_freeze < T_ref.

Return type:

bool

property calibratable_output_names: list[str]

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str] = 'initial-abstraction'

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

class RDIIModel(ia_model=None, uh_components=None, units='imperial')[source]

Bases: IModel

Rainfall-Derived Inflow and Infiltration model.

Combines one IAModel with N configurable IUnitHydroComponent instances. Defaults to the classic three-pathway (fast / medium / slow) RTK parameterization.

Parameters:
  • ia_model (IModel, optional) – Initial-abstraction model. Its predict() must return a DataFrame containing a p_excess_mm or p_excess_in column (depending on units). Defaults to IAModel.

  • uh_components (list[IUnitHydroComponent], optional) – Unit hydrograph components. Each must implement IUnitHydroComponent. Defaults to three RTKTriangle instances (fast / medium / slow).

  • units (str) – Unit system — "imperial" (inches, default) or "metric" (mm).

Usage:

from sparsehydro.models.rdii import RDIIModel, IAModel, RTKTriangle

model = RDIIModel()           # defaults: 1 IAModel + 3 RTKTriangles
model.initialize()
model.validate()
model.prepare(df)
result = model.predict()      # datetime, rdii_cfs, rdii_mm, p_excess_mm
model.finalize()

# Mix RTK and Nash UH:
from sparsehydro.models.unithydrograph import create_uh_model
NashUH = create_uh_model("Nash")
model2 = RDIIModel(
    ia_model=IAModel(),
    uh_components=[RTKTriangle(R=0.05, T=1.0, K=1.5), NashUH()],
)
apply_flat_parameter(name, value)

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]

Release stored data and advance to FINALIZED.

Returns:

Nothing.

Return type:

None

get_output_field(name)

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()[source]

Inequality constraint residuals for the optimizer.

Returns R_i - 1.0, ia_T_freeze - ia_T_ref]. A value ≤ 0 means feasible.

Returns:

Two-element list R_i - 1, ia_T_freeze - ia_T_ref].

Return type:

list[float]

initialize()[source]

Initialize sub-models and register all parameters.

Registers area_acres, R_1 R_N (composite fractions), all IA model parameters (original names), and all UH shape parameters (uh{i}_{name} prefix, excluding each component’s amplitude param).

Returns:

Nothing.

Return type:

None

is_created()

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict(*args, **kwargs)[source]

Compute RDII by convolving P_excess with each UH component.

Syncs parameter values to sub-models on every call so parameter changes made between optimizer iterations are picked up automatically.

Returns:

DataFrame with columns datetime, rdii_cfs, rdii_mm (or rdii_in), p_excess_mm (or p_excess_in).

Return type:

pandas.DataFrame

Raises:

RuntimeError – If prepare() has not been called.

prepare(data, **kwargs)[source]

Load input data, infer dt, fill missing temperature, prepare the IA model.

Parameters:

data (pandas.DataFrame) – DataFrame with columns datetime, rainfall_in or rainfall_mm (depending on units), and optionally flow_cfs and temperature_c.

Raises:

ValueError – If required columns are absent or dt cannot be inferred.

read_flat_parameter(name)

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)[source]

Rename a scalar parameter and keep internal sync maps up to date.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a parameter named new_name already exists.

  • KeyError – If no parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]

Validate all parameters and physical constraints.

Checks ia_T_freeze < ia_T_ref when both are present.

Returns:

True if all constraints are satisfied.

Return type:

bool

property calibratable_output_names: list[str]

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str] = 'rdii'

Unique string identifier for this model type. Must be defined by every concrete subclass.

property n_components: int

Number of unit hydrograph components.

Returns:

Count of registered UH components.

Return type:

int

property output_field_names: list[str]

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

class RTKEnsembleModel[source]

Bases: object

Additive ensemble of RDIIModel instances — one per RDII pathway.

In SWMM each RTK pathway (fast / medium / slow) has its own independent initial-abstraction model. RTKEnsembleModel.create() wires up n_models RDIIModel instances — each carrying its own IAModel and n_triangles RTKTriangle objects — into a single additive EnsembleModel.

Use create() rather than the constructor:

ensemble = RTKEnsembleModel.create(
    n_models=3,
    n_triangles=3,
    units="imperial",
    area_acres=500.0,
)
ensemble.validate()
ensemble.prepare(df)
result = ensemble.predict()
ensemble.finalize()
classmethod create(n_models=3, n_triangles=1, units='imperial', area_acres=100.0, ia_defaults=None, rtk_defaults=None, aliases=None, output_name='rdii_cfs')[source]

Build an additive RTK ensemble.

Parameters:
  • n_models (int) – Number of RDIIModel instances (>= 1). Defaults to 3.

  • n_triangles (int) – RTK triangles inside each RDIIModel (>= 1). Defaults to 1.

  • units (str) – Unit system — "imperial" or "metric".

  • area_acres (float) – Drainage area shared by all components [acres]. Frozen and excluded from calibration.

  • ia_defaults (dict | None) – Keyword arguments forwarded to every IAModel constructor.

  • rtk_defaults (list[list[tuple[float, float, float]]] | None) – Nested initial (R, T, K) values. If omitted, default_rtk_params() is called.

  • aliases (list[str] | None) – Label per component. Defaults to ["fast", "medium", "slow"] for n_models=3, else ["rtk_1", …, "rtk_N"].

  • output_name (str) – Column name for the combined RDII signal.

Returns:

Fully initialised EnsembleModel.

Return type:

EnsembleModel

Raises:

ValueError – If counts or default lengths are inconsistent.

model_name = 'rtk-ensemble'
class RTKTriangle(R=0.05, T=1.0, K=1.5)[source]

Bases: IUnitHydroComponent

Triangular RTK unit hydrograph component.

Parameters:
  • R (float) – Fraction of rainfall excess entering the sewer [0, 1].

  • T (float) – Time to peak [hr] (must be > 0).

  • K (float) – Ratio of recession time to time-to-peak (must be > 1).

apply_flat_parameter(name, value)

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]

Release stored forcing data and advance to FINALIZED.

Returns:

Nothing.

Return type:

None

get_kernel(dt_hours, n_steps=None)[source]

Return the normalized triangular UH ordinate array.

The R-scaling is intentionally not applied here; the caller (RDIIModel) applies its own R_i fraction.

Parameters:
  • dt_hours (float) – Time-step size [hr].

  • n_steps (int | None) – Number of output steps; defaults to the natural support.

Returns:

1-D array of normalized UH ordinates [1/hr].

Return type:

numpy.ndarray

get_output_field(name)

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

initialize()[source]

Register R, T, K as scalar parameters and advance to INITIALIZED.

Returns:

Nothing.

Return type:

None

is_created()

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict()[source]

Convolve rainfall excess with this triangle’s UH kernel and apply R-scaling.

Returns:

DataFrame with columns datetime and rdii_mm.

Return type:

pandas.DataFrame

Raises:

RuntimeError – If prepare() has not been called.

prepare(data)[source]

Load rainfall-excess forcing data and infer time step.

Parameters:

data (pandas.DataFrame) – DataFrame with columns datetime and p_excess_mm.

Returns:

Nothing.

Return type:

None

Raises:

ValueError – If required columns are absent.

read_flat_parameter(name)

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]

Validate parameter bounds and advance to VALIDATED.

Returns:

True if all parameters are within bounds.

Return type:

bool

property base_duration: float

T * (1 + K).

Returns:

Base duration T * (1 + K) [hr].

Return type:

float

Type:

Total triangle duration in hours

property calibratable_output_names: list[str]

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str] = 'rtk-triangle'

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property peak_ordinate: float

Peak ordinate value 2 / (T * (1 + K)), ensuring unit area.

Returns:

Peak ordinate 2 / (T * (1 + K)) [1/hr].

Return type:

float

property scalar_parameter_names: list[str]

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

default_rtk_params(n_models, n_triangles=1, T_min=0.5, T_max=120.0, R_total=0.1, K_min=1.5, K_max=3.0)[source]

Generate initial (R, T, K) tuples grouped by model.

Returns a list of n_models sub-lists, each containing n_triangles (R, T, K) tuples distributed across the parameter space:

  • T — log-spaced between T_min and T_max.

  • K — linearly interpolated from K_min (fastest) to K_max (slowest).

  • RR_total / (n_models × n_triangles) for every triangle.

Parameters:
  • n_models (int) – Number of RDIIModel instances (>= 1).

  • n_triangles (int) – RTK triangles per model (>= 1).

  • T_min (float) – Time-to-peak for the fastest triangle [hr].

  • T_max (float) – Time-to-peak for the slowest triangle [hr].

  • R_total (float) – Total runoff fraction divided equally across all triangles.

  • K_min (float) – Recession ratio for the fastest triangle.

  • K_max (float) – Recession ratio for the slowest triangle.

Returns:

Nested list [[( R, T, K), ...], ...].

Return type:

list[list[tuple[float, float, float]]]

Raises:

ValueError – If any count or bound argument is invalid.

triangular_uh(triangle, dt_hours, n_steps=None)[source]

Compute the unit hydrograph ordinate array for one RTK triangle.

Each element represents the average flow rate [1/hr] over its interval, computed by analytically integrating the piecewise-linear triangle.

The array satisfies:

np.sum(ordinates) * dt_hours ≈ 1.0   (within 1e-10 relative error)
Parameters:
  • triangle (RTKTriangle) – RTK triangle parameters.

  • dt_hours (float) – Time-step size [hr].

  • n_steps (int | None) – Number of output steps. Defaults to natural support.

Returns:

1-D array of UH ordinates [1/hr].

Return type:

numpy.ndarray

Raises:

ValueError – If dt_hours <= 0.

RDII Model#

RDIIModel couples an IAModel with a configurable number of RTKTriangle unit hydrographs:

from sparsehydro.models.rdii import RDIIModel

model = RDIIModel(n_triangles=3)
model.initialize()
model.validate()

RDIIModel — configurable IA model + any mix of UH components.

Combines one IAModel with N configurable IUnitHydroComponent objects (RTK triangles, Nash/Gamma adapters, or custom shapes).

Parameter naming convention#

  • Own: area_acres, R_1 R_N

  • From IA model: original parameter names (e.g. ia_max, ia_k0 …)

  • From UH component i (1-indexed): uh{i}_{name} for each shape parameter, skipping the component’s amplitude/scaling parameter which is subsumed by R_{i}.

prepare() input DataFrame columns#

Column

Required

Notes

datetime rainfall_in rainfall_mm flow_cfs temperature_c

Yes imperial metric No No

Any pandas DatetimeLike Depth per step [in] Depth per step [mm] Observed flow (optimizer) Falls back to ia_T_ref

class RDIIModel(ia_model=None, uh_components=None, units='imperial')[source]#

Bases: IModel

Rainfall-Derived Inflow and Infiltration model.

Combines one IAModel with N configurable IUnitHydroComponent instances. Defaults to the classic three-pathway (fast / medium / slow) RTK parameterization.

Parameters:
  • ia_model (IModel, optional) – Initial-abstraction model. Its predict() must return a DataFrame containing a p_excess_mm or p_excess_in column (depending on units). Defaults to IAModel.

  • uh_components (list[IUnitHydroComponent], optional) – Unit hydrograph components. Each must implement IUnitHydroComponent. Defaults to three RTKTriangle instances (fast / medium / slow).

  • units (str) – Unit system — "imperial" (inches, default) or "metric" (mm).

Usage:

from sparsehydro.models.rdii import RDIIModel, IAModel, RTKTriangle

model = RDIIModel()           # defaults: 1 IAModel + 3 RTKTriangles
model.initialize()
model.validate()
model.prepare(df)
result = model.predict()      # datetime, rdii_cfs, rdii_mm, p_excess_mm
model.finalize()

# Mix RTK and Nash UH:
from sparsehydro.models.unithydrograph import create_uh_model
NashUH = create_uh_model("Nash")
model2 = RDIIModel(
    ia_model=IAModel(),
    uh_components=[RTKTriangle(R=0.05, T=1.0, K=1.5), NashUH()],
)
apply_flat_parameter(name, value)#

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)#

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]#

Release stored data and advance to FINALIZED.

Returns:

Nothing.

Return type:

None

get_output_field(name)#

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)#

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)#

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()[source]#

Inequality constraint residuals for the optimizer.

Returns R_i - 1.0, ia_T_freeze - ia_T_ref]. A value ≤ 0 means feasible.

Returns:

Two-element list R_i - 1, ia_T_freeze - ia_T_ref].

Return type:

list[float]

initialize()[source]#

Initialize sub-models and register all parameters.

Registers area_acres, R_1 R_N (composite fractions), all IA model parameters (original names), and all UH shape parameters (uh{i}_{name} prefix, excluding each component’s amplitude param).

Returns:

Nothing.

Return type:

None

is_created()#

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()#

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()#

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()#

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()#

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()#

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()#

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()#

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict(*args, **kwargs)[source]#

Compute RDII by convolving P_excess with each UH component.

Syncs parameter values to sub-models on every call so parameter changes made between optimizer iterations are picked up automatically.

Returns:

DataFrame with columns datetime, rdii_cfs, rdii_mm (or rdii_in), p_excess_mm (or p_excess_in).

Return type:

pandas.DataFrame

Raises:

RuntimeError – If prepare() has not been called.

prepare(data, **kwargs)[source]#

Load input data, infer dt, fill missing temperature, prepare the IA model.

Parameters:

data (pandas.DataFrame) – DataFrame with columns datetime, rainfall_in or rainfall_mm (depending on units), and optionally flow_cfs and temperature_c.

Raises:

ValueError – If required columns are absent or dt cannot be inferred.

read_flat_parameter(name)#

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)#

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)#

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)#

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)#

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)[source]#

Rename a scalar parameter and keep internal sync maps up to date.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a parameter named new_name already exists.

  • KeyError – If no parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)#

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]#

Validate all parameters and physical constraints.

Checks ia_T_freeze < ia_T_ref when both are present.

Returns:

True if all constraints are satisfied.

Return type:

bool

property calibratable_output_names: list[str]#

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]#

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]#

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str] = 'rdii'#

Unique string identifier for this model type. Must be defined by every concrete subclass.

property n_components: int#

Number of unit hydrograph components.

Returns:

Count of registered UH components.

Return type:

int

property output_field_names: list[str]#

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]#

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]#

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState#

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]#

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

Initial Abstraction#

Physics-based Initial Abstraction (IA) recovery and depletion model.

Tracks available soil/vadose-zone storage capacity over time. During dry intervals the capacity recovers toward ia_max via an exponential approach whose rate is temperature-dependent (capturing ET and drainage). During rainfall the capacity is depleted exponentially per mm of input. Recovery is suppressed entirely below T_freeze, producing emergent seasonal RDII behaviour from a single parameter set.

Key equations#

Recovery (dry interval Δt, temperature T):

k_rec(T) = k0 + kT * exp(θ * (T - T_ref))   if T >= T_freeze
         = 0                                   if T < T_freeze

IA_avail(t+Δt) = IA_max - (IA_max - IA_avail(t)) * exp(-k_rec(T) * Δt)

Depletion and rainfall excess (rainfall pulse ΔP mm, uniform within the step):

The wet step integrates the depletion ODE d(IA)/dp = -k_dep * IA exactly over the step (p = cumulative rain), so results are invariant to sub-step refinement — equivalent to uniformly disaggregating the step to an arbitrarily fine timestep:

IA(p) = IA_avail(t) * exp(-k_dep * p)

instantaneous excess rate = max(0, 1 - k_dep * IA(p))

IA_avail(t+Δt) = IA_avail(t) * exp(-k_dep * ΔP)

Optional degree-day snow model (snow=True):

T <= snow_T :  SWE += ΔP ;  liquid input = 0          (snowfall)
T >  snow_T :  melt = min(SWE, snow_ddf * (T - snow_T) * Δt_days)
               SWE -= melt ;  liquid input = ΔP + melt (rain-on-snow adds)
class IAModel(ia_max=None, k0=0.05, kT=0.02, theta=0.1, T_ref=20.0, k_dep=None, T_freeze=0.0, units='imperial', snow=False, snow_T=1.0, snow_ddf=None)[source]#

Bases: IModel

Stateful initial-abstraction model implementing the IModel lifecycle.

Constructor arguments seed the initialize() parameter registry. After initialize(), calibratable values live in the scalar-parameter registry and are kept in sync with the instance attributes used by the physics methods.

Parameters:
  • ia_max (float | None) – Maximum abstraction capacity. Defaults to 0.2 in (imperial) or 5.0 mm (metric). Pass None to use the unit-appropriate default.

  • k0 (float) – Base recovery rate constant [1/hr].

  • kT (float) – Temperature-dependent recovery coefficient [1/hr].

  • theta (float) – Temperature sensitivity exponent [1/°C].

  • T_ref (float) – Reference temperature [°C].

  • k_dep (float | None) – Depletion rate constant. Defaults to 7.62 /in (imperial) or 0.3 /mm (metric). Pass None to use the unit-appropriate default.

  • T_freeze (float) – Temperature below which recovery is suppressed [°C].

  • units (str) – Unit system — "imperial" (default, inches) or "metric" (mm).

  • snow (bool) – Enable the degree-day snow model.

  • snow_T (float) – Initial rain/snow threshold & melt base [°C].

  • snow_ddf (float | None) – Initial degree-day factor.

static compute_excess_series(rainfall_mm, dt_hours, temperature, ia_max, k0, kT, theta, T_ref, k_dep, T_freeze, snow_ddf=0.0, snow_T=None)[source]#

Compute rainfall excess array for a full time series.

Pure function (no instance state) — safe for parallel optimizer use. ia_avail starts at ia_max (fully saturated capacity).

Parameters:
  • rainfall_mm (numpy.ndarray) – Per-step rainfall depth series.

  • dt_hours (numpy.ndarray) – Per-step interval length series [hr].

  • temperature (numpy.ndarray | None) – Per-step temperature series [°C], or None to use T_ref everywhere.

  • ia_max (float) – Maximum abstraction capacity.

  • k0 (float) – Base recovery rate constant [1/hr].

  • kT (float) – Temperature-dependent recovery coefficient [1/hr].

  • theta (float) – Temperature sensitivity exponent [1/°C].

  • T_ref (float) – Reference temperature [°C].

  • k_dep (float) – Depletion rate constant.

  • T_freeze (float) – Temperature below which recovery is suppressed [°C].

  • snow_ddf (float) – Degree-day snowmelt factor (0.0 disables melt).

  • snow_T (float | None) – Rain/snow threshold [°C], or None to disable snow.

Returns:

Rainfall excess depth series, same length as rainfall_mm.

Return type:

numpy.ndarray

apply_flat_parameter(name, value)#

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)#

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

compute_excess(rainfall_mm)[source]#

Return rainfall excess and deplete ia_avail accordingly.

Parameters:

rainfall_mm (float) – Rainfall depth applied this step.

Returns:

Rainfall excess depth for the step.

Return type:

float

finalize()[source]#

Release stored forcing data and advance to FINALIZED.

Returns:

Nothing.

Return type:

None

get_output_field(name)#

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)#

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)#

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()#

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

initialize()[source]#

Register all IA scalar parameters and advance to INITIALIZED.

Returns:

Nothing.

Return type:

None

is_created()#

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()#

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()#

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()#

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()#

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()#

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()#

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()#

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict()[source]#

Compute rainfall excess for the prepared time series.

Returns:

DataFrame with columns datetime and the unit-specific excess column (p_excess_in or p_excess_mm).

Return type:

pandas.DataFrame

Raises:

RuntimeError – If prepare() has not been called.

prepare(data)[source]#

Load forcing data and sync parameters from the registry.

Parameters:

data (pandas.DataFrame) – DataFrame with columns datetime and the unit-specific rainfall column (rainfall_in or rainfall_mm); an optional temperature_c column defaults to T_ref when absent.

Returns:

Nothing.

Return type:

None

Raises:

ValueError – If required columns are absent.

read_flat_parameter(name)#

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

recovery_rate(temperature=None)[source]#

Compute k_rec(T) = k0 + kT * exp(θ*(T - T_ref)), zeroed below T_freeze.

Parameters:

temperature (float | None) – Air temperature [°C]; defaults to T_ref.

Returns:

Recovery rate constant [1/hr] (0.0 below T_freeze).

Return type:

float

register_inequality_constraint(record)#

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)#

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)#

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)#

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)#

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)#

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

reset()[source]#

Reset ia_avail to ia_max (fully recovered state).

Returns:

Nothing.

Return type:

None

step_dry(dt_hours, temperature=None)[source]#

Advance ia_avail over a dry interval of dt_hours.

Parameters:
  • dt_hours (float) – Length of the dry interval [hr].

  • temperature (float | None) – Air temperature [°C]; defaults to T_ref.

Returns:

Updated available abstraction capacity ia_avail.

Return type:

float

step_wet(delta_precip_mm)[source]#

Deplete ia_avail for a rainfall pulse of delta_precip_mm mm.

Parameters:

delta_precip_mm (float) – Rainfall depth applied this step.

Returns:

Updated available abstraction capacity ia_avail.

Return type:

float

validate()[source]#

Validate parameter bounds and physical constraint T_freeze < T_ref.

Returns:

True if all parameters are within bounds and T_freeze < T_ref.

Return type:

bool

property calibratable_output_names: list[str]#

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

ia_avail: float#
property inequality_constraint_descriptions: list[str]#

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]#

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str] = 'initial-abstraction'#

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]#

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]#

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property scalar_parameter_names: list[str]#

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState#

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]#

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

RTK Triangle#

Triangular RTK unit hydrograph and RTK ensemble model.

RTKTriangle defines a single triangular RTK unit hydrograph component. RTKEnsembleModel builds an additive ensemble of RDIIModel instances, one per RDII pathway (fast / medium / slow), each with its own IAModel.

RTK triangle shape#

  • R — fraction of rainfall excess entering the sewer (dimensionless).

  • T — time to peak [hours].

  • K — ratio of recession time to time-to-peak (must be > 1).

The unit hydrograph is piecewise-linear:

  • Rising limb: linear from 0 to peak over [0, T].

  • Falling limb: linear from peak to 0 over [T, T*(1+K)].

  • Peak ordinate = 2 / (T * (1+K)), ensuring area under curve equals 1.

class RTKEnsembleModel[source]#

Bases: object

Additive ensemble of RDIIModel instances — one per RDII pathway.

In SWMM each RTK pathway (fast / medium / slow) has its own independent initial-abstraction model. RTKEnsembleModel.create() wires up n_models RDIIModel instances — each carrying its own IAModel and n_triangles RTKTriangle objects — into a single additive EnsembleModel.

Use create() rather than the constructor:

ensemble = RTKEnsembleModel.create(
    n_models=3,
    n_triangles=3,
    units="imperial",
    area_acres=500.0,
)
ensemble.validate()
ensemble.prepare(df)
result = ensemble.predict()
ensemble.finalize()
classmethod create(n_models=3, n_triangles=1, units='imperial', area_acres=100.0, ia_defaults=None, rtk_defaults=None, aliases=None, output_name='rdii_cfs')[source]#

Build an additive RTK ensemble.

Parameters:
  • n_models (int) – Number of RDIIModel instances (>= 1). Defaults to 3.

  • n_triangles (int) – RTK triangles inside each RDIIModel (>= 1). Defaults to 1.

  • units (str) – Unit system — "imperial" or "metric".

  • area_acres (float) – Drainage area shared by all components [acres]. Frozen and excluded from calibration.

  • ia_defaults (dict | None) – Keyword arguments forwarded to every IAModel constructor.

  • rtk_defaults (list[list[tuple[float, float, float]]] | None) – Nested initial (R, T, K) values. If omitted, default_rtk_params() is called.

  • aliases (list[str] | None) – Label per component. Defaults to ["fast", "medium", "slow"] for n_models=3, else ["rtk_1", …, "rtk_N"].

  • output_name (str) – Column name for the combined RDII signal.

Returns:

Fully initialised EnsembleModel.

Return type:

EnsembleModel

Raises:

ValueError – If counts or default lengths are inconsistent.

model_name = 'rtk-ensemble'#
class RTKTriangle(R=0.05, T=1.0, K=1.5)[source]#

Bases: IUnitHydroComponent

Triangular RTK unit hydrograph component.

Parameters:
  • R (float) – Fraction of rainfall excess entering the sewer [0, 1].

  • T (float) – Time to peak [hr] (must be > 0).

  • K (float) – Ratio of recession time to time-to-peak (must be > 1).

apply_flat_parameter(name, value)#

Apply one value from a flattened calibration search vector.

Dispatches on the parameter name’s shape: a plain name (e.g. "HHL") is treated as a scalar parameter; a name with a trailing index (e.g. "pf_dow[3]", as produced by CalibrationProblem for VectorParameter elements) sets that single element of the named vector parameter in-place.

Parameters:
  • name (str) – Scalar parameter name, or "{vector_name}[{index}]".

  • value (float) – New value to assign.

Returns:

Nothing.

Return type:

None

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

apply_parameter_values(values, *, skip_missing=True)#

Apply a mapping of parameter names to values in-place.

Parameters:
  • values (dict[str, float]) – Mapping of scalar parameter name to its new value.

  • skip_missing (bool) – When True (default) names that are not registered are ignored; when False a missing name raises.

Returns:

Names of the parameters that were actually updated.

Return type:

list[str]

Raises:

KeyError – If skip_missing is False and a name in values is not registered.

finalize()[source]#

Release stored forcing data and advance to FINALIZED.

Returns:

Nothing.

Return type:

None

get_kernel(dt_hours, n_steps=None)[source]#

Return the normalized triangular UH ordinate array.

The R-scaling is intentionally not applied here; the caller (RDIIModel) applies its own R_i fraction.

Parameters:
  • dt_hours (float) – Time-step size [hr].

  • n_steps (int | None) – Number of output steps; defaults to the natural support.

Returns:

1-D array of normalized UH ordinates [1/hr].

Return type:

numpy.ndarray

get_output_field(name)#

Return the FieldRecord for name.

Parameters:

name (str) – Name of the output field to retrieve.

Returns:

The registered output-field metadata.

Return type:

FieldRecord

Raises:

KeyError – If no output field named name is registered.

get_scalar_parameter(name)#

Retrieve a registered scalar parameter by name.

Parameters:

name (str) – Name of the scalar parameter to retrieve.

Returns:

The registered scalar parameter.

Return type:

ScalarParameter

Raises:

KeyError – If no scalar parameter named name is registered.

get_vector_parameter(name)#

Retrieve a registered vector parameter by name.

Parameters:

name (str) – Name of the vector parameter to retrieve.

Returns:

The registered vector parameter.

Return type:

VectorParameter

Raises:

KeyError – If no vector parameter named name is registered.

inequality_constraints()#

Inequality constraint residuals where g_j <= 0 means feasible.

Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).

Returns:

Constraint residuals; an empty list indicates no constraints.

Return type:

list[float]

initialize()[source]#

Register R, T, K as scalar parameters and advance to INITIALIZED.

Returns:

Nothing.

Return type:

None

is_created()#

Return whether the model is in the CREATED state.

Returns:

True if the model has been constructed but not yet initialized.

Return type:

bool

is_finalized()#

Return whether the model is in the FINALIZED state.

Returns:

True if finalize() has completed.

Return type:

bool

is_initialized()#

Return whether the model is in the INITIALIZED state.

Returns:

True if initialize() has completed.

Return type:

bool

is_predicted()#

Return whether the model is in the PREDICTED state.

Returns:

True if predict() has completed.

Return type:

bool

is_prepared()#

Return whether the model is in the PREPARED state.

Returns:

True if prepare() has completed.

Return type:

bool

is_validated()#

Return whether the model is in the VALIDATED state.

Returns:

True if validate() has completed successfully.

Return type:

bool

output_field_metadata()#

Return a DataFrame describing every registered output field.

Returns:

One row per output field with field, units, calibratable and description columns.

Return type:

pandas.DataFrame

parameters_valid()#

Return whether every registered parameter is within its bounds.

Returns:

True when all scalar and vector parameters satisfy their bounds; False otherwise.

Return type:

bool

predict()[source]#

Convolve rainfall excess with this triangle’s UH kernel and apply R-scaling.

Returns:

DataFrame with columns datetime and rdii_mm.

Return type:

pandas.DataFrame

Raises:

RuntimeError – If prepare() has not been called.

prepare(data)[source]#

Load rainfall-excess forcing data and infer time step.

Parameters:

data (pandas.DataFrame) – DataFrame with columns datetime and p_excess_mm.

Returns:

Nothing.

Return type:

None

Raises:

ValueError – If required columns are absent.

read_flat_parameter(name)#

Read one value addressed the same way as apply_flat_parameter().

Parameters:

name (str) – Scalar parameter name, or "{vector_name}[{index}]".

Returns:

The current value at that address.

Return type:

float

Raises:

KeyError – If the named scalar or vector parameter is not registered, or index is out of range for the vector parameter.

register_inequality_constraint(record)#

Register a named inequality constraint.

Parameters:

record (ConstraintRecord) – Constraint metadata to append to the registry.

Returns:

Nothing.

Return type:

None

register_output_field(field)#

Register metadata for one column of the predict() output.

Parameters:

field (FieldRecord) – Output field metadata. Replaces any existing field with the same name.

Returns:

Nothing.

Return type:

None

register_scalar_parameter(param)#

Register a scalar parameter with the model.

Parameters:

param (ScalarParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

register_vector_parameter(param)#

Register a vector parameter with the model.

Parameters:

param (VectorParameter) – Parameter to register. Replaces any existing parameter sharing the same name.

Returns:

Nothing.

Return type:

None

rename_scalar_parameter(old_name, new_name)#

Rename a registered scalar parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a scalar parameter named new_name already exists.

  • KeyError – If no scalar parameter named old_name is registered.

rename_vector_parameter(old_name, new_name)#

Rename a registered vector parameter.

Parameters:
  • old_name (str) – Current name of the parameter.

  • new_name (str) – New name to assign to the parameter.

Returns:

Nothing.

Return type:

None

Raises:
  • ValueError – If a vector parameter named new_name already exists.

  • KeyError – If no vector parameter named old_name is registered.

validate()[source]#

Validate parameter bounds and advance to VALIDATED.

Returns:

True if all parameters are within bounds.

Return type:

bool

property base_duration: float#

T * (1 + K).

Returns:

Base duration T * (1 + K) [hr].

Return type:

float

Type:

Total triangle duration in hours

property calibratable_output_names: list[str]#

Names of output columns flagged as calibratable.

Returns:

Names of output fields whose calibratable flag is True.

Return type:

list[str]

property inequality_constraint_descriptions: list[str]#

Ordered list of registered inequality constraint descriptions.

Returns:

Constraint descriptions in registration order.

Return type:

list[str]

property inequality_constraint_names: list[str]#

Ordered list of registered inequality constraint names.

Returns:

Constraint names in registration order.

Return type:

list[str]

model_name: ClassVar[str] = 'rtk-triangle'#

Unique string identifier for this model type. Must be defined by every concrete subclass.

property output_field_names: list[str]#

Ordered list of registered output column names.

Returns:

Output column names in registration order.

Return type:

list[str]

property output_fields: list[FieldRecord]#

Ordered list of all registered output-field records.

Returns:

FieldRecord objects in registration order.

Return type:

list[FieldRecord]

property peak_ordinate: float#

Peak ordinate value 2 / (T * (1 + K)), ensuring unit area.

Returns:

Peak ordinate 2 / (T * (1 + K)) [1/hr].

Return type:

float

property scalar_parameter_names: list[str]#

Ordered list of registered scalar parameter names.

Returns:

Scalar parameter names in registration order.

Return type:

list[str]

property state: ModelState#

Current lifecycle state of the model.

Returns:

The model’s current lifecycle state.

Return type:

ModelState

property vector_parameter_names: list[str]#

Ordered list of registered vector parameter names.

Returns:

Vector parameter names in registration order.

Return type:

list[str]

default_rtk_params(n_models, n_triangles=1, T_min=0.5, T_max=120.0, R_total=0.1, K_min=1.5, K_max=3.0)[source]#

Generate initial (R, T, K) tuples grouped by model.

Returns a list of n_models sub-lists, each containing n_triangles (R, T, K) tuples distributed across the parameter space:

  • T — log-spaced between T_min and T_max.

  • K — linearly interpolated from K_min (fastest) to K_max (slowest).

  • RR_total / (n_models × n_triangles) for every triangle.

Parameters:
  • n_models (int) – Number of RDIIModel instances (>= 1).

  • n_triangles (int) – RTK triangles per model (>= 1).

  • T_min (float) – Time-to-peak for the fastest triangle [hr].

  • T_max (float) – Time-to-peak for the slowest triangle [hr].

  • R_total (float) – Total runoff fraction divided equally across all triangles.

  • K_min (float) – Recession ratio for the fastest triangle.

  • K_max (float) – Recession ratio for the slowest triangle.

Returns:

Nested list [[( R, T, K), ...], ...].

Return type:

list[list[tuple[float, float, float]]]

Raises:

ValueError – If any count or bound argument is invalid.

triangular_uh(triangle, dt_hours, n_steps=None)[source]#

Compute the unit hydrograph ordinate array for one RTK triangle.

Each element represents the average flow rate [1/hr] over its interval, computed by analytically integrating the piecewise-linear triangle.

The array satisfies:

np.sum(ordinates) * dt_hours ≈ 1.0   (within 1e-10 relative error)
Parameters:
  • triangle (RTKTriangle) – RTK triangle parameters.

  • dt_hours (float) – Time-step size [hr].

  • n_steps (int | None) – Number of output steps. Defaults to natural support.

Returns:

1-D array of UH ordinates [1/hr].

Return type:

numpy.ndarray

Raises:

ValueError – If dt_hours <= 0.


Calibration#

The sparsehydro.calibration subpackage provides solver-agnostic abstractions for parameter estimation:

  • CalibrationProblem — wraps any IModel with observed data and objectives.

  • CalibrationResult — stores the Pareto front, per-generation history, and metadata.

  • A library of IObjective implementations covering MSE, NSE, KGE, and more.

  • Multiple solver backends (see Solvers below).

sparsehydro.calibration — general-purpose model calibration abstractions.

Public API#

Objectives

Name

Description

IObjective

Abstract objective function interface

MSE

Mean squared error

RMSE

Root mean squared error

MAE

Mean absolute error

PeakWeightedMSE

Flow-weighted MSE

NashSutcliffe

Nash-Sutcliffe efficiency

KGE

Kling-Gupta efficiency

PBIAS

Absolute percent bias

VolumeRelativeError

Relative total volume error

LogNSE

NSE on log-transformed flows

IndexOfAgreement

Willmott’s index of agreement

ConcordanceCorrelationCoefficient

Lin’s concordance correlation coefficient

Problem & results

Name

Description

CalibrationProblem

Wraps any IModel + observed + objectives

CalibrationResult

Pareto front + generation history

GenerationRecord

Per-generation population snapshot

Solvers

Name

Description

ISolver

Abstract solver interface

NSGAIISolver

NSGA-II (requires pymoo)

ParticleSwarmSolver

SMPSO / OMOPSO (requires platypus-opt)

PlatypusSolver

Any Platypus algorithm (requires platypus-opt)

ScipySolver

SciPy single-objective (requires scipy)

class CalibrationProblem(model, data=None, objectives=None, column_map=None, prepare_fn=None, mask=None, **prepare_kwargs)[source]

Bases: object

Solver-agnostic calibration problem for any IModel.

Bundles a model with input data, preprocessing, observed targets, and objectives. The same problem instance can be passed to any ISolver without modification.

All column/role mappings are expressed through a single column_map dict:

  • Non-reserved entries {target_col: source_col} — rename data[source_col] to target_col before calling model.prepare().

  • Reserved key "observed"str (column name) or callable (prepared_data) np.ndarray. Identifies the calibration target.

  • Reserved key "predicted"str or callable (predict_df) np.ndarray. Identifies the model output to compare.

Parameters:
  • model (IModel) – Model in at least VALIDATED state. Prepared automatically when data is supplied.

  • data (Any) – Input data (any type). Passed through the preprocessing pipeline and then to model.prepare(). May be None if the model is already in PREPARED state, but then column_map["observed"] must be a callable that does not require the prepared data (e.g. a closure).

  • objectives (list[IObjective]) – At least one objective.

  • column_map (dict[str, Any] or None) – Unified mapping dict (see above).

  • prepare_fn (Callable or None) – (data, **prepare_kwargs) prepared_data callable for complex preprocessing. Mutually exclusive with non-reserved column_map rename entries.

  • mask (str or Callable or numpy.ndarray or None) – Problem-level default mask restricting every objective to a subset of timesteps. May be a boolean np.ndarray, a column-name string, or a callable (prepared_data) -> array-like — resolved like observed/predicted. Equivalent to column_map["mask"] (the explicit argument wins if both are given). Individual objectives that carry their own mask override this default. Positions where observed or predicted is NaN are always excluded regardless.

  • prepare_kwargs (Any) – Extra keyword arguments forwarded to prepare_fn.

Masking:

problem = CalibrationProblem(
    model=model, data=df,
    objectives=[NashSutcliffe(), VolumeRelativeError()],
    column_map={"observed": "stormflow", "predicted": "rdii_cfs",
                "mask": "is_storm"},   # bool column in prepared data
)
evaluate(x, penalty_weight=1000000.0)[source]

Apply a parameter vector, run predict(), and return objectives.

Objective values are in minimisation form: maximised objectives are negated. When penalty_weight > 0 and the model reports inequality constraints, a squared penalty penalty_weight * Σ max(0, g_j)² is added to steer constraint-unaware solvers toward feasible regions. Pass penalty_weight=0.0 when the solver handles constraints natively.

Only parameters with calibrate=True are set from x; fixed parameters (calibrate=False) retain their current values.

Parameters:
  • x (numpy.ndarray) – Parameter vector of length n_params (calibratable only).

  • penalty_weight (float) – Multiplier for the squared-penalty term (default 1e6).

Returns:

1-D array of length n_objectives in minimisation form.

Return type:

numpy.ndarray

make_copy()[source]

Return a deep-copied CalibrationProblem safe for parallel workers.

The deep-copied model already holds its prepared state; data preparation is not re-run. All mutable state (model, observed array, bounds) is independent from the original.

Return type:

CalibrationProblem

property bounds: tuple[ndarray, ndarray]

Lower and upper bounds as (xl, xu) arrays.

property constraint_descriptions: list[str]

Ordered list of inequality constraint descriptions.

property constraint_names: list[str]

Ordered list of inequality constraint names (empty if unconstrained).

property minimize_flags: list[bool]

True if the corresponding objective should be minimised.

property n_ieq_constr: int

Number of inequality constraints reported by the model.

property n_objectives: int

Number of objectives.

property n_params: int

Number of calibratable search dimensions (scalars + flattened vector elements).

property objective_names: list[str]

Objective names in evaluation order.

property param_names: list[str]

Ordered list of calibrated search-dimension names.

Scalar parameters appear by their own name; each calibratable VectorParameter contributes one entry per element, named "{vector_name}[{index}]".

class CalibrationResult(history, pareto_X, pareto_F, param_names, objective_names, minimize_flags)[source]

Bases: object

General-purpose container for calibration results.

Produced by any ISolver. Objective values are stored in minimisation form (maximised objectives are negated). Conversion back to display form is handled by objective_display_values() and to_pareto_dataframe().

Parameters:
  • history (list[GenerationRecord]) – One GenerationRecord per generation. May be empty for single-shot solvers.

  • pareto_X (numpy.ndarray) – Parameter matrix for the final Pareto front, shape (m, n_params).

  • pareto_F (numpy.ndarray) – Objective matrix in minimisation form, shape (m, n_obj).

  • param_names (list[str]) – Ordered list of calibrated parameter names.

  • objective_names (list[str]) – Names of each objective (matching objective order).

  • minimize_flags (list[bool]) – True for minimised objectives; False for maximised objectives.

best_by(objective_name)[source]

Return the parameter vector that is best for the named objective.

“Best” means the lowest value for minimised objectives and the highest for maximised objectives. Internally, pareto_F is always in minimisation form, so argmin always selects the best solution.

Parameters:

objective_name (str) – Name matching one of objective_names.

Returns:

1-D parameter array.

Return type:

numpy.ndarray

Raises:

ValueError – If objective_name is not found.

objective_display_values()[source]

Return Pareto objective values in display form (un-negated).

Returns:

Array of shape (m, n_obj) with actual objective values.

Return type:

numpy.ndarray

to_pareto_dataframe()[source]

Return a tidy DataFrame spanning all generations.

Columns: generation, one column per parameter, one column per objective (display-form values), is_pareto (True only for solutions on the final generation’s Pareto front).

Return type:

pandas.DataFrame

class ConcordanceCorrelationCoefficient(mask=None)[source]

Bases: IObjective

Lin’s Concordance Correlation Coefficient (CCC).

Combines precision (Pearson correlation) and accuracy (closeness to the perfect-concordance line) into a single coefficient bounded to [−1, 1]:

\[\rho_c = \frac{2\,\sigma_{op}} {\sigma_o^2 + \sigma_p^2 + (\mu_o - \mu_p)^2}\]

CCC = 1 for perfect agreement between observed and predicted. Unlike Pearson correlation alone, CCC penalises systematic bias and scale differences, making it sensitive to both random and systematic error.

Variables:
  • name"ccc"

  • minimizeFalse

Raises:

ValueError – If both series are constant and equal (denominator zero).

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = False
name: ClassVar[str] = 'ccc'
class GenerationRecord(generation, X, F, n_pareto)

Bases: tuple

Create new instance of GenerationRecord(generation, X, F, n_pareto)

count(value, /)

Return number of occurrences of value.

index(value, start=0, stop=9223372036854775807, /)

Return first index of value.

Raises ValueError if the value is not present.

F

Alias for field number 2

X

Alias for field number 1

generation

Alias for field number 0

n_pareto

Alias for field number 3

class IObjective(mask=None)[source]

Bases: ABC

Abstract calibration objective.

Subclasses must set the class variables name and minimize and implement evaluate().

Variables:
  • name – Short snake_case identifier (used as column name in result DataFrames).

  • minimizeTrue if lower scores are better; False for objectives like NSE where higher is better.

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)[source]

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

abstractmethod evaluate(observed, predicted)[source]

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool]
name: ClassVar[str]
class ISolver[source]

Bases: ABC

Abstract calibration solver.

All solvers accept a CalibrationProblem and return a CalibrationResult.

solve() accepts **kwargs that override constructor-level settings for that call only — the solver instance is not mutated. This lets the same solver be reused for both quick exploratory runs and full production runs:

solver = NSGAIISolver(pop_size=100, n_gen=200)
quick  = solver.solve(problem, n_gen=5)    # fast sanity check
full   = solver.solve(problem)             # original settings

Minimal implementation:

class MySolver(ISolver):
    def solve(self, problem: CalibrationProblem, **kwargs) -> CalibrationResult:
        x_best = ...          # your optimisation logic
        F_best = problem.evaluate(x_best).reshape(1, -1)
        return CalibrationResult(
            history=[],
            pareto_X=x_best.reshape(1, -1),
            pareto_F=F_best,
            param_names=problem.param_names,
            objective_names=problem.objective_names,
            minimize_flags=problem.minimize_flags,
        )
abstractmethod solve(problem, **kwargs)[source]

Run the solver and return results.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides for solver settings (e.g. n_gen=10). Each solver documents which keys are recognised.

Returns:

Calibration result with Pareto front and generation history.

Return type:

CalibrationResult

class IndexOfAgreement(mask=None)[source]

Bases: IObjective

Willmott’s Index of Agreement (d).

A dimensionless goodness-of-fit measure in [0, 1] that is less sensitive to large errors than NSE while still rewarding accurate reproduction of timing, phase, and magnitude.

\[d = 1 - \frac{\sum_t (Q_{obs,t} - Q_{pred,t})^2} {\sum_t (|Q_{pred,t} - \bar{Q}_{obs}| + |Q_{obs,t} - \bar{Q}_{obs}|)^2}\]
Variables:
  • name"index_of_agreement"

  • minimizeFalse

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = False
name: ClassVar[str] = 'index_of_agreement'
class KGE(mask=None)[source]

Bases: IObjective

Kling–Gupta Efficiency (KGE).

Decomposes model error into correlation, bias, and variability components:

\[KGE = 1 - \sqrt{(r-1)^2 + (\alpha-1)^2 + (\beta-1)^2}\]

where \(r\) is the Pearson correlation, \(\alpha = \sigma_p / \sigma_o\) is the variability ratio, and \(\beta = \mu_p / \mu_o\) is the bias ratio. KGE = 1 for a perfect predictor.

Variables:
  • name"kge"

  • minimizeFalse

Raises:

ValueError – If std(observed) == 0 or mean(observed) == 0.

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = False
name: ClassVar[str] = 'kge'
class LogNSE(epsilon=0.01, mask=None)[source]

Bases: IObjective

Nash–Sutcliffe Efficiency on log-transformed flows (Log-NSE).

The log transform de-emphasises large peak errors and gives more weight to low-flow reproduction — complementary to the standard NashSutcliffe when both peak and low-flow performance matter.

\[\text{LogNSE} = 1 - \frac{ \sum_t (\ln(Q_{obs,t}+\varepsilon) - \ln(Q_{pred,t}+\varepsilon))^2 }{ \sum_t (\ln(Q_{obs,t}+\varepsilon) - \overline{\ln(Q_{obs}+\varepsilon)})^2 }\]
Parameters:
  • epsilon (float) – Offset added before the log transform to avoid log(0). Default 0.01.

  • mask (np.ndarray | None) – Optional boolean array selecting the timesteps to score over.

Variables:
  • name"log_nse"

  • minimizeFalse

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = False
name: ClassVar[str] = 'log_nse'
class MAE(mask=None)[source]

Bases: IObjective

Mean absolute error.

Variables:
  • name"mae"

  • minimizeTrue

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = True
name: ClassVar[str] = 'mae'
class MSE(mask=None)[source]

Bases: IObjective

Mean squared error.

Variables:
  • name"mse"

  • minimizeTrue

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = True
name: ClassVar[str] = 'mse'
class NSGAIISolver(pop_size=100, n_gen=200, seed=42, verbose=False, n_jobs=1, callback=None)[source]

Bases: ISolver

Multi-objective NSGA-II calibration solver.

Works with any CalibrationProblem. For multi-objective problems the full Pareto front is returned in pareto_X and pareto_F.

Parameters:
  • pop_size (int) – Population size per generation.

  • n_gen (int) – Total number of generations.

  • seed (int or None) – Random seed for reproducibility (None for random).

  • verbose (bool) – Print pymoo progress output.

  • n_jobs (int) – Parallel workers via ProcessPoolExecutor (1 = sequential).

  • callback (Callable or None) – Optional progress callback invoked once per generation.

solve(problem, **kwargs)[source]

Run NSGA-II and return a CalibrationResult.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides: pop_size, n_gen, seed, verbose, n_jobs, callback.

Returns:

Result with per-generation history and final Pareto front.

Return type:

CalibrationResult

class NashSutcliffe(mask=None)[source]

Bases: IObjective

Nash–Sutcliffe Efficiency (NSE).

\[NSE = 1 - \frac{\sum_t (Q_{obs,t} - Q_{pred,t})^2} {\sum_t (Q_{obs,t} - \bar{Q}_{obs})^2}\]

NSE = 1 for a perfect predictor; 0 for the mean-flow predictor; negative for worse than the mean.

Variables:
  • name"nash_sutcliffe"

  • minimizeFalse

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = False
name: ClassVar[str] = 'nash_sutcliffe'
class PBIAS(mask=None)[source]

Bases: IObjective

Absolute percent bias.

Measures the tendency of the model to over- or under-predict total volume, expressed as a percentage of observed volume. The absolute value is returned so lower is always better.

\[PBIAS = 100 \cdot \left| \frac{\sum_t (Q_{obs,t} - Q_{pred,t})}{\sum_t Q_{obs,t}} \right|\]
Variables:
  • name"pbias"

  • minimizeTrue

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = True
name: ClassVar[str] = 'pbias'
class ParticleSwarmSolver(swarm_size=100, leader_size=100, n_evaluations=10000, epsilons=None, seed=42, record_frequency=1, callback=None, **algorithm_kwargs)[source]

Bases: ISolver

Multi-objective Particle Swarm solver backed by Platypus.

Selects platypus.OMOPSO (ε-dominance archive) when epsilons are provided, otherwise uses platypus.SMPSO.

Parameters:
  • swarm_size (int) – Number of particles in the swarm.

  • leader_size (int) – Size of the leader archive.

  • n_evaluations (int) – Total function-evaluation budget.

  • epsilons (list or None) – Per-objective ε values for OMOPSO; None uses SMPSO. Length must equal the number of objectives.

  • seed (int or None) – Random seed (None for non-deterministic).

  • record_frequency (int) – History snapshot interval (algorithm iterations).

  • algorithm_kwargs (Any) – Additional keyword arguments forwarded to the Platypus algorithm constructor.

solve(problem, **kwargs)[source]

Run the PSO solver and return a CalibrationResult.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides: swarm_size, leader_size, n_evaluations, seed, record_frequency, epsilons, callback.

Returns:

Result with per-iteration history and final Pareto front.

Return type:

CalibrationResult

class PeakWeightedMSE(power=1.0, mask=None)[source]

Bases: IObjective

Peak-weighted mean squared error.

Weights each squared residual by the observed flow at that step relative to the mean observed flow, raised to power, penalising errors during high-flow events.

\[ \begin{align}\begin{aligned}w_t = (Q_{obs,t} / \bar{Q}_{obs})^{p}\\PWMSE = \frac{\sum_t w_t (Q_{obs,t} - Q_{pred,t})^2}{\sum_t w_t}\end{aligned}\end{align} \]

power=1.0 (default) gives linear weighting; larger values sharpen the focus on peaks. power=0.0 reduces to plain MSE.

Parameters:
  • power (float) – Exponent applied to the normalised-flow weights (>= 0).

  • mask (np.ndarray | None) – Optional boolean array selecting the timesteps to score over.

Variables:
  • name"peak_weighted_mse"

  • minimizeTrue

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = True
name: ClassVar[str] = 'peak_weighted_mse'
class PlatypusSolver(algorithm_class, n_evaluations=10000, seed=42, record_frequency=1, callback=None, **algorithm_kwargs)[source]

Bases: ISolver

Generic Platypus multi-objective solver.

Wraps any platypus.Algorithm subclass — NSGA-II, NSGA-III, SPEA2, MOEA/D, GDE3, IBEA, OMOPSO, SMPSO, ε-MOEA, etc. — in the ISolver interface.

The algorithm class and all of its constructor keyword arguments (except problem, which is built internally) are passed directly through, so any algorithm-specific tuning is fully accessible.

Parameters:
  • algorithm_class (type) – A Platypus algorithm class (not instance), e.g. platypus.NSGA2, platypus.SPEA2, platypus.MOEAD.

  • n_evaluations (int) – Total function-evaluation budget. The solver stops when algorithm.nfe >= n_evaluations.

  • seed (int | None) – Seed for random and numpy.random (None for non-deterministic runs).

  • record_frequency (int) – Append a GenerationRecord to history every record_frequency algorithm iterations. Set to a larger value to reduce memory usage on long runs.

  • algorithm_kwargs – All remaining keyword arguments are forwarded verbatim to algorithm_class(problem, **algorithm_kwargs).

Examples:

import platypus
from sparsehydro.calibration import PlatypusSolver

# NSGA-II with explicit population size
solver = PlatypusSolver(platypus.NSGAII, population_size=100, n_evaluations=10_000)

# SPEA2
solver = PlatypusSolver(platypus.SPEA2, population_size=50, n_evaluations=5_000)

# GDE3 (good for real-valued problems)
solver = PlatypusSolver(platypus.GDE3, population_size=80, n_evaluations=8_000)

# ε-MOEA with epsilon archive
solver = PlatypusSolver(
    platypus.EpsMOEA,
    epsilons=[0.01, 0.01],
    population_size=100,
    n_evaluations=10_000,
)

result = solver.solve(problem)
solve(problem, **kwargs)[source]

Run the Platypus algorithm and return a CalibrationResult.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides: n_evaluations, seed, record_frequency, callback. Additional keys are merged into algorithm_kwargs and forwarded to the algorithm constructor.

Returns:

Result with per-iteration history and final Pareto front.

Return type:

CalibrationResult

class ProgressCallback(frequency=1)[source]

Bases: object

Prints a one-line progress summary after every frequency generations.

Output format:

gen=   10  evals=  1000  pareto=  12  mse=1234.5678  nash_sutcliffe=0.7231
Parameters:

frequency (int) – Print every frequency callback invocations (default 1).

class RMSE(mask=None)[source]

Bases: IObjective

Root mean squared error.

Variables:
  • name"rmse"

  • minimizeTrue

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = True
name: ClassVar[str] = 'rmse'
class ScipySolver(method='differential_evolution', objective_index=0, maxiter=1000, seed=42, verbose=False, **kwargs)[source]

Bases: ISolver

Single-objective SciPy calibration solver.

Parameters:
  • method (str) – "differential_evolution" (default) or any scipy.optimize.minimize method string (e.g. "L-BFGS-B").

  • objective_index (int) – Zero-based index of the objective to optimise when the problem has multiple objectives.

  • maxiter (int) – Maximum number of iterations / generations.

  • seed (int or None) – Random seed (used by differential_evolution).

  • verbose (bool) – Print solver progress.

  • kwargs (Any) – Additional keyword arguments forwarded to the underlying SciPy function.

solve(problem, **kwargs)[source]

Run the SciPy solver and return a CalibrationResult.

The Pareto “front” contains exactly one solution — the optimum found for the selected objective.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides: method, objective_index, maxiter, seed, verbose.

Returns:

Result with the single best solution.

Return type:

CalibrationResult

class VolumeRelativeError(mask=None)[source]

Bases: IObjective

Relative total volume error.

Fractional difference between predicted and observed cumulative runoff volume. The absolute value is returned so lower is always better.

\[VRE = \left| \frac{\sum_t Q_{pred,t} - \sum_t Q_{obs,t}}{\sum_t Q_{obs,t}} \right|\]
Variables:
  • name"volume_relative_error"

  • minimizeTrue

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = True
name: ClassVar[str] = 'volume_relative_error'

Calibration Problem#

CalibrationProblem: wraps any IModel with data, observed targets, and objectives.

All column/data mappings — including the observed target and the predicted output — are specified through a single column_map dictionary. Values can be either a column name string (for DataFrame data) or a callable (for any data type).

DataFrame workflow (most common):

from sparsehydro.calibration import CalibrationProblem, NashSutcliffe, PeakWeightedMSE
from sparsehydro.models.rdii import RDIIModel

model = RDIIModel(n_triangles=3)
model.initialize()
model.validate()

problem = CalibrationProblem(
    model=model,
    data=df,
    objectives=[PeakWeightedMSE(), NashSutcliffe()],
    column_map={
        # Data prep: target_col → source_col (rename before model.prepare)
        "rainfall_mm":   "rain",
        "temperature_c": "air_temp_c",
        # Reserved roles (string = column name)
        "observed":  "stormflow",  # column in prepared data → target array
        "predicted": "rdii_cfs",   # column in model.predict() output
    },
)
result = NSGAIISolver().solve(problem)

Generic / callable workflow:

problem = CalibrationProblem(
    model=model,
    data=raw_dict,
    objectives=[PeakWeightedMSE()],
    prepare_fn=lambda d, **kw: build_dataframe(d, **kw),
    column_map={
        # Reserved roles (callable = extractor function)
        "observed":  lambda prepared: prepared["obs"].to_numpy(),
        "predicted": lambda pred_df: pred_df["rdii_cfs"].to_numpy(),
    },
)
class CalibrationProblem(model, data=None, objectives=None, column_map=None, prepare_fn=None, mask=None, **prepare_kwargs)[source]#

Bases: object

Solver-agnostic calibration problem for any IModel.

Bundles a model with input data, preprocessing, observed targets, and objectives. The same problem instance can be passed to any ISolver without modification.

All column/role mappings are expressed through a single column_map dict:

  • Non-reserved entries {target_col: source_col} — rename data[source_col] to target_col before calling model.prepare().

  • Reserved key "observed"str (column name) or callable (prepared_data) np.ndarray. Identifies the calibration target.

  • Reserved key "predicted"str or callable (predict_df) np.ndarray. Identifies the model output to compare.

Parameters:
  • model (IModel) – Model in at least VALIDATED state. Prepared automatically when data is supplied.

  • data (Any) – Input data (any type). Passed through the preprocessing pipeline and then to model.prepare(). May be None if the model is already in PREPARED state, but then column_map["observed"] must be a callable that does not require the prepared data (e.g. a closure).

  • objectives (list[IObjective]) – At least one objective.

  • column_map (dict[str, Any] or None) – Unified mapping dict (see above).

  • prepare_fn (Callable or None) – (data, **prepare_kwargs) prepared_data callable for complex preprocessing. Mutually exclusive with non-reserved column_map rename entries.

  • mask (str or Callable or numpy.ndarray or None) – Problem-level default mask restricting every objective to a subset of timesteps. May be a boolean np.ndarray, a column-name string, or a callable (prepared_data) -> array-like — resolved like observed/predicted. Equivalent to column_map["mask"] (the explicit argument wins if both are given). Individual objectives that carry their own mask override this default. Positions where observed or predicted is NaN are always excluded regardless.

  • prepare_kwargs (Any) – Extra keyword arguments forwarded to prepare_fn.

Masking:

problem = CalibrationProblem(
    model=model, data=df,
    objectives=[NashSutcliffe(), VolumeRelativeError()],
    column_map={"observed": "stormflow", "predicted": "rdii_cfs",
                "mask": "is_storm"},   # bool column in prepared data
)
evaluate(x, penalty_weight=1000000.0)[source]#

Apply a parameter vector, run predict(), and return objectives.

Objective values are in minimisation form: maximised objectives are negated. When penalty_weight > 0 and the model reports inequality constraints, a squared penalty penalty_weight * Σ max(0, g_j)² is added to steer constraint-unaware solvers toward feasible regions. Pass penalty_weight=0.0 when the solver handles constraints natively.

Only parameters with calibrate=True are set from x; fixed parameters (calibrate=False) retain their current values.

Parameters:
  • x (numpy.ndarray) – Parameter vector of length n_params (calibratable only).

  • penalty_weight (float) – Multiplier for the squared-penalty term (default 1e6).

Returns:

1-D array of length n_objectives in minimisation form.

Return type:

numpy.ndarray

make_copy()[source]#

Return a deep-copied CalibrationProblem safe for parallel workers.

The deep-copied model already holds its prepared state; data preparation is not re-run. All mutable state (model, observed array, bounds) is independent from the original.

Return type:

CalibrationProblem

property bounds: tuple[ndarray, ndarray]#

Lower and upper bounds as (xl, xu) arrays.

property constraint_descriptions: list[str]#

Ordered list of inequality constraint descriptions.

property constraint_names: list[str]#

Ordered list of inequality constraint names (empty if unconstrained).

property minimize_flags: list[bool]#

True if the corresponding objective should be minimised.

property n_ieq_constr: int#

Number of inequality constraints reported by the model.

property n_objectives: int#

Number of objectives.

property n_params: int#

Number of calibratable search dimensions (scalars + flattened vector elements).

property objective_names: list[str]#

Objective names in evaluation order.

property param_names: list[str]#

Ordered list of calibrated search-dimension names.

Scalar parameters appear by their own name; each calibratable VectorParameter contributes one entry per element, named "{vector_name}[{index}]".

Calibration Result#

CalibrationResult stores objective values in minimisation form internally: maximised objectives (e.g. NSE, KGE) are negated on the way in and restored via objective_display_values() and to_pareto_dataframe().

Calibration result containers — solver-agnostic.

CalibrationResult stores the Pareto front and per-generation history produced by any ISolver. Objective values are kept in minimisation form internally: maximised objectives are negated on the way in and un-negated on the way out via CalibrationResult.objective_display_values() and CalibrationResult.to_pareto_dataframe().

class CalibrationResult(history, pareto_X, pareto_F, param_names, objective_names, minimize_flags)[source]#

Bases: object

General-purpose container for calibration results.

Produced by any ISolver. Objective values are stored in minimisation form (maximised objectives are negated). Conversion back to display form is handled by objective_display_values() and to_pareto_dataframe().

Parameters:
  • history (list[GenerationRecord]) – One GenerationRecord per generation. May be empty for single-shot solvers.

  • pareto_X (numpy.ndarray) – Parameter matrix for the final Pareto front, shape (m, n_params).

  • pareto_F (numpy.ndarray) – Objective matrix in minimisation form, shape (m, n_obj).

  • param_names (list[str]) – Ordered list of calibrated parameter names.

  • objective_names (list[str]) – Names of each objective (matching objective order).

  • minimize_flags (list[bool]) – True for minimised objectives; False for maximised objectives.

best_by(objective_name)[source]#

Return the parameter vector that is best for the named objective.

“Best” means the lowest value for minimised objectives and the highest for maximised objectives. Internally, pareto_F is always in minimisation form, so argmin always selects the best solution.

Parameters:

objective_name (str) – Name matching one of objective_names.

Returns:

1-D parameter array.

Return type:

numpy.ndarray

Raises:

ValueError – If objective_name is not found.

objective_display_values()[source]#

Return Pareto objective values in display form (un-negated).

Returns:

Array of shape (m, n_obj) with actual objective values.

Return type:

numpy.ndarray

to_pareto_dataframe()[source]#

Return a tidy DataFrame spanning all generations.

Columns: generation, one column per parameter, one column per objective (display-form values), is_pareto (True only for solutions on the final generation’s Pareto front).

Return type:

pandas.DataFrame

class GenerationRecord(generation, X, F, n_pareto)#

Bases: tuple

Per-generation snapshot of the optimizer population.

Parameters:
  • generation (int) – Generation index (1-based).

  • X (numpy.ndarray) – Parameter matrix, shape (pop_size, n_params).

  • F (numpy.ndarray) – Objective matrix in minimisation form, shape (pop_size, n_obj).

  • n_pareto (int) – Number of Pareto-dominant solutions in this generation.

count(value, /)#

Return number of occurrences of value.

index(value, start=0, stop=9223372036854775807, /)#

Return first index of value.

Raises ValueError if the value is not present.

F#

Alias for field number 2

X#

Alias for field number 1

generation#

Alias for field number 0

n_pareto#

Alias for field number 3

Objectives#

Class

Description

MSE

Mean squared error (minimise)

RMSE

Root mean squared error (minimise)

MAE

Mean absolute error (minimise)

PeakWeightedMSE

Flow-weighted MSE — penalises peak-flow errors

NashSutcliffe

Nash-Sutcliffe efficiency (maximise)

KGE

Kling-Gupta efficiency (maximise)

Objective function abstractions for model calibration.

IObjective defines the interface that every calibration objective must implement. Concrete subclasses encapsulate both the direction of optimisation (minimize) and the computation of a scalar score from observed vs predicted arrays.

Built-in objectives#

Class

minimize

Description

MSE

True

Mean squared error

RMSE

True

Root mean squared error

MAE

True

Mean absolute error

PeakWeightedMSE

True

Flow-weighted MSE (peaks penalised)

PBIAS

True

Absolute percent bias (volume balance)

VolumeRelativeError

True

Relative total runoff volume error

NashSutcliffe

False

Nash–Sutcliffe efficiency

LogNSE

False

NSE on log-transformed flows

KGE

False

Kling–Gupta efficiency

IndexOfAgreement

False

Willmott’s Index of Agreement

ConcordanceCorrelationCoefficient

False

Lin’s Concordance Correlation Coefficient

Custom objectives#

Subclass IObjective, set name and minimize, and implement evaluate():

class MyObjective(IObjective):
    name = "my_obj"
    minimize = True

    def evaluate(self, observed, predicted):
        return float(np.sum(np.abs(observed - predicted)))
class ConcordanceCorrelationCoefficient(mask=None)[source]#

Bases: IObjective

Lin’s Concordance Correlation Coefficient (CCC).

Combines precision (Pearson correlation) and accuracy (closeness to the perfect-concordance line) into a single coefficient bounded to [−1, 1]:

\[\rho_c = \frac{2\,\sigma_{op}} {\sigma_o^2 + \sigma_p^2 + (\mu_o - \mu_p)^2}\]

CCC = 1 for perfect agreement between observed and predicted. Unlike Pearson correlation alone, CCC penalises systematic bias and scale differences, making it sensitive to both random and systematic error.

Variables:
  • name"ccc"

  • minimizeFalse

Raises:

ValueError – If both series are constant and equal (denominator zero).

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)#

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]#

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = False#
name: ClassVar[str] = 'ccc'#
class IObjective(mask=None)[source]#

Bases: ABC

Abstract calibration objective.

Subclasses must set the class variables name and minimize and implement evaluate().

Variables:
  • name – Short snake_case identifier (used as column name in result DataFrames).

  • minimizeTrue if lower scores are better; False for objectives like NSE where higher is better.

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)[source]#

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

abstractmethod evaluate(observed, predicted)[source]#

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool]#
name: ClassVar[str]#
class IndexOfAgreement(mask=None)[source]#

Bases: IObjective

Willmott’s Index of Agreement (d).

A dimensionless goodness-of-fit measure in [0, 1] that is less sensitive to large errors than NSE while still rewarding accurate reproduction of timing, phase, and magnitude.

\[d = 1 - \frac{\sum_t (Q_{obs,t} - Q_{pred,t})^2} {\sum_t (|Q_{pred,t} - \bar{Q}_{obs}| + |Q_{obs,t} - \bar{Q}_{obs}|)^2}\]
Variables:
  • name"index_of_agreement"

  • minimizeFalse

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)#

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]#

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = False#
name: ClassVar[str] = 'index_of_agreement'#
class KGE(mask=None)[source]#

Bases: IObjective

Kling–Gupta Efficiency (KGE).

Decomposes model error into correlation, bias, and variability components:

\[KGE = 1 - \sqrt{(r-1)^2 + (\alpha-1)^2 + (\beta-1)^2}\]

where \(r\) is the Pearson correlation, \(\alpha = \sigma_p / \sigma_o\) is the variability ratio, and \(\beta = \mu_p / \mu_o\) is the bias ratio. KGE = 1 for a perfect predictor.

Variables:
  • name"kge"

  • minimizeFalse

Raises:

ValueError – If std(observed) == 0 or mean(observed) == 0.

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)#

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]#

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = False#
name: ClassVar[str] = 'kge'#
class LogNSE(epsilon=0.01, mask=None)[source]#

Bases: IObjective

Nash–Sutcliffe Efficiency on log-transformed flows (Log-NSE).

The log transform de-emphasises large peak errors and gives more weight to low-flow reproduction — complementary to the standard NashSutcliffe when both peak and low-flow performance matter.

\[\text{LogNSE} = 1 - \frac{ \sum_t (\ln(Q_{obs,t}+\varepsilon) - \ln(Q_{pred,t}+\varepsilon))^2 }{ \sum_t (\ln(Q_{obs,t}+\varepsilon) - \overline{\ln(Q_{obs}+\varepsilon)})^2 }\]
Parameters:
  • epsilon (float) – Offset added before the log transform to avoid log(0). Default 0.01.

  • mask (np.ndarray | None) – Optional boolean array selecting the timesteps to score over.

Variables:
  • name"log_nse"

  • minimizeFalse

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)#

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]#

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = False#
name: ClassVar[str] = 'log_nse'#
class MAE(mask=None)[source]#

Bases: IObjective

Mean absolute error.

Variables:
  • name"mae"

  • minimizeTrue

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)#

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]#

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = True#
name: ClassVar[str] = 'mae'#
class MSE(mask=None)[source]#

Bases: IObjective

Mean squared error.

Variables:
  • name"mse"

  • minimizeTrue

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)#

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]#

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = True#
name: ClassVar[str] = 'mse'#
class NashSutcliffe(mask=None)[source]#

Bases: IObjective

Nash–Sutcliffe Efficiency (NSE).

\[NSE = 1 - \frac{\sum_t (Q_{obs,t} - Q_{pred,t})^2} {\sum_t (Q_{obs,t} - \bar{Q}_{obs})^2}\]

NSE = 1 for a perfect predictor; 0 for the mean-flow predictor; negative for worse than the mean.

Variables:
  • name"nash_sutcliffe"

  • minimizeFalse

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)#

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]#

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = False#
name: ClassVar[str] = 'nash_sutcliffe'#
class PBIAS(mask=None)[source]#

Bases: IObjective

Absolute percent bias.

Measures the tendency of the model to over- or under-predict total volume, expressed as a percentage of observed volume. The absolute value is returned so lower is always better.

\[PBIAS = 100 \cdot \left| \frac{\sum_t (Q_{obs,t} - Q_{pred,t})}{\sum_t Q_{obs,t}} \right|\]
Variables:
  • name"pbias"

  • minimizeTrue

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)#

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]#

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = True#
name: ClassVar[str] = 'pbias'#
class PeakWeightedMSE(power=1.0, mask=None)[source]#

Bases: IObjective

Peak-weighted mean squared error.

Weights each squared residual by the observed flow at that step relative to the mean observed flow, raised to power, penalising errors during high-flow events.

\[ \begin{align}\begin{aligned}w_t = (Q_{obs,t} / \bar{Q}_{obs})^{p}\\PWMSE = \frac{\sum_t w_t (Q_{obs,t} - Q_{pred,t})^2}{\sum_t w_t}\end{aligned}\end{align} \]

power=1.0 (default) gives linear weighting; larger values sharpen the focus on peaks. power=0.0 reduces to plain MSE.

Parameters:
  • power (float) – Exponent applied to the normalised-flow weights (>= 0).

  • mask (np.ndarray | None) – Optional boolean array selecting the timesteps to score over.

Variables:
  • name"peak_weighted_mse"

  • minimizeTrue

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)#

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]#

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = True#
name: ClassVar[str] = 'peak_weighted_mse'#
class RMSE(mask=None)[source]#

Bases: IObjective

Root mean squared error.

Variables:
  • name"rmse"

  • minimizeTrue

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)#

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]#

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = True#
name: ClassVar[str] = 'rmse'#
class VolumeRelativeError(mask=None)[source]#

Bases: IObjective

Relative total volume error.

Fractional difference between predicted and observed cumulative runoff volume. The absolute value is returned so lower is always better.

\[VRE = \left| \frac{\sum_t Q_{pred,t} - \sum_t Q_{obs,t}}{\sum_t Q_{obs,t}} \right|\]
Variables:
  • name"volume_relative_error"

  • minimizeTrue

Store an optional per-objective boolean mask.

Parameters:

mask (numpy.ndarray or None) – Boolean array selecting the timesteps this objective is computed over. Applied by compute() unless overridden by an explicit mask argument. None (default) uses all values. Column-name / callable mask specifications are resolved by CalibrationProblem, not here — pass a boolean array when using an objective standalone.

compute(observed, predicted, mask=None)#

Evaluate the objective over a selected subset of timesteps.

Positions where observed or predicted is NaN are always excluded, in addition to any boolean mask. The effective mask is the explicit mask argument when supplied, otherwise the objective’s own mask (an explicit argument wins — this lets CalibrationProblem apply a problem-level default while honouring per-objective overrides).

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

  • mask (numpy.ndarray or None) – Boolean array of the same length as observed. Only positions where mask is True are included. None (default) falls back to mask.

Returns:

Scalar objective value computed over the selected subset.

Return type:

float

Raises:
  • TypeError – If the effective mask is a column name or callable (those must be resolved via CalibrationProblem).

  • ValueError – If the mask length does not match observed, or if no elements remain after masking and NaN removal.

evaluate(observed, predicted)[source]#

Compute a scalar score from observed and predicted arrays.

Parameters:
  • observed (numpy.ndarray) – 1-D array of observed values.

  • predicted (numpy.ndarray) – 1-D array of predicted values (same shape).

Returns:

Scalar objective value.

Return type:

float

Raises:

ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).

minimize: ClassVar[bool] = True#
name: ClassVar[str] = 'volume_relative_error'#

Solvers#

All solvers implement ISolver and return a CalibrationResult.

Class

Algorithm

Extra dep

NSGAIISolver

NSGA-II (pymoo)

pymoo

ScipySolver

SciPy minimisers

scipy

PlatypusSolver

Any Platypus algorithm

platypus-opt

ParticleSwarmSolver

SMPSO / OMOPSO (PSO)

platypus-opt

sparsehydro.calibration.solvers — solver abstractions and implementations.

class ISolver[source]

Bases: ABC

Abstract calibration solver.

All solvers accept a CalibrationProblem and return a CalibrationResult.

solve() accepts **kwargs that override constructor-level settings for that call only — the solver instance is not mutated. This lets the same solver be reused for both quick exploratory runs and full production runs:

solver = NSGAIISolver(pop_size=100, n_gen=200)
quick  = solver.solve(problem, n_gen=5)    # fast sanity check
full   = solver.solve(problem)             # original settings

Minimal implementation:

class MySolver(ISolver):
    def solve(self, problem: CalibrationProblem, **kwargs) -> CalibrationResult:
        x_best = ...          # your optimisation logic
        F_best = problem.evaluate(x_best).reshape(1, -1)
        return CalibrationResult(
            history=[],
            pareto_X=x_best.reshape(1, -1),
            pareto_F=F_best,
            param_names=problem.param_names,
            objective_names=problem.objective_names,
            minimize_flags=problem.minimize_flags,
        )
abstractmethod solve(problem, **kwargs)[source]

Run the solver and return results.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides for solver settings (e.g. n_gen=10). Each solver documents which keys are recognised.

Returns:

Calibration result with Pareto front and generation history.

Return type:

CalibrationResult

class NSGAIISolver(pop_size=100, n_gen=200, seed=42, verbose=False, n_jobs=1, callback=None)[source]

Bases: ISolver

Multi-objective NSGA-II calibration solver.

Works with any CalibrationProblem. For multi-objective problems the full Pareto front is returned in pareto_X and pareto_F.

Parameters:
  • pop_size (int) – Population size per generation.

  • n_gen (int) – Total number of generations.

  • seed (int or None) – Random seed for reproducibility (None for random).

  • verbose (bool) – Print pymoo progress output.

  • n_jobs (int) – Parallel workers via ProcessPoolExecutor (1 = sequential).

  • callback (Callable or None) – Optional progress callback invoked once per generation.

solve(problem, **kwargs)[source]

Run NSGA-II and return a CalibrationResult.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides: pop_size, n_gen, seed, verbose, n_jobs, callback.

Returns:

Result with per-generation history and final Pareto front.

Return type:

CalibrationResult

class ParticleSwarmSolver(swarm_size=100, leader_size=100, n_evaluations=10000, epsilons=None, seed=42, record_frequency=1, callback=None, **algorithm_kwargs)[source]

Bases: ISolver

Multi-objective Particle Swarm solver backed by Platypus.

Selects platypus.OMOPSO (ε-dominance archive) when epsilons are provided, otherwise uses platypus.SMPSO.

Parameters:
  • swarm_size (int) – Number of particles in the swarm.

  • leader_size (int) – Size of the leader archive.

  • n_evaluations (int) – Total function-evaluation budget.

  • epsilons (list or None) – Per-objective ε values for OMOPSO; None uses SMPSO. Length must equal the number of objectives.

  • seed (int or None) – Random seed (None for non-deterministic).

  • record_frequency (int) – History snapshot interval (algorithm iterations).

  • algorithm_kwargs (Any) – Additional keyword arguments forwarded to the Platypus algorithm constructor.

solve(problem, **kwargs)[source]

Run the PSO solver and return a CalibrationResult.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides: swarm_size, leader_size, n_evaluations, seed, record_frequency, epsilons, callback.

Returns:

Result with per-iteration history and final Pareto front.

Return type:

CalibrationResult

class PlatypusSolver(algorithm_class, n_evaluations=10000, seed=42, record_frequency=1, callback=None, **algorithm_kwargs)[source]

Bases: ISolver

Generic Platypus multi-objective solver.

Wraps any platypus.Algorithm subclass — NSGA-II, NSGA-III, SPEA2, MOEA/D, GDE3, IBEA, OMOPSO, SMPSO, ε-MOEA, etc. — in the ISolver interface.

The algorithm class and all of its constructor keyword arguments (except problem, which is built internally) are passed directly through, so any algorithm-specific tuning is fully accessible.

Parameters:
  • algorithm_class (type) – A Platypus algorithm class (not instance), e.g. platypus.NSGA2, platypus.SPEA2, platypus.MOEAD.

  • n_evaluations (int) – Total function-evaluation budget. The solver stops when algorithm.nfe >= n_evaluations.

  • seed (int | None) – Seed for random and numpy.random (None for non-deterministic runs).

  • record_frequency (int) – Append a GenerationRecord to history every record_frequency algorithm iterations. Set to a larger value to reduce memory usage on long runs.

  • algorithm_kwargs – All remaining keyword arguments are forwarded verbatim to algorithm_class(problem, **algorithm_kwargs).

Examples:

import platypus
from sparsehydro.calibration import PlatypusSolver

# NSGA-II with explicit population size
solver = PlatypusSolver(platypus.NSGAII, population_size=100, n_evaluations=10_000)

# SPEA2
solver = PlatypusSolver(platypus.SPEA2, population_size=50, n_evaluations=5_000)

# GDE3 (good for real-valued problems)
solver = PlatypusSolver(platypus.GDE3, population_size=80, n_evaluations=8_000)

# ε-MOEA with epsilon archive
solver = PlatypusSolver(
    platypus.EpsMOEA,
    epsilons=[0.01, 0.01],
    population_size=100,
    n_evaluations=10_000,
)

result = solver.solve(problem)
solve(problem, **kwargs)[source]

Run the Platypus algorithm and return a CalibrationResult.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides: n_evaluations, seed, record_frequency, callback. Additional keys are merged into algorithm_kwargs and forwarded to the algorithm constructor.

Returns:

Result with per-iteration history and final Pareto front.

Return type:

CalibrationResult

class ScipySolver(method='differential_evolution', objective_index=0, maxiter=1000, seed=42, verbose=False, **kwargs)[source]

Bases: ISolver

Single-objective SciPy calibration solver.

Parameters:
  • method (str) – "differential_evolution" (default) or any scipy.optimize.minimize method string (e.g. "L-BFGS-B").

  • objective_index (int) – Zero-based index of the objective to optimise when the problem has multiple objectives.

  • maxiter (int) – Maximum number of iterations / generations.

  • seed (int or None) – Random seed (used by differential_evolution).

  • verbose (bool) – Print solver progress.

  • kwargs (Any) – Additional keyword arguments forwarded to the underlying SciPy function.

solve(problem, **kwargs)[source]

Run the SciPy solver and return a CalibrationResult.

The Pareto “front” contains exactly one solution — the optimum found for the selected objective.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides: method, objective_index, maxiter, seed, verbose.

Returns:

Result with the single best solution.

Return type:

CalibrationResult

Solver Base#

Abstract solver interface.

class ISolver[source]#

Bases: ABC

Abstract calibration solver.

All solvers accept a CalibrationProblem and return a CalibrationResult.

solve() accepts **kwargs that override constructor-level settings for that call only — the solver instance is not mutated. This lets the same solver be reused for both quick exploratory runs and full production runs:

solver = NSGAIISolver(pop_size=100, n_gen=200)
quick  = solver.solve(problem, n_gen=5)    # fast sanity check
full   = solver.solve(problem)             # original settings

Minimal implementation:

class MySolver(ISolver):
    def solve(self, problem: CalibrationProblem, **kwargs) -> CalibrationResult:
        x_best = ...          # your optimisation logic
        F_best = problem.evaluate(x_best).reshape(1, -1)
        return CalibrationResult(
            history=[],
            pareto_X=x_best.reshape(1, -1),
            pareto_F=F_best,
            param_names=problem.param_names,
            objective_names=problem.objective_names,
            minimize_flags=problem.minimize_flags,
        )
abstractmethod solve(problem, **kwargs)[source]#

Run the solver and return results.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides for solver settings (e.g. n_gen=10). Each solver documents which keys are recognised.

Returns:

Calibration result with Pareto front and generation history.

Return type:

CalibrationResult

NSGA-II Solver#

Requires pymoo:

pip install pymoo

NSGA-II multi-objective solver backed by pymoo.

Requires the optional pymoo dependency:

pip install sparsehydro[rdii]

The solver wraps any CalibrationProblem inside a pymoo.ElementwiseProblem adapter and runs NSGA-II with SBX crossover and polynomial mutation. All objectives are passed to NSGA-II in minimisation form (maximised objectives are negated by evaluate()).

class NSGAIISolver(pop_size=100, n_gen=200, seed=42, verbose=False, n_jobs=1, callback=None)[source]#

Bases: ISolver

Multi-objective NSGA-II calibration solver.

Works with any CalibrationProblem. For multi-objective problems the full Pareto front is returned in pareto_X and pareto_F.

Parameters:
  • pop_size (int) – Population size per generation.

  • n_gen (int) – Total number of generations.

  • seed (int or None) – Random seed for reproducibility (None for random).

  • verbose (bool) – Print pymoo progress output.

  • n_jobs (int) – Parallel workers via ProcessPoolExecutor (1 = sequential).

  • callback (Callable or None) – Optional progress callback invoked once per generation.

solve(problem, **kwargs)[source]#

Run NSGA-II and return a CalibrationResult.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides: pop_size, n_gen, seed, verbose, n_jobs, callback.

Returns:

Result with per-generation history and final Pareto front.

Return type:

CalibrationResult

SciPy Solver#

Requires scipy:

pip install scipy

SciPy-backed single-objective calibration solver.

Requires the optional scipy dependency:

pip install sparsehydro[rdii]

For multi-objective calibration problems, only one objective (selected by objective_index) is optimised; the remaining objectives are evaluated at the final solution and stored in the result for reference.

Two solver modes are supported:

  • "differential_evolution" (default) — global stochastic optimiser; uses parameter bounds directly; recommended for non-convex problems.

  • Any scipy.optimize.minimize method string (e.g. "L-BFGS-B") — gradient-based local optimiser; starts from the midpoint of each bound.

class ScipySolver(method='differential_evolution', objective_index=0, maxiter=1000, seed=42, verbose=False, **kwargs)[source]#

Bases: ISolver

Single-objective SciPy calibration solver.

Parameters:
  • method (str) – "differential_evolution" (default) or any scipy.optimize.minimize method string (e.g. "L-BFGS-B").

  • objective_index (int) – Zero-based index of the objective to optimise when the problem has multiple objectives.

  • maxiter (int) – Maximum number of iterations / generations.

  • seed (int or None) – Random seed (used by differential_evolution).

  • verbose (bool) – Print solver progress.

  • kwargs (Any) – Additional keyword arguments forwarded to the underlying SciPy function.

solve(problem, **kwargs)[source]#

Run the SciPy solver and return a CalibrationResult.

The Pareto “front” contains exactly one solution — the optimum found for the selected objective.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides: method, objective_index, maxiter, seed, verbose.

Returns:

Result with the single best solution.

Return type:

CalibrationResult

Platypus Solver#

Wraps any platypus.Algorithm subclass — NSGA-II, NSGA-III, SPEA2, MOEA/D, GDE3, IBEA, ε-MOEA, and more — behind the uniform ISolver interface.

Requires platypus-opt:

pip install platypus-opt

Generic Platypus multi-objective solver.

Wraps any platypus.Algorithm subclass so that the full Platypus suite — NSGA-II, NSGA-III, SPEA2, MOEA/D, GDE3, IBEA, OMOPSO, SMPSO, ε-MOEA, and more — can calibrate any CalibrationProblem.

Requires the optional platypus dependency:

pip install sparsehydro[platypus]

Example usage:

import platypus
from sparsehydro.calibration import PlatypusSolver

# Any Platypus algorithm, any keyword arguments
solver = PlatypusSolver(platypus.NSGAII, population_size=100, n_evaluations=10_000)
solver = PlatypusSolver(platypus.SPEA2, population_size=50, n_evaluations=5_000)
solver = PlatypusSolver(platypus.GDE3, population_size=80, n_evaluations=8_000)
solver = PlatypusSolver(platypus.IBEA, population_size=100, n_evaluations=10_000)
class ParticleSwarmSolver(swarm_size=100, leader_size=100, n_evaluations=10000, epsilons=None, seed=42, record_frequency=1, callback=None, **algorithm_kwargs)[source]#

Bases: ISolver

Multi-objective Particle Swarm solver backed by Platypus.

Selects platypus.OMOPSO (ε-dominance archive) when epsilons are provided, otherwise uses platypus.SMPSO.

Parameters:
  • swarm_size (int) – Number of particles in the swarm.

  • leader_size (int) – Size of the leader archive.

  • n_evaluations (int) – Total function-evaluation budget.

  • epsilons (list or None) – Per-objective ε values for OMOPSO; None uses SMPSO. Length must equal the number of objectives.

  • seed (int or None) – Random seed (None for non-deterministic).

  • record_frequency (int) – History snapshot interval (algorithm iterations).

  • algorithm_kwargs (Any) – Additional keyword arguments forwarded to the Platypus algorithm constructor.

solve(problem, **kwargs)[source]#

Run the PSO solver and return a CalibrationResult.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides: swarm_size, leader_size, n_evaluations, seed, record_frequency, epsilons, callback.

Returns:

Result with per-iteration history and final Pareto front.

Return type:

CalibrationResult

class PlatypusSolver(algorithm_class, n_evaluations=10000, seed=42, record_frequency=1, callback=None, **algorithm_kwargs)[source]#

Bases: ISolver

Generic Platypus multi-objective solver.

Wraps any platypus.Algorithm subclass — NSGA-II, NSGA-III, SPEA2, MOEA/D, GDE3, IBEA, OMOPSO, SMPSO, ε-MOEA, etc. — in the ISolver interface.

The algorithm class and all of its constructor keyword arguments (except problem, which is built internally) are passed directly through, so any algorithm-specific tuning is fully accessible.

Parameters:
  • algorithm_class (type) – A Platypus algorithm class (not instance), e.g. platypus.NSGA2, platypus.SPEA2, platypus.MOEAD.

  • n_evaluations (int) – Total function-evaluation budget. The solver stops when algorithm.nfe >= n_evaluations.

  • seed (int | None) – Seed for random and numpy.random (None for non-deterministic runs).

  • record_frequency (int) – Append a GenerationRecord to history every record_frequency algorithm iterations. Set to a larger value to reduce memory usage on long runs.

  • algorithm_kwargs – All remaining keyword arguments are forwarded verbatim to algorithm_class(problem, **algorithm_kwargs).

Examples:

import platypus
from sparsehydro.calibration import PlatypusSolver

# NSGA-II with explicit population size
solver = PlatypusSolver(platypus.NSGAII, population_size=100, n_evaluations=10_000)

# SPEA2
solver = PlatypusSolver(platypus.SPEA2, population_size=50, n_evaluations=5_000)

# GDE3 (good for real-valued problems)
solver = PlatypusSolver(platypus.GDE3, population_size=80, n_evaluations=8_000)

# ε-MOEA with epsilon archive
solver = PlatypusSolver(
    platypus.EpsMOEA,
    epsilons=[0.01, 0.01],
    population_size=100,
    n_evaluations=10_000,
)

result = solver.solve(problem)
solve(problem, **kwargs)[source]#

Run the Platypus algorithm and return a CalibrationResult.

Parameters:
  • problem (CalibrationProblem) – Calibration problem wrapping model + data + objectives.

  • kwargs – Per-call overrides: n_evaluations, seed, record_frequency, callback. Additional keys are merged into algorithm_kwargs and forwarded to the algorithm constructor.

Returns:

Result with per-iteration history and final Pareto front.

Return type:

CalibrationResult

Particle Swarm Solver#

ParticleSwarmSolver is defined in the same module as PlatypusSolver. It wraps platypus.SMPSO (default) or platypus.OMOPSO (when epsilons are provided) behind the standard ISolver interface.

Requires platypus-opt:

pip install platypus-opt

See Platypus Solver above — ParticleSwarmSolver is exported from sparsehydro.calibration.solvers.platypus_solver and from the top-level sparsehydro.calibration namespace.