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(plussparsehydro.models.rdiiandsparsehydro.models.unithydrograph)Calibration —
sparsehydro.calibrationEvent detection —
sparsehydro.eventsStormflow filters —
sparsehydro.filtersVisualization —
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:
objectMetadata for a single column in a model’s
predict()output DataFrame.Register one
FieldRecordper output column duringinitialize()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) –
Truewhen this column can serve as thepredictedcolumn in aCalibrationProblem— i.e. it is a flow-rate or quantity directly comparable to an observed signal. Diagnostic columns (depth, excess, datetime) should beFalse.
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:
ABCAbstract interface for a parsimonious hydrological model.
Model name
Every concrete subclass must define a
model_nameclass 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_nameraisesTypeErrorimmediately.Lifecycle
Concrete subclasses must advance
self._stateas each method completes:CREATED → INITIALIZED → VALIDATED → PREPARED → PREDICTED → FINALIZED
Parameter registry
Parameters are registered during
initialize()viaregister_scalar_parameter()andregister_vector_parameter(). Calibration tools retrieve them by name throughget_scalar_parameter()andget_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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)[source]
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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
FieldRecordfor name.
- get_scalar_parameter(name)[source]
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)[source]
Retrieve a registered vector parameter by name.
- inequality_constraints()[source]
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- abstractmethod initialize(*args, **kwargs)[source]
Set up model structure and register parameters.
Called once before
validate(). Implementations register everyScalarParameterandVectorParameterhere and advance the state toINITIALIZED.
- is_created()[source]
Return whether the model is in the
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()[source]
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()[source]
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()[source]
Return whether the model is in the
PREDICTEDstate.- Returns:
Trueifpredict()has completed.- Return type:
- is_prepared()[source]
Return whether the model is in the
PREPAREDstate.- Returns:
Trueifprepare()has completed.- Return type:
- is_validated()[source]
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()[source]
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()[source]
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- abstractmethod predict(*args, **kwargs)[source]
Execute the model and return its outputs.
- Parameters:
- Returns:
Model outputs, typically with a predicted-flow column.
- Return type:
- abstractmethod prepare(*args, **kwargs)[source]
Load and pre-process forcing/input data.
- read_flat_parameter(name)[source]
Read one value addressed the same way as
apply_flat_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:
- 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:
- 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
VALIDATEDwhen returningTrue.- Returns:
Trueif the model is valid and ready forprepare();Falseotherwise.- Return type:
- property inequality_constraint_descriptions: list[str]
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str]
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- class ITorchModel[source]
-
Abstract interface for differentiable parsimonious models.
Inherits from both
IModelandtorch.nn.Module. Subclasses must implement all fiveIModellifecycle methods andforward()— the differentiable computation graph.The default
predict()implementation callsforward()and advances model state toPREDICTED. Overridepredict()if additional pre/post-processing aroundforward()is required.Gradient-tracked parameters should be declared as
torch.nn.Parameterattributes so that PyTorch optimisers can discover them viaModule.parameters(). The sparsehydroregister_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
fnrecursively 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand a name in values is not registered.
- bfloat16()
Casts all floating point parameters and buffers to
bfloat16datatype.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
doubledatatype.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
floatdatatype.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.Parameterattributes.- 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:
- get_buffer(target)
Return the buffer given by
targetif it exists, otherwise throw an error.See the docstring for
get_submodulefor a more detailed explanation of this method’s functionality as well as how to correctly specifytarget.- Parameters:
target (str) – The fully-qualified string name of the buffer to look for. (See
get_submodulefor how to specify a fully-qualified string.)- Returns:
The buffer referenced by
target- Return type:
- 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:
- get_output_field(name)
Return the
FieldRecordfor name.
- get_parameter(target)
Return the parameter given by
targetif it exists, otherwise throw an error.See the docstring for
get_submodulefor a more detailed explanation of this method’s functionality as well as how to correctly specifytarget.- Parameters:
target (str) – The fully-qualified string name of the Parameter to look for. (See
get_submodulefor 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.
- get_submodule(target)
Return the submodule given by
targetif it exists, otherwise throw an error.For example, let’s say you have an
nn.ModuleAthat 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.ModuleA.Awhich has a nested submodulenet_b, which itself has two submodulesnet_candlinear.net_cthen has a submoduleconv.)To check whether or not we have the
linearsubmodule, we would callget_submodule("net_b.linear"). To check whether we have theconvsubmodule, we would callget_submodule("net_b.net_c.conv").The runtime of
get_submoduleis bounded by the degree of module nesting intarget. A query againstnamed_modulesachieves 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_submoduleshould 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:
- 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.
- half()
Casts all floating point parameters and buffers to
halfdatatype.Note
This method modifies the module in-place.
- Returns:
self
- Return type:
Module
- inequality_constraints()
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- abstractmethod initialize(*args, **kwargs)
Set up model structure and register parameters.
Called once before
validate(). Implementations register everyScalarParameterandVectorParameterhere and advance the state toINITIALIZED.
- 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
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()
Return whether the model is in the
PREDICTEDstate.- Returns:
Trueifpredict()has completed.- Return type:
- is_prepared()
Return whether the model is in the
PREPAREDstate.- Returns:
Trueifprepare()has completed.- Return type:
- is_validated()
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- load_state_dict(state_dict, strict=True, assign=False)
Copy parameters and buffers from
state_dictinto this module and its descendants.If
strictisTrue, then the keys ofstate_dictmust exactly match the keys returned by this module’sstate_dict()function.Warning
If
assignisTruethe optimizer must be created after the call toload_state_dictunlessget_swap_module_params_on_conversion()isTrue.- Parameters:
state_dict (dict) – a dict containing parameters and persistent buffers.
strict (bool, optional) – whether to strictly enforce that the keys in
state_dictmatch the keys returned by this module’sstate_dict()function. Default:Trueassign (bool, optional) – When set to
False, the properties of the tensors in the current module are preserved whereas setting it toTruepreserves properties of the Tensors in the state dict. The only exception is therequires_gradfield ofParameterfor which the value from the module is preserved. Default:False
- Returns:
missing_keysis a list of str containing any keys that are expectedby this module but missing from the provided
state_dict.
unexpected_keysis a list of str containing the keys that are notexpected by this module but present in the provided
state_dict.
- Return type:
NamedTuplewithmissing_keysandunexpected_keysfields
Note
If a parameter or buffer is registered as
Noneand its corresponding key exists instate_dict,load_state_dict()will raise aRuntimeError.
- 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,
lwill 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:
- Yields:
(str, Module) – Tuple of name and module
Note
Duplicate modules are returned only once. In the following example,
lwill 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,calibratableanddescriptioncolumns.- Return type:
- 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:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- predict(*args, **kwargs)[source]
Run the differentiable forward pass and advance model state.
Delegates to
forward()and sets the model state toPREDICTED.- 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:
- abstractmethod prepare(*args, **kwargs)
Load and pre-process forcing/input data.
- read_flat_parameter(name)
Read one value addressed the same way as
apply_flat_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_meanis 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 settingpersistenttoFalse. The only difference between a persistent buffer and a non-persistent buffer is that the latter will not be a part of this module’sstate_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 ascuda, are ignored. IfNone, the buffer is not included in the module’sstate_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_kwargsisFalseor 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 theforward. The hook can modify the output. It can modify the input inplace but it will not have effect on forward since this is called afterforward()is called. The hook should have the following signature:hook(module, args, output) -> None or modified output
If
with_kwargsisTrue, the forward hook will be passed thekwargsgiven 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 providedhookwill be fired before all existingforwardhooks on thistorch.nn.Module. Otherwise, the providedhookwill be fired after all existingforwardhooks on thistorch.nn.Module. Note that globalforwardhooks registered withregister_module_forward_hook()will fire before all hooks registered by this method. Default:Falsewith_kwargs (bool) – If
True, thehookwill be passed the kwargs given to the forward function. Default:Falsealways_call (bool) – If
Truethehookwill 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_kwargsis 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 theforward. 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_kwargsis 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
hookwill be fired before all existingforward_prehooks on thistorch.nn.Module. Otherwise, the providedhookwill be fired after all existingforward_prehooks on thistorch.nn.Module. Note that globalforward_prehooks registered withregister_module_forward_pre_hook()will fire before all hooks registered by this method. Default:Falsewith_kwargs (bool) – If true, the
hookwill 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:
Ordinarily, the hook fires when the gradients are computed with respect to the module inputs.
If none of the module inputs require gradients, the hook will fire when the gradients are computed with respect to module outputs.
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_inputandgrad_outputare 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 ofgrad_inputin subsequent computations.grad_inputwill only correspond to the inputs given as positional arguments and all kwarg arguments are ignored. Entries ingrad_inputandgrad_outputwill beNonefor 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
hookwill be fired before all existingbackwardhooks on thistorch.nn.Module. Otherwise, the providedhookwill be fired after all existingbackwardhooks on thistorch.nn.Module. Note that globalbackwardhooks registered withregister_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_outputis 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 ofgrad_outputin subsequent computations. Entries ingrad_outputwill beNonefor 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
hookwill be fired before all existingbackward_prehooks on thistorch.nn.Module. Otherwise, the providedhookwill be fired after all existingbackward_prehooks on thistorch.nn.Module. Note that globalbackward_prehooks registered withregister_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
moduleargument is the current module that this hook is registered on, and theincompatible_keysargument is aNamedTupleconsisting of attributesmissing_keysandunexpected_keys.missing_keysis alistofstrcontaining the missing keys andunexpected_keysis alistofstrcontaining the unexpected keys.The given incompatible_keys can be modified inplace if needed.
Note that the checks performed when calling
load_state_dict()withstrict=Trueare affected by modifications the hook makes tomissing_keysorunexpected_keys, as expected. Additions to either set of keys will result in an error being thrown whenstrict=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 ascuda, are ignored. IfNone, the parameter is not included in the module’sstate_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_dictinplace.
- 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_dictcall 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:
- 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:
- 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_gradattributes 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 correspondingget_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
targetif it exists, otherwise throw an error.Note
If
strictis set toFalse(default), the method will replace an existing submodule or create a new submodule if the parent module exists. Ifstrictis set toTrue, 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.ModuleAthat looks like this:A( (net_b): Module( (net_c): Module( (conv): Conv2d(3, 3, 3) ) (linear): Linear(3, 3) ) )(The diagram shows an
nn.ModuleA.Ahas a nested submodulenet_b, which itself has two submodulesnet_candlinear.net_cthen has a submoduleconv.)To override the
Conv2dwith a new submoduleLinear, you could callset_submodule("net_b.net_c.conv", nn.Linear(1, 1))wherestrictcould beTrueorFalseTo add a new submodule
Conv2dto the existingnet_bmodule, you would callset_submodule("net_b.conv", nn.Conv2d(1, 1, 1)).In the above if you set
strict=Trueand callset_submodule("net_b.conv", nn.Conv2d(1, 1, 1), strict=True), an AttributeError will be raised becausenet_bdoes not have a submodule namedconv.- 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. IfTrue, 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
targetstring is empty or ifmoduleis not an instance ofnn.Module.AttributeError – If at any point along the path resulting from the
targetstring the (sub)path resolves to a non-existent attribute name or an object that is not an instance ofnn.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
Noneare 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 fordestination,prefixandkeep_varsin order. However, this is being deprecated and keyword arguments will be enforced in future releases.Warning
Please avoid the use of argument
destinationas 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
OrderedDictwill 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
Tensors returned in the state dict are detached from autograd. If it’s set toTrue, detaching will not be performed. Default:False.
- Returns:
a dictionary containing a whole state of the module
- Return type:
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 complexdtypes. In addition, this method will only cast the floating point or complex parameters and buffers todtype(if given). The integral parameters and buffers will be moveddevice, if that is given, but with dtypes unchanged. Whennon_blockingis 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 moduledtype (
torch.dtype) – the desired floating point or complex dtype of the parameters and buffers in this moduletensor (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
VALIDATEDwhen returningTrue.- Returns:
Trueif the model is valid and ready forprepare();Falseotherwise.- Return type:
- 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.Optimizerfor 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
- call_super_init: bool = False
- dump_patches: bool = False
- property inequality_constraint_descriptions: list[str]
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str]
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- training: bool
- class IUnitHydroComponent[source]
-
Abstract base for unit hydrograph components used within
RDIIModel.Extends
IModelwith 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 (
Rfor RTK triangles,Afor Nash/Gamma UH shapes). When a component is embedded inRDIIModel, that composite manages the fractionR_iseparately 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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:
- Returns:
1-D ordinate array [1/hr].
- Return type:
- get_output_field(name)
Return the
FieldRecordfor name.
- get_scalar_parameter(name)
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)
Retrieve a registered vector parameter by name.
- inequality_constraints()
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- abstractmethod initialize(*args, **kwargs)
Set up model structure and register parameters.
Called once before
validate(). Implementations register everyScalarParameterandVectorParameterhere and advance the state toINITIALIZED.
- is_created()
Return whether the model is in the
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()
Return whether the model is in the
PREDICTEDstate.- Returns:
Trueifpredict()has completed.- Return type:
- is_prepared()
Return whether the model is in the
PREPAREDstate.- Returns:
Trueifprepare()has completed.- Return type:
- is_validated()
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- abstractmethod predict(*args, **kwargs)
Execute the model and return its outputs.
- Parameters:
- Returns:
Model outputs, typically with a predicted-flow column.
- Return type:
- abstractmethod prepare(*args, **kwargs)
Load and pre-process forcing/input data.
- read_flat_parameter(name)
Read one value addressed the same way as
apply_flat_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:
- 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:
- 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
VALIDATEDwhen returningTrue.- Returns:
Trueif the model is valid and ready forprepare();Falseotherwise.- Return type:
- property inequality_constraint_descriptions: list[str]
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str]
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- class ModelRegistry[source]
Bases:
objectCentral registry for tracking compatible parsimonious model classes.
A model class is considered compatible if it:
Is a concrete (non-abstract) subclass of
IModel.Defines a non-empty
model_nameclass 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.
- get(name)[source]
Return the model class registered under
name.
- is_registered(name)[source]
Return
Trueif a model withnameis registered.
- names()[source]
Return a sorted list of all registered model names.
- 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
IModelthat defines a non-emptymodel_nameclass variable.- Returns:
The model class unchanged (enables decorator use).
- Return type:
- Raises:
TypeError – If
model_clsis not a concreteIModelsubclass or does not define a validmodel_name.ValueError – If a model with the same name is already registered.
- class ModelState(*values)[source]
Bases:
EnumEnumeration of the six lifecycle states for a parsimonious model.
States follow a strict progression:
CREATED → INITIALIZED → VALIDATED → PREPARED → PREDICTED → FINALIZED
Concrete
IModelimplementations are responsible for advancing_stateas each lifecycle method completes.- Variables:
CREATED – Object has been instantiated; no parameters registered yet.
INITIALIZED –
initialize()has completed; parameters are registered and model structure is set up.VALIDATED –
validate()returnedTrue; all parameters are within their specified bounds.PREPARED –
prepare()has completed; forcing/input data are loaded and pre-processed.PREDICTED –
predict()has completed; model outputs are available.FINALIZED –
finalize()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:
objectA 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
valueclamped to the bounds.- Returns:
New
ScalarParameterwith value in[lower_bound, upper_bound].- Return type:
- is_valid()[source]
Return
Trueifvaluelies within[lower_bound, upper_bound].- Returns:
Truewhen the value satisfies the bounds constraint.- Return type:
- normalize()[source]
Return
valuemapped linearly to[0, 1]within the bounds.Returns
0.0whenlower_bound == upper_bound.- Returns:
Normalized value in
[0, 1].- Return type:
- 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
ValueErrorif 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_boundafter the update.
- calibrate: bool = True
When
Falsethe parameter is held fixed and excluded from the calibration search space. Its value is still applied duringpredict()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:
objectA named vector parameter with element-wise lower and upper bounds.
A scalar supplied for
lower_boundsorupper_boundsis broadcast to match the length ofvalues.- 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
Falsethe parameter is held fixed and excluded from the calibration search space.
- Raises:
ValueError – If
valuesis not 1-D, if the bounds arrays do not match the length ofvaluesafter broadcasting, or if anylower_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
VectorParameterwith every value within its bounds.- Return type:
- is_valid()[source]
Return
Trueif all values lie within their respective bounds.- Returns:
Truewhen every element satisfies its bounds constraint.- Return type:
- normalize()[source]
Return values mapped element-wise to
[0, 1]within the bounds.Elements with
lower_bound == upper_boundare mapped to0.0.- Returns:
Array of normalized values, each in
[0, 1].- Return type:
- 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
ValueErrorif 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
Falsethe parameter is held fixed and excluded from the calibration search space. Its values are still applied duringpredict()but the optimizer will never modify them.
- description: str = ''
- lower_bounds: ndarray
- name: str
- units: str = ''
- upper_bounds: ndarray
- values: ndarray
Enumerations#
Enumerations for tracking model lifecycle state in sparsehydro.
- class ModelState(*values)[source]#
Bases:
EnumEnumeration of the six lifecycle states for a parsimonious model.
States follow a strict progression:
CREATED → INITIALIZED → VALIDATED → PREPARED → PREDICTED → FINALIZED
Concrete
IModelimplementations are responsible for advancing_stateas each lifecycle method completes.- Variables:
CREATED – Object has been instantiated; no parameters registered yet.
INITIALIZED –
initialize()has completed; parameters are registered and model structure is set up.VALIDATED –
validate()returnedTrue; all parameters are within their specified bounds.PREPARED –
prepare()has completed; forcing/input data are loaded and pre-processed.PREDICTED –
predict()has completed; model outputs are available.FINALIZED –
finalize()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:
objectMetadata for a single inequality constraint registered by a model.
Complements
ScalarParameterfor the constraint side of the optimisation problem. The residual values themselves are returned byinequality_constraints(); this class carries only the identity of each constraint so that solvers and notebooks can display meaningful labels.- Parameters:
- class FieldRecord(name, units='', description='', calibratable=False)[source]#
Bases:
objectMetadata for a single column in a model’s
predict()output DataFrame.Register one
FieldRecordper output column duringinitialize()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) –
Truewhen this column can serve as thepredictedcolumn in aCalibrationProblem— i.e. it is a flow-rate or quantity directly comparable to an observed signal. Diagnostic columns (depth, excess, datetime) should beFalse.
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
- class ScalarParameter(name, value, lower_bound, upper_bound, units='', description='', calibrate=True)[source]#
Bases:
objectA 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
valueclamped to the bounds.- Returns:
New
ScalarParameterwith value in[lower_bound, upper_bound].- Return type:
- is_valid()[source]#
Return
Trueifvaluelies within[lower_bound, upper_bound].- Returns:
Truewhen the value satisfies the bounds constraint.- Return type:
- normalize()[source]#
Return
valuemapped linearly to[0, 1]within the bounds.Returns
0.0whenlower_bound == upper_bound.- Returns:
Normalized value in
[0, 1].- Return type:
- 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
ValueErrorif 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_boundafter the update.
- class VectorParameter(name, values, lower_bounds, upper_bounds, units='', description='', calibrate=True)[source]#
Bases:
objectA named vector parameter with element-wise lower and upper bounds.
A scalar supplied for
lower_boundsorupper_boundsis broadcast to match the length ofvalues.- 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
Falsethe parameter is held fixed and excluded from the calibration search space.
- Raises:
ValueError – If
valuesis not 1-D, if the bounds arrays do not match the length ofvaluesafter broadcasting, or if anylower_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
VectorParameterwith every value within its bounds.- Return type:
- is_valid()[source]#
Return
Trueif all values lie within their respective bounds.- Returns:
Truewhen every element satisfies its bounds constraint.- Return type:
- normalize()[source]#
Return values mapped element-wise to
[0, 1]within the bounds.Elements with
lower_bound == upper_boundare mapped to0.0.- Returns:
Array of normalized values, each in
[0, 1].- Return type:
- 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
ValueErrorif 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.
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:
ABCAbstract interface for a parsimonious hydrological model.
Model name
Every concrete subclass must define a
model_nameclass 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_nameraisesTypeErrorimmediately.Lifecycle
Concrete subclasses must advance
self._stateas each method completes:CREATED → INITIALIZED → VALIDATED → PREPARED → PREDICTED → FINALIZED
Parameter registry
Parameters are registered during
initialize()viaregister_scalar_parameter()andregister_vector_parameter(). Calibration tools retrieve them by name throughget_scalar_parameter()andget_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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)[source]#
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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
FieldRecordfor name.
- get_scalar_parameter(name)[source]#
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)[source]#
Retrieve a registered vector parameter by name.
- inequality_constraints()[source]#
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- abstractmethod initialize(*args, **kwargs)[source]#
Set up model structure and register parameters.
Called once before
validate(). Implementations register everyScalarParameterandVectorParameterhere and advance the state toINITIALIZED.
- is_created()[source]#
Return whether the model is in the
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()[source]#
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()[source]#
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_validated()[source]#
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()[source]#
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()[source]#
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- abstractmethod predict(*args, **kwargs)[source]#
Execute the model and return its outputs.
- Parameters:
- Returns:
Model outputs, typically with a predicted-flow column.
- Return type:
- read_flat_parameter(name)[source]#
Read one value addressed the same way as
apply_flat_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:
- 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:
- 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
VALIDATEDwhen returningTrue.
- property inequality_constraint_descriptions: list[str]#
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]#
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str]#
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]#
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState#
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- class IUnitHydroComponent[source]#
-
Abstract base for unit hydrograph components used within
RDIIModel.Extends
IModelwith 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 (
Rfor RTK triangles,Afor Nash/Gamma UH shapes). When a component is embedded inRDIIModel, that composite manages the fractionR_iseparately 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)#
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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:
- Returns:
1-D ordinate array [1/hr].
- Return type:
- get_output_field(name)#
Return the
FieldRecordfor name.
- get_scalar_parameter(name)#
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)#
Retrieve a registered vector parameter by name.
- inequality_constraints()#
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- abstractmethod initialize(*args, **kwargs)#
Set up model structure and register parameters.
Called once before
validate(). Implementations register everyScalarParameterandVectorParameterhere and advance the state toINITIALIZED.
- is_created()#
Return whether the model is in the
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()#
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()#
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()#
Return whether the model is in the
PREDICTEDstate.
- is_prepared()#
Return whether the model is in the
PREPAREDstate.
- is_validated()#
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()#
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()#
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- abstractmethod predict(*args, **kwargs)#
Execute the model and return its outputs.
- Parameters:
- Returns:
Model outputs, typically with a predicted-flow column.
- Return type:
- abstractmethod prepare(*args, **kwargs)#
Load and pre-process forcing/input data.
- read_flat_parameter(name)#
Read one value addressed the same way as
apply_flat_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:
- 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:
- 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
VALIDATEDwhen returningTrue.
- property inequality_constraint_descriptions: list[str]#
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]#
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str]#
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]#
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState#
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
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:
objectCentral registry for tracking compatible parsimonious model classes.
A model class is considered compatible if it:
Is a concrete (non-abstract) subclass of
IModel.Defines a non-empty
model_nameclass 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.
- 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
IModelthat defines a non-emptymodel_nameclass variable.- Returns:
The model class unchanged (enables decorator use).
- Return type:
- Raises:
TypeError – If
model_clsis not a concreteIModelsubclass or does not define a validmodel_name.ValueError – If a model with the same name is already 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]#
-
Abstract interface for differentiable parsimonious models.
Inherits from both
IModelandtorch.nn.Module. Subclasses must implement all fiveIModellifecycle methods andforward()— the differentiable computation graph.The default
predict()implementation callsforward()and advances model state toPREDICTED. Overridepredict()if additional pre/post-processing aroundforward()is required.Gradient-tracked parameters should be declared as
torch.nn.Parameterattributes so that PyTorch optimisers can discover them viaModule.parameters(). The sparsehydroregister_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
fnrecursively 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)#
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand a name in values is not registered.
- bfloat16()#
Casts all floating point parameters and buffers to
bfloat16datatype.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
doubledatatype.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
floatdatatype.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.Parameterattributes.- 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:
- get_buffer(target)#
Return the buffer given by
targetif it exists, otherwise throw an error.See the docstring for
get_submodulefor a more detailed explanation of this method’s functionality as well as how to correctly specifytarget.- Parameters:
target (str) – The fully-qualified string name of the buffer to look for. (See
get_submodulefor how to specify a fully-qualified string.)- Returns:
The buffer referenced by
target- Return type:
- 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:
- get_output_field(name)#
Return the
FieldRecordfor name.
- get_parameter(target)#
Return the parameter given by
targetif it exists, otherwise throw an error.See the docstring for
get_submodulefor a more detailed explanation of this method’s functionality as well as how to correctly specifytarget.- Parameters:
target (str) – The fully-qualified string name of the Parameter to look for. (See
get_submodulefor 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.
- get_submodule(target)#
Return the submodule given by
targetif it exists, otherwise throw an error.For example, let’s say you have an
nn.ModuleAthat 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.ModuleA.Awhich has a nested submodulenet_b, which itself has two submodulesnet_candlinear.net_cthen has a submoduleconv.)To check whether or not we have the
linearsubmodule, we would callget_submodule("net_b.linear"). To check whether we have theconvsubmodule, we would callget_submodule("net_b.net_c.conv").The runtime of
get_submoduleis bounded by the degree of module nesting intarget. A query againstnamed_modulesachieves 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_submoduleshould 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:
- 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.
- half()#
Casts all floating point parameters and buffers to
halfdatatype.Note
This method modifies the module in-place.
- Returns:
self
- Return type:
Module
- inequality_constraints()#
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- abstractmethod initialize(*args, **kwargs)#
Set up model structure and register parameters.
Called once before
validate(). Implementations register everyScalarParameterandVectorParameterhere and advance the state toINITIALIZED.
- 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
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()#
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()#
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()#
Return whether the model is in the
PREDICTEDstate.
- is_prepared()#
Return whether the model is in the
PREPAREDstate.
- is_validated()#
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- load_state_dict(state_dict, strict=True, assign=False)#
Copy parameters and buffers from
state_dictinto this module and its descendants.If
strictisTrue, then the keys ofstate_dictmust exactly match the keys returned by this module’sstate_dict()function.Warning
If
assignisTruethe optimizer must be created after the call toload_state_dictunlessget_swap_module_params_on_conversion()isTrue.- Parameters:
state_dict (dict) – a dict containing parameters and persistent buffers.
strict (bool, optional) – whether to strictly enforce that the keys in
state_dictmatch the keys returned by this module’sstate_dict()function. Default:Trueassign (bool, optional) – When set to
False, the properties of the tensors in the current module are preserved whereas setting it toTruepreserves properties of the Tensors in the state dict. The only exception is therequires_gradfield ofParameterfor which the value from the module is preserved. Default:False
- Returns:
missing_keysis a list of str containing any keys that are expectedby this module but missing from the provided
state_dict.
unexpected_keysis a list of str containing the keys that are notexpected by this module but present in the provided
state_dict.
- Return type:
NamedTuplewithmissing_keysandunexpected_keysfields
Note
If a parameter or buffer is registered as
Noneand its corresponding key exists instate_dict,load_state_dict()will raise aRuntimeError.
- 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,
lwill 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:
- Yields:
(str, Module) – Tuple of name and module
Note
Duplicate modules are returned only once. In the following example,
lwill 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,calibratableanddescriptioncolumns.- Return type:
- 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:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- predict(*args, **kwargs)[source]#
Run the differentiable forward pass and advance model state.
Delegates to
forward()and sets the model state toPREDICTED.- Parameters:
- Returns:
The output tensor returned by
forward().- Return type:
- abstractmethod prepare(*args, **kwargs)#
Load and pre-process forcing/input data.
- read_flat_parameter(name)#
Read one value addressed the same way as
apply_flat_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_meanis 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 settingpersistenttoFalse. The only difference between a persistent buffer and a non-persistent buffer is that the latter will not be a part of this module’sstate_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 ascuda, are ignored. IfNone, the buffer is not included in the module’sstate_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_kwargsisFalseor 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 theforward. The hook can modify the output. It can modify the input inplace but it will not have effect on forward since this is called afterforward()is called. The hook should have the following signature:hook(module, args, output) -> None or modified output
If
with_kwargsisTrue, the forward hook will be passed thekwargsgiven 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 providedhookwill be fired before all existingforwardhooks on thistorch.nn.Module. Otherwise, the providedhookwill be fired after all existingforwardhooks on thistorch.nn.Module. Note that globalforwardhooks registered withregister_module_forward_hook()will fire before all hooks registered by this method. Default:Falsewith_kwargs (bool) – If
True, thehookwill be passed the kwargs given to the forward function. Default:Falsealways_call (bool) – If
Truethehookwill 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_kwargsis 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 theforward. 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_kwargsis 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
hookwill be fired before all existingforward_prehooks on thistorch.nn.Module. Otherwise, the providedhookwill be fired after all existingforward_prehooks on thistorch.nn.Module. Note that globalforward_prehooks registered withregister_module_forward_pre_hook()will fire before all hooks registered by this method. Default:Falsewith_kwargs (bool) – If true, the
hookwill 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:
Ordinarily, the hook fires when the gradients are computed with respect to the module inputs.
If none of the module inputs require gradients, the hook will fire when the gradients are computed with respect to module outputs.
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_inputandgrad_outputare 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 ofgrad_inputin subsequent computations.grad_inputwill only correspond to the inputs given as positional arguments and all kwarg arguments are ignored. Entries ingrad_inputandgrad_outputwill beNonefor 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
hookwill be fired before all existingbackwardhooks on thistorch.nn.Module. Otherwise, the providedhookwill be fired after all existingbackwardhooks on thistorch.nn.Module. Note that globalbackwardhooks registered withregister_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_outputis 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 ofgrad_outputin subsequent computations. Entries ingrad_outputwill beNonefor 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
hookwill be fired before all existingbackward_prehooks on thistorch.nn.Module. Otherwise, the providedhookwill be fired after all existingbackward_prehooks on thistorch.nn.Module. Note that globalbackward_prehooks registered withregister_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
moduleargument is the current module that this hook is registered on, and theincompatible_keysargument is aNamedTupleconsisting of attributesmissing_keysandunexpected_keys.missing_keysis alistofstrcontaining the missing keys andunexpected_keysis alistofstrcontaining the unexpected keys.The given incompatible_keys can be modified inplace if needed.
Note that the checks performed when calling
load_state_dict()withstrict=Trueare affected by modifications the hook makes tomissing_keysorunexpected_keys, as expected. Additions to either set of keys will result in an error being thrown whenstrict=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 ascuda, are ignored. IfNone, the parameter is not included in the module’sstate_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_dictinplace.
- 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_dictcall 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:
- 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:
- 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_gradattributes 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 correspondingget_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
targetif it exists, otherwise throw an error.Note
If
strictis set toFalse(default), the method will replace an existing submodule or create a new submodule if the parent module exists. Ifstrictis set toTrue, 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.ModuleAthat looks like this:A( (net_b): Module( (net_c): Module( (conv): Conv2d(3, 3, 3) ) (linear): Linear(3, 3) ) )(The diagram shows an
nn.ModuleA.Ahas a nested submodulenet_b, which itself has two submodulesnet_candlinear.net_cthen has a submoduleconv.)To override the
Conv2dwith a new submoduleLinear, you could callset_submodule("net_b.net_c.conv", nn.Linear(1, 1))wherestrictcould beTrueorFalseTo add a new submodule
Conv2dto the existingnet_bmodule, you would callset_submodule("net_b.conv", nn.Conv2d(1, 1, 1)).In the above if you set
strict=Trueand callset_submodule("net_b.conv", nn.Conv2d(1, 1, 1), strict=True), an AttributeError will be raised becausenet_bdoes not have a submodule namedconv.- 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. IfTrue, 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
targetstring is empty or ifmoduleis not an instance ofnn.Module.AttributeError – If at any point along the path resulting from the
targetstring the (sub)path resolves to a non-existent attribute name or an object that is not an instance ofnn.Module.
- 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
Noneare 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 fordestination,prefixandkeep_varsin order. However, this is being deprecated and keyword arguments will be enforced in future releases.Warning
Please avoid the use of argument
destinationas 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
OrderedDictwill 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
Tensors returned in the state dict are detached from autograd. If it’s set toTrue, detaching will not be performed. Default:False.
- Returns:
a dictionary containing a whole state of the module
- Return type:
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 complexdtypes. In addition, this method will only cast the floating point or complex parameters and buffers todtype(if given). The integral parameters and buffers will be moveddevice, if that is given, but with dtypes unchanged. Whennon_blockingis 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 moduledtype (
torch.dtype) – the desired floating point or complex dtype of the parameters and buffers in this moduletensor (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
VALIDATEDwhen returningTrue.
- 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.Optimizerfor 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 inequality_constraint_descriptions: list[str]#
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]#
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str]#
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]#
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState#
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
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 |
|---|---|
|
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 |
|
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 |
|
Unit hydrograph shape per RTKTriangle Stacked per-triangle RDII contributions |
|
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:
IModelGeneral-purpose visualization model for any
IModeloutput.Wraps
plot_timeseries(),plot_pareto_evolution(), andplot_parallel_coordinates()behind the standardIModellifecycle.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:
- 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand a name in values is not registered.
- finalize()[source]
Release stored data and figures and advance to FINALIZED.
- get_output_field(name)
Return the
FieldRecordfor name.
- get_scalar_parameter(name)
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)
Retrieve a registered vector parameter by name.
- inequality_constraints()
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- initialize()[source]
Advance to INITIALIZED.
- is_created()
Return whether the model is in the
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()
Return whether the model is in the
PREDICTEDstate.- Returns:
Trueifpredict()has completed.- Return type:
- is_prepared()
Return whether the model is in the
PREPAREDstate.- Returns:
Trueifprepare()has completed.- Return type:
- is_validated()
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- 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:
- 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
Noneto omit.rainfall_col (str or None) – Column name for rainfall forcing, or
Noneto 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().
- 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:
- 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:
- 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.
- property inequality_constraint_descriptions: list[str]
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]
Ordered list of registered inequality constraint names.
- model_name = 'visualization'
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property parallel_figure: go.Figure | None
Parallel-coordinates trade-off explorer, or
Nonewhen no result was supplied.
- property pareto_figure: go.Figure | None
Animated Pareto-front evolution, or
Nonewhen no result was supplied.
- property state: ModelState
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- property timeseries_figure: go.Figure | None
Dual-axis rainfall/flow time series, or
Nonebeforepredict().
- 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.Frameobjects (used byplot_pareto_evolution()) andgo.Parcoordstraces cannot be embedded in a sharedmake_subplotsgrid, each sub-figure is serialised individually withplotly.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):
Time series — if timeseries_df is supplied.
Objective convergence — always shown.
Pareto front evolution (animated) — requires ≥ 1 history record.
Parameter distributions — always shown.
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
Noneto omit.rainfall_col (str or None) – Rainfall column name, or
Noneto 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
Noneto skip writing.use_cdn (bool) – Include Plotly via CDN
<script>tag whenTrue; inline the full Plotly bundle whenFalse(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. WhenNoneall 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
Aparameter per event (SequentialFitSummary.calibrated_areas()). For single models this is theAvalue; for ensembles it is the sum of all component*_Aparameters.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
Noneto omit the top panel.observed (numpy.ndarray) – 1-D observed flow array.
pred_df (pandas.DataFrame) – Output of
predict(), containing{alias}_outputcolumns 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 bycollect_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}_outputseries with the observed target, followed by a final row for the combined output_name series vs. observed. This differs fromplot_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}_outputcolumns 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
Noneto skip the top panel.observed (numpy.ndarray) – 1-D array of observed flow values.
pred_df (pandas.DataFrame) – Output of
predict()containing{alias}_outputcolumns and the output_name column.aliases (list[str]) – List of alias strings matching the EnsembleModel’s
aliasesattribute (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)*xandy = (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 thetolerance_anglesoption onplot_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.0draws 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 whenFalse.
- Returns:
Plotly Figure with
go.Parcoordstrace.- 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 whenFalse.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:
summary (SequentialFitSummary) – Sequential fitting summary.
title (str) – Figure title.
- 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:
- 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:
result (CalibrationResult) – Calibration result.
title (str) – Figure title.
- Returns:
Plotly Figure with
go.Splomtrace.- 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
datetimecolumn (or similar time index) and any number of columns namedrdii_component_N(N = 0, 1, 2, …). Arainfall_mmcolumn is optional; if absent, no rainfall panel is shown.- Parameters:
result_df (pandas.DataFrame) – DataFrame produced by an RDIIModel run. Must contain
rdii_component_Ncolumns.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:
triangles (RTKTriangle or list[RTKTriangle] or tuple[RTKTriangle, ...]) – An
RTKTriangleinstance or a list/tuple of instances.dt_hours (float) – Time step in hours.
title (str) – Figure title.
- 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:
result (CalibrationResult) – Calibration result.
title (str) – Figure title.
- Returns:
Plotly Figure with
go.Heatmaptrace.- 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:
summary (SequentialFitSummary) – Sequential fitting summary.
rain_stormflow (pandas.DataFrame) – Frame with
datetime,rain,stormflow.events (list[EventRecord] | None) – Events to overlay; defaults to
summary.events.title (str) – Figure title.
- 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.Splomtraces.- 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
Noneto 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):
plot_timeseries()— rainfall + observed/predicted subplotsplot_residuals_scatter()— observed-vs-predicted, residual bars, autocorrelationplot_cumulative_volume()— cumulative sums + volume errorVisualizationModel— IModel wrapper for the above plots
- class VisualizationModel(title='Model Time Series', rainfall_label='Rainfall [mm]', flow_label='Flow')[source]#
Bases:
IModelGeneral-purpose visualization model for any
IModeloutput.Wraps
plot_timeseries(),plot_pareto_evolution(), andplot_parallel_coordinates()behind the standardIModellifecycle.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:
- 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)#
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand a name in values is not registered.
- get_output_field(name)#
Return the
FieldRecordfor name.
- get_scalar_parameter(name)#
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)#
Retrieve a registered vector parameter by name.
- inequality_constraints()#
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- is_created()#
Return whether the model is in the
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()#
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()#
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()#
Return whether the model is in the
PREDICTEDstate.
- is_prepared()#
Return whether the model is in the
PREPAREDstate.
- is_validated()#
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()#
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()#
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- 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:
- 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
Noneto omit.rainfall_col (str or None) – Column name for rainfall forcing, or
Noneto 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().
- 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:
- 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:
- 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.
- property inequality_constraint_descriptions: list[str]#
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]#
Ordered list of registered inequality constraint names.
- model_name = 'visualization'#
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]#
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property parallel_figure: go.Figure | None#
Parallel-coordinates trade-off explorer, or
Nonewhen no result was supplied.
- property pareto_figure: go.Figure | None#
Animated Pareto-front evolution, or
Nonewhen no result was supplied.
- property state: ModelState#
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- 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 slopestan(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. WhenNoneall 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
Noneto omit the top panel.observed (numpy.ndarray) – 1-D observed flow array.
pred_df (pandas.DataFrame) – Output of
predict(), containing{alias}_outputcolumns 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 bycollect_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}_outputseries with the observed target, followed by a final row for the combined output_name series vs. observed. This differs fromplot_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}_outputcolumns 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
Noneto skip the top panel.observed (numpy.ndarray) – 1-D array of observed flow values.
pred_df (pandas.DataFrame) – Output of
predict()containing{alias}_outputcolumns and the output_name column.aliases (list[str]) – List of alias strings matching the EnsembleModel’s
aliasesattribute (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)*xandy = (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 thetolerance_anglesoption onplot_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.0draws 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
Noneto 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_pareto_evolution()— animated Pareto front with generation sliderplot_parallel_coordinates()— parallel-axis trade-off explorerplot_objective_convergence()— best-value + percentile bands per generationplot_parameter_distributions()— violin plots of Pareto parameter valuesplot_sensitivity_heatmap()— parameter-objective Pearson correlation heat mapplot_pareto_scatter_matrix()— scatter-plot matrix (SPLOM) of all objectivesplot_splom()— SPLOM of all final-generation solutions, non-dominated highlighted
- 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 whenFalse.
- Returns:
Plotly Figure with
go.Parcoordstrace.- 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 whenFalse.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:
- 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:
result (CalibrationResult) – Calibration result.
title (str) – Figure title.
- Returns:
Plotly Figure with
go.Splomtrace.- 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:
result (CalibrationResult) – Calibration result.
title (str) – Figure title.
- Returns:
Plotly Figure with
go.Heatmaptrace.- 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.Splomtraces.- 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_rtk_shape()— unit hydrograph shape per RTKTriangleplot_rdii_components()— stacked per-triangle RDII contributions over time
- plot_rdii_components(result_df, title='RDII Components', rainfall_label='Rainfall [mm]')[source]#
Stacked RDII component traces alongside rainfall.
The DataFrame must contain a
datetimecolumn (or similar time index) and any number of columns namedrdii_component_N(N = 0, 1, 2, …). Arainfall_mmcolumn is optional; if absent, no rainfall panel is shown.- Parameters:
result_df (pandas.DataFrame) – DataFrame produced by an RDIIModel run. Must contain
rdii_component_Ncolumns.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:
triangles (RTKTriangle or list[RTKTriangle] or tuple[RTKTriangle, ...]) – An
RTKTriangleinstance or a list/tuple of instances.dt_hours (float) – Time step in hours.
title (str) – Figure title.
- 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()— combine multiple sub-figures into a single offline HTML file.
- 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.Frameobjects (used byplot_pareto_evolution()) andgo.Parcoordstraces cannot be embedded in a sharedmake_subplotsgrid, each sub-figure is serialised individually withplotly.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):
Time series — if timeseries_df is supplied.
Objective convergence — always shown.
Pareto front evolution (animated) — requires ≥ 1 history record.
Parameter distributions — always shown.
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
Noneto omit.rainfall_col (str or None) – Rainfall column name, or
Noneto 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
Noneto skip writing.use_cdn (bool) – Include Plotly via CDN
<script>tag whenTrue; inline the full Plotly bundle whenFalse(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 |
|---|---|
|
Two-panel timeseries with event shading bands |
|
sg_0 / sg_1 / sg_2 with threshold lines |
|
sg_0 + peak markers + event shading |
|
Rainfall / obs+pred / residual three-row panel |
|
Fitted params over time, colored by NSE |
|
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_rainfall_flow_with_events()— two-panel timeseries with event bandsplot_filter_signals()— sg_0 / sg_1 / sg_2 with threshold linesplot_event_detection()— sg_0 + peak markers + event shadingplot_sequential_fit()— observed vs global+per-event predicted + residualplot_parameter_evolution()— fitted params over time colored by NSEplot_effective_area()— bar chart of Ae per event
- 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
Aparameter per event (SequentialFitSummary.calibrated_areas()). For single models this is theAvalue; for ensembles it is the sum of all component*_Aparameters.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:
summary (SequentialFitSummary) – Sequential fitting summary.
title (str) – Figure title.
- 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:
summary (SequentialFitSummary) – Sequential fitting summary.
rain_stormflow (pandas.DataFrame) – Frame with
datetime,rain,stormflow.events (list[EventRecord] | None) – Events to overlay; defaults to
summary.events.title (str) – Figure title.
- 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#
FilterResult— dataclass holding the four signal arrays + thresholdsapply_savgol_filter()— computes sg_0, sg_1, sg_2 from a rain/stormflow DataFramecompute_thresholds()— attaches percentile-based detection thresholds
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:
objectContainer 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:
- class FilterResult(datetime, raw_flow, sg_0, sg_1, sg_2, thresholds=<factory>)[source]#
Bases:
objectOutput 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".
- 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;
thresholdsis empty untilcompute_thresholds()is called.- Return type:
- 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
FilterResultwiththresholdspopulated (immutable update — the original is not modified).- Return type:
- 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
Noneto 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:
- 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 a7 * points_per_day-length weekly pattern array.- Return type:
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#
EventRecord— dataclass for a single storm eventdetect_events()— automatic event detection from rain/stormflow dataevents_to_dataframe()— convert a list of EventRecord to a DataFrameload_events_from_csv()— load pre-defined events from a CSV file
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:
objectA 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 whentotal_rain == 0.peak_flow (float) – Maximum stormflow value within the event window.
b2b_start (bool) –
Trueif the event starts at a back-to-back trough.b2b_end (bool) –
Trueif 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:
- 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 detectedEventRecordobjects (event_idstarts at 1) and filter_result holds the sg signals and computed thresholds for diagnostics.- Return type:
- events_to_dataframe(events)[source]#
Convert a list of
EventRecordobjects 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:
- load_events_from_csv(path)[source]#
Load an
events_list.csvas a list ofEventRecordobjects.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.csvfile.- Returns:
Events parsed from the CSV (sentinel values for missing fields).
- Return type:
Unit Hydrograph#
sparsehydro.models.unithydrograph — unit hydrograph models.
This subpackage provides:
UnitHydrographAdapter— the adapter base that bridges the existingUnitHydrographclass to theIModellifecycle.create_uh_model()— factory that creates a concrete, registry-compatible subclass for any model registered inUnitHydrograph._registry.register_all_uh_models()— bulk registration helper.GammaUH— Gamma-function UHNashUH— Nash cascade UHTriangleUH— Triangular UHSequentialFitter— sequential event fittingSequentialFitSummary— 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:
IUnitHydroComponentGamma-function unit hydrograph.
Shape:
f(t) ∝ (t/tp)^tt * exp(-t/tp)- Parameters:
- 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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:
- Returns:
Normalized UH ordinates [1/hr] such that
sum * dt_hours ≈ 1.- Return type:
- get_output_field(name)
Return the
FieldRecordfor name.
- get_scalar_parameter(name)
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)
Retrieve a registered vector parameter by name.
- inequality_constraints()
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- 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
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()
Return whether the model is in the
PREDICTEDstate.- Returns:
Trueifpredict()has completed.- Return type:
- is_prepared()
Return whether the model is in the
PREPAREDstate.- Returns:
Trueifprepare()has completed.- Return type:
- is_validated()
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- predict()[source]
Convolve rainfall with the gamma UH kernel and return predicted flow.
- Returns:
DataFrame with columns
datetimeandQ_pred.- Return type:
- Raises:
RuntimeError – If
prepare()has not been called.
- prepare(data)[source]
Cache forcing data and coerce the
datetimecolumn.- Parameters:
data (pandas.DataFrame) – DataFrame with
datetimeandraincolumns.- Returns:
Nothing.
- Return type:
None
- read_flat_parameter(name)
Read one value addressed the same way as
apply_flat_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:
- 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:
- 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:
Trueif all parameters are within bounds.- Return type:
- property inequality_constraint_descriptions: list[str]
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str] = 'gamma-uh'
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- class NashUH(A=100.0, n=2.0, k=5.0)[source]
Bases:
IUnitHydroComponentNash cascade (linear-reservoir) unit hydrograph.
Shape:
f(t) ∝ t^(n-1) * exp(-t/k)- Parameters:
- 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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:
- Returns:
Normalized UH ordinates [1/hr] such that
sum * dt_hours ≈ 1.- Return type:
- get_output_field(name)
Return the
FieldRecordfor name.
- get_scalar_parameter(name)
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)
Retrieve a registered vector parameter by name.
- inequality_constraints()
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- 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
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()
Return whether the model is in the
PREDICTEDstate.- Returns:
Trueifpredict()has completed.- Return type:
- is_prepared()
Return whether the model is in the
PREPAREDstate.- Returns:
Trueifprepare()has completed.- Return type:
- is_validated()
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- predict()[source]
Convolve rainfall with the Nash cascade kernel and return predicted flow.
- Returns:
DataFrame with columns
datetimeandQ_pred.- Return type:
- Raises:
RuntimeError – If
prepare()has not been called.
- prepare(data)[source]
Cache forcing data and coerce the
datetimecolumn.- Parameters:
data (pandas.DataFrame) – DataFrame with
datetimeandraincolumns.- Returns:
Nothing.
- Return type:
None
- read_flat_parameter(name)
Read one value addressed the same way as
apply_flat_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:
- 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:
- 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:
Trueif all parameters are within bounds.- Return type:
- property inequality_constraint_descriptions: list[str]
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str] = 'nash-uh'
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- class SequentialFitSummary(events, calibration_results, global_predicted, global_observed, model_class_name, fitted_effective_areas)[source]
Bases:
objectResults of a sequential unit hydrograph fitting run.
- Variables:
events (list[EventRecord]) – Events that were fitted, in chronological order.
calibration_results (list[CalibrationResult]) – One
CalibrationResultper 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
Aparameter. For an ensemble (aliases likefast_A,slow_A) it is the sum of all*_Aparameters — consistent withmode="sum"and fixed weights of 1.0.- Returns:
Calibrated total
Avalue per fitted event.- Return type:
- 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:
- 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:
- 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:
- calibration_results: list[CalibrationResult]
- events: list[EventRecord]
- global_observed: DataFrame
- global_predicted: DataFrame
- model_class_name: str
- class SequentialFitter(model_factory, rain_stormflow, events, output_column='Q_pred')[source]
Bases:
objectFit an
IModelto storm events one by one.- Parameters:
model_factory (Callable[[], IModel]) –
Zero-argument callable returning a fresh
IModelin CREATED state. Works with single UH models andEnsembleModel: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.minimizemethod, 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:
- class TriangleUH(A=100.0, tt=50.0, tp=20.0)[source]
Bases:
IUnitHydroComponentTriangular unit hydrograph.
Rising limb 0 → peak at
tp; falling limb peak → 0 attt.- Parameters:
- 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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:
- Returns:
Normalized UH ordinates [1/hr]; all zeros when
tp >= tt.- Return type:
- get_output_field(name)
Return the
FieldRecordfor name.
- get_scalar_parameter(name)
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)
Retrieve a registered vector parameter by name.
- inequality_constraints()
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- 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
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()
Return whether the model is in the
PREDICTEDstate.- Returns:
Trueifpredict()has completed.- Return type:
- is_prepared()
Return whether the model is in the
PREPAREDstate.- Returns:
Trueifprepare()has completed.- Return type:
- is_validated()
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- predict()[source]
Convolve rainfall with the triangular UH kernel and return predicted flow.
- Returns:
DataFrame with columns
datetimeandQ_pred.- Return type:
- Raises:
RuntimeError – If
prepare()has not been called.
- prepare(data)[source]
Cache forcing data and coerce the
datetimecolumn.- Parameters:
data (pandas.DataFrame) – DataFrame with
datetimeandraincolumns.- Returns:
Nothing.
- Return type:
None
- read_flat_parameter(name)
Read one value addressed the same way as
apply_flat_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:
- 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:
- 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 < ttordering constraint.- Returns:
Trueif all parameters are within bounds andtp < tt.- Return type:
- property inequality_constraint_descriptions: list[str]
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str] = 'triangle-uh'
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- class UnitHydrographAdapter[source]
Bases:
IUnitHydroComponentAdapter base that bridges
UnitHydrographto theIModellifecycle.Do not instantiate or register this class directly. Use
create_uh_model()orregister_all_uh_models()to obtain concrete, registry-compatible subclasses.Lifecycle mapping
IModel method
Adapter action
initializeConstructs
UnitHydrograph(key), reads_registryto create oneScalarParameterper model parameter.validateDelegates to
parameters_valid().prepareStores the
rain_stormflowDataFrame; syncsScalarParametervalues →_uh.parameters.predictCalls
_uh.predict(); returns the DataFrame.finalizeReleases the stored DataFrame.
Parameter synchronisation
ScalarParametervalues are the source of truth. They are pushed to_uh.parametersbefore everypredictorfitcall. Afterfitthe optimised values are pulled back so both representations stay consistent.Infinite bounds
UnitHydrograph._registryusesnp.inffor unbounded parameters (e.g.A). These are clamped to ±:data:_INF_SUBSTITUTE when creatingScalarParameterobjects 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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
UnitHydrographand 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:
- 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 theAamplitude parameter divided out, sonp.sum(result) ≈ 1.0.Note
The
dt_hoursargument is accepted for API uniformity but does not resample the kernel.- Parameters:
- Returns:
Unit-area UH ordinate array.
- Return type:
- Raises:
RuntimeError – If
initialize()has not been called.
- get_output_field(name)
Return the
FieldRecordfor name.
- get_scalar_parameter(name)
Retrieve a registered scalar parameter by name.
- get_uh(max_steps=864, norm=0)[source]
Return the unit hydrograph ordinate array from the wrapped model.
- Parameters:
- Returns:
UH ordinate array.
- Return type:
- Raises:
RuntimeError – If
initialize()has not been called.
- get_vector_parameter(name)
Retrieve a registered vector parameter by name.
- inequality_constraints()
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- initialize()[source]
Construct the wrapped
UnitHydrographand register its parameters.- Returns:
Nothing.
- Return type:
None
- Raises:
TypeError – If called on the base
UnitHydrographAdapterinstead of a factory-created subclass.
- is_created()
Return whether the model is in the
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()
Return whether the model is in the
PREDICTEDstate.- Returns:
Trueifpredict()has completed.- Return type:
- is_prepared()
Return whether the model is in the
PREPAREDstate.- Returns:
Trueifprepare()has completed.- Return type:
- is_validated()
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- 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:
- Raises:
RuntimeError – If
initialize()orprepare()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().
- 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:
- 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:
- 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:
Trueif all parameters are within bounds.- Return type:
- property inequality_constraint_descriptions: list[str]
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]
Ordered list of registered inequality constraint names.
- property is_fit: bool
Trueif the wrappedUnitHydrographhas been successfully fitted.- Returns:
Fit status of the wrapped model (
Falseif not yet built).- Return type:
- model_name: ClassVar[str] = 'uh-adapter'
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- create_uh_model(uh_model_name)[source]
Create and register a concrete
IModelsubclass for one UH model.
- register_all_uh_models()[source]
Create and register adapters for every model in
UnitHydrograph._registry.Call this once after confirming that
uh_modelsis 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:
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 |
|---|---|---|
|
A, tt (shape), tp (scale/steps) |
|
|
A, n (reservoirs), k (storage) |
|
|
A, tt (total steps), tp (peak) |
Piecewise linear; |
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:
IUnitHydroComponentGamma-function unit hydrograph.
Shape:
f(t) ∝ (t/tp)^tt * exp(-t/tp)- Parameters:
- 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)#
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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:
- Returns:
Normalized UH ordinates [1/hr] such that
sum * dt_hours ≈ 1.- Return type:
- get_output_field(name)#
Return the
FieldRecordfor name.
- get_scalar_parameter(name)#
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)#
Retrieve a registered vector parameter by name.
- inequality_constraints()#
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- 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
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()#
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()#
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()#
Return whether the model is in the
PREDICTEDstate.
- is_prepared()#
Return whether the model is in the
PREPAREDstate.
- is_validated()#
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()#
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()#
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- predict()[source]#
Convolve rainfall with the gamma UH kernel and return predicted flow.
- Returns:
DataFrame with columns
datetimeandQ_pred.- Return type:
- Raises:
RuntimeError – If
prepare()has not been called.
- prepare(data)[source]#
Cache forcing data and coerce the
datetimecolumn.- Parameters:
data (pandas.DataFrame) – DataFrame with
datetimeandraincolumns.- Returns:
Nothing.
- Return type:
None
- read_flat_parameter(name)#
Read one value addressed the same way as
apply_flat_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:
- 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:
- 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:
Trueif all parameters are within bounds.- Return type:
- property inequality_constraint_descriptions: list[str]#
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]#
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str] = 'gamma-uh'#
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]#
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState#
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- class NashUH(A=100.0, n=2.0, k=5.0)[source]#
Bases:
IUnitHydroComponentNash cascade (linear-reservoir) unit hydrograph.
Shape:
f(t) ∝ t^(n-1) * exp(-t/k)- Parameters:
- 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)#
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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:
- Returns:
Normalized UH ordinates [1/hr] such that
sum * dt_hours ≈ 1.- Return type:
- get_output_field(name)#
Return the
FieldRecordfor name.
- get_scalar_parameter(name)#
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)#
Retrieve a registered vector parameter by name.
- inequality_constraints()#
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- 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
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()#
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()#
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()#
Return whether the model is in the
PREDICTEDstate.
- is_prepared()#
Return whether the model is in the
PREPAREDstate.
- is_validated()#
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()#
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()#
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- predict()[source]#
Convolve rainfall with the Nash cascade kernel and return predicted flow.
- Returns:
DataFrame with columns
datetimeandQ_pred.- Return type:
- Raises:
RuntimeError – If
prepare()has not been called.
- prepare(data)[source]#
Cache forcing data and coerce the
datetimecolumn.- Parameters:
data (pandas.DataFrame) – DataFrame with
datetimeandraincolumns.- Returns:
Nothing.
- Return type:
None
- read_flat_parameter(name)#
Read one value addressed the same way as
apply_flat_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:
- 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:
- 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:
Trueif all parameters are within bounds.- Return type:
- property inequality_constraint_descriptions: list[str]#
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]#
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str] = 'nash-uh'#
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]#
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState#
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- class TriangleUH(A=100.0, tt=50.0, tp=20.0)[source]#
Bases:
IUnitHydroComponentTriangular unit hydrograph.
Rising limb 0 → peak at
tp; falling limb peak → 0 attt.- Parameters:
- 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)#
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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:
- Returns:
Normalized UH ordinates [1/hr]; all zeros when
tp >= tt.- Return type:
- get_output_field(name)#
Return the
FieldRecordfor name.
- get_scalar_parameter(name)#
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)#
Retrieve a registered vector parameter by name.
- inequality_constraints()#
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- 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
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()#
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()#
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()#
Return whether the model is in the
PREDICTEDstate.
- is_prepared()#
Return whether the model is in the
PREPAREDstate.
- is_validated()#
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()#
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()#
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- predict()[source]#
Convolve rainfall with the triangular UH kernel and return predicted flow.
- Returns:
DataFrame with columns
datetimeandQ_pred.- Return type:
- Raises:
RuntimeError – If
prepare()has not been called.
- prepare(data)[source]#
Cache forcing data and coerce the
datetimecolumn.- Parameters:
data (pandas.DataFrame) – DataFrame with
datetimeandraincolumns.- Returns:
Nothing.
- Return type:
None
- read_flat_parameter(name)#
Read one value addressed the same way as
apply_flat_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:
- 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:
- 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 < ttordering constraint.- Returns:
Trueif all parameters are within bounds andtp < tt.- Return type:
- property inequality_constraint_descriptions: list[str]#
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]#
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str] = 'triangle-uh'#
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]#
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState#
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
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:
objectResults of a sequential unit hydrograph fitting run.
- Variables:
events (list[EventRecord]) – Events that were fitted, in chronological order.
calibration_results (list[CalibrationResult]) – One
CalibrationResultper 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
Aparameter. For an ensemble (aliases likefast_A,slow_A) it is the sum of all*_Aparameters — consistent withmode="sum"and fixed weights of 1.0.- Returns:
Calibrated total
Avalue per fitted event.- Return type:
- 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:
- 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:
- 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:
- calibration_results: list[CalibrationResult]#
- events: list[EventRecord]#
- class SequentialFitter(model_factory, rain_stormflow, events, output_column='Q_pred')[source]#
Bases:
objectFit an
IModelto storm events one by one.- Parameters:
model_factory (Callable[[], IModel]) –
Zero-argument callable returning a fresh
IModelin CREATED state. Works with single UH models andEnsembleModel: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.minimizemethod, 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:
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 lazily — import 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:
IUnitHydroComponentAdapter base that bridges
UnitHydrographto theIModellifecycle.Do not instantiate or register this class directly. Use
create_uh_model()orregister_all_uh_models()to obtain concrete, registry-compatible subclasses.Lifecycle mapping
IModel method
Adapter action
initializeConstructs
UnitHydrograph(key), reads_registryto create oneScalarParameterper model parameter.validateDelegates to
parameters_valid().prepareStores the
rain_stormflowDataFrame; syncsScalarParametervalues →_uh.parameters.predictCalls
_uh.predict(); returns the DataFrame.finalizeReleases the stored DataFrame.
Parameter synchronisation
ScalarParametervalues are the source of truth. They are pushed to_uh.parametersbefore everypredictorfitcall. Afterfitthe optimised values are pulled back so both representations stay consistent.Infinite bounds
UnitHydrograph._registryusesnp.inffor unbounded parameters (e.g.A). These are clamped to ±:data:_INF_SUBSTITUTE when creatingScalarParameterobjects 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)#
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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
UnitHydrographand 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:
- 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 theAamplitude parameter divided out, sonp.sum(result) ≈ 1.0.Note
The
dt_hoursargument is accepted for API uniformity but does not resample the kernel.- Parameters:
- Returns:
Unit-area UH ordinate array.
- Return type:
- Raises:
RuntimeError – If
initialize()has not been called.
- get_output_field(name)#
Return the
FieldRecordfor name.
- get_scalar_parameter(name)#
Retrieve a registered scalar parameter by name.
- get_uh(max_steps=864, norm=0)[source]#
Return the unit hydrograph ordinate array from the wrapped model.
- Parameters:
- Returns:
UH ordinate array.
- Return type:
- Raises:
RuntimeError – If
initialize()has not been called.
- get_vector_parameter(name)#
Retrieve a registered vector parameter by name.
- inequality_constraints()#
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- initialize()[source]#
Construct the wrapped
UnitHydrographand register its parameters.- Returns:
Nothing.
- Return type:
None
- Raises:
TypeError – If called on the base
UnitHydrographAdapterinstead of a factory-created subclass.
- is_created()#
Return whether the model is in the
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()#
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()#
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()#
Return whether the model is in the
PREDICTEDstate.
- is_prepared()#
Return whether the model is in the
PREPAREDstate.
- is_validated()#
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()#
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()#
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- 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:
- Raises:
RuntimeError – If
initialize()orprepare()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().
- 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:
- 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:
- 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:
Trueif all parameters are within bounds.- Return type:
- property inequality_constraint_descriptions: list[str]#
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]#
Ordered list of registered inequality constraint names.
- property is_fit: bool#
Trueif the wrappedUnitHydrographhas been successfully fitted.- Returns:
Fit status of the wrapped model (
Falseif not yet built).- Return type:
- model_name: ClassVar[str] = 'uh-adapter'#
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]#
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState#
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- create_uh_model(uh_model_name)[source]#
Create and register a concrete
IModelsubclass for one UH model.
- register_all_uh_models()[source]#
Create and register adapters for every model in
UnitHydrograph._registry.Call this once after confirming that
uh_modelsis 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:
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 fractionRWwhose 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 |
|---|---|---|
|
Catchment area [acres] |
both |
|
Precipitation averaging time [hr] |
both |
|
Hydrograph half-life [hr] |
both |
|
Temperature averaging time [hr] |
both |
|
Cold-season temperature (Point 1) |
both |
|
Hot-season temperature (Point 2) |
both |
|
Dry-weather capture fraction |
standard |
|
Antecedent-moisture half-life [hr] |
standard |
|
Capture fraction at |
standard |
|
Capture fraction at |
standard |
|
Capture fraction at |
baseflow |
|
Capture fraction at |
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:
IModelReparameterized 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 butcold_temp/hot_tempmust 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) orCold_R(baseflow) at Point 1.hot_value (float | None) –
Hot_SHCF(standard) orHot_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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)#
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand a name in values is not registered.
- get_output_field(name)#
Return the
FieldRecordfor name.
- get_scalar_parameter(name)#
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)#
Retrieve a registered vector parameter by name.
- inequality_constraints()[source]#
Inequality constraint residuals (
g ≤ 0is feasible).Returns
[Cold_Temp - Hot_Temp]enforcingCold_Temp < Hot_Temp.
- is_created()#
Return whether the model is in the
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()#
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()#
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()#
Return whether the model is in the
PREDICTEDstate.
- is_prepared()#
Return whether the model is in the
PREPAREDstate.
- is_validated()#
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()#
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()#
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- predict(*args, **kwargs)[source]#
Run the AMM recursion and return the output time series.
- Returns:
DataFrame with columns
datetime,{output_name},capture_fraction,map,matempand — for the standard component —rwandshcf.- Return type:
- 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
datetimeandrainfall_in(imperial) orrainfall_mm(metric). An optionaltemperature(ortemperature_c) column drives the seasonal sigmoid; when absent it falls back to the midpoint ofCold_TempandHot_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().
- 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:
- 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:
- 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:
Trueif all parameters are within bounds andCold_Temp < Hot_Temp.- Return type:
- property inequality_constraint_descriptions: list[str]#
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]#
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str] = 'amm'#
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]#
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState#
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
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 eventsN triangular RTK unit hydrographs (
RTKTriangle)A configurable composite model mixing the IA model with any number of RTK triangles (
RDIIModel)area_acresparameter converts depth [mm] → flow [CFS] automaticallyCalibration via the generic
CalibrationProblem— usecolumn_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 excessRTKTriangle— single triangular RTK unit hydrographRTKEnsembleModel— additive ensemble of RDIIModelsRDIIModel— IA model + N configurable UH components
Helpers#
triangular_uh()— compute RTK triangle ordinate arraydefault_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:
IModelStateful initial-abstraction model implementing the
IModellifecycle.Constructor arguments seed the
initialize()parameter registry. Afterinitialize(), 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
Noneto 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
Noneto 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_availstarts atia_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
Noneto useT_refeverywhere.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.0disables melt).snow_T (float | None) – Rain/snow threshold [°C], or
Noneto disable snow.
- Returns:
Rainfall excess depth series, same length as rainfall_mm.
- Return type:
- 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand a name in values is not registered.
- compute_excess(rainfall_mm)[source]
Return rainfall excess and deplete
ia_availaccordingly.
- finalize()[source]
Release stored forcing data and advance to FINALIZED.
- Returns:
Nothing.
- Return type:
None
- get_output_field(name)
Return the
FieldRecordfor name.
- get_scalar_parameter(name)
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)
Retrieve a registered vector parameter by name.
- inequality_constraints()
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- 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
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()
Return whether the model is in the
PREDICTEDstate.- Returns:
Trueifpredict()has completed.- Return type:
- is_prepared()
Return whether the model is in the
PREPAREDstate.- Returns:
Trueifprepare()has completed.- Return type:
- is_validated()
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- predict()[source]
Compute rainfall excess for the prepared time series.
- Returns:
DataFrame with columns
datetimeand the unit-specific excess column (p_excess_inorp_excess_mm).- Return type:
- 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
datetimeand the unit-specific rainfall column (rainfall_inorrainfall_mm); an optionaltemperature_ccolumn defaults toT_refwhen 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().
- recovery_rate(temperature=None)[source]
Compute k_rec(T) = k0 + kT * exp(θ*(T - T_ref)), zeroed below T_freeze.
- 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:
- 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:
- 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_availtoia_max(fully recovered state).- Returns:
Nothing.
- Return type:
None
- step_dry(dt_hours, temperature=None)[source]
Advance
ia_availover a dry interval ofdt_hours.
- step_wet(delta_precip_mm)[source]
Deplete
ia_availfor a rainfall pulse ofdelta_precip_mmmm.
- validate()[source]
Validate parameter bounds and physical constraint T_freeze < T_ref.
- Returns:
Trueif all parameters are within bounds andT_freeze < T_ref.- Return type:
- property inequality_constraint_descriptions: list[str]
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str] = 'initial-abstraction'
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- class RDIIModel(ia_model=None, uh_components=None, units='imperial')[source]
Bases:
IModelRainfall-Derived Inflow and Infiltration model.
Combines one
IAModelwith N configurableIUnitHydroComponentinstances. 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 ap_excess_mmorp_excess_incolumn (depending on units). Defaults toIAModel.uh_components (list[IUnitHydroComponent], optional) – Unit hydrograph components. Each must implement
IUnitHydroComponent. Defaults to threeRTKTriangleinstances (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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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
FieldRecordfor name.
- get_scalar_parameter(name)
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)
Retrieve a registered vector parameter by name.
- 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.
- 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
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()
Return whether the model is in the
PREDICTEDstate.- Returns:
Trueifpredict()has completed.- Return type:
- is_prepared()
Return whether the model is in the
PREPAREDstate.- Returns:
Trueifprepare()has completed.- Return type:
- is_validated()
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- 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(orrdii_in),p_excess_mm(orp_excess_in).- Return type:
- 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_inorrainfall_mm(depending on units), and optionallyflow_cfsandtemperature_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().
- 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:
- 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:
- 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_refwhen both are present.- Returns:
Trueif all constraints are satisfied.- Return type:
- property inequality_constraint_descriptions: list[str]
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]
Ordered list of registered inequality constraint names.
- 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:
- property output_fields: list[FieldRecord]
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- class RTKEnsembleModel[source]
Bases:
objectAdditive ensemble of
RDIIModelinstances — one per RDII pathway.In SWMM each RTK pathway (fast / medium / slow) has its own independent initial-abstraction model.
RTKEnsembleModel.create()wires up n_modelsRDIIModelinstances — each carrying its ownIAModeland n_trianglesRTKTriangleobjects — into a single additiveEnsembleModel.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
IAModelconstructor.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:
IUnitHydroComponentTriangular RTK unit hydrograph component.
- Parameters:
- 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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 ownR_ifraction.- Parameters:
- Returns:
1-D array of normalized UH ordinates [1/hr].
- Return type:
- get_output_field(name)
Return the
FieldRecordfor name.
- get_scalar_parameter(name)
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)
Retrieve a registered vector parameter by name.
- inequality_constraints()
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- 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
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()
Return whether the model is in the
PREDICTEDstate.- Returns:
Trueifpredict()has completed.- Return type:
- is_prepared()
Return whether the model is in the
PREPAREDstate.- Returns:
Trueifprepare()has completed.- Return type:
- is_validated()
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- predict()[source]
Convolve rainfall excess with this triangle’s UH kernel and apply R-scaling.
- Returns:
DataFrame with columns
datetimeandrdii_mm.- Return type:
- 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
datetimeandp_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().
- 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:
- 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:
- 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:
Trueif all parameters are within bounds.- Return type:
- property base_duration: float
T * (1 + K).
- Returns:
Base duration
T * (1 + K)[hr].- Return type:
- Type:
Total triangle duration in hours
- property inequality_constraint_descriptions: list[str]
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str] = 'rtk-triangle'
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- 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:
- property state: ModelState
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- 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).
R —
R_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:
- 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:
- 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_NFrom 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 byR_{i}.
prepare() input DataFrame columns#
Column |
Required |
Notes |
|---|---|---|
|
Yes imperial metric No No |
Any pandas DatetimeLike
Depth per step [in]
Depth per step [mm]
Observed flow (optimizer)
Falls back to |
- class RDIIModel(ia_model=None, uh_components=None, units='imperial')[source]#
Bases:
IModelRainfall-Derived Inflow and Infiltration model.
Combines one
IAModelwith N configurableIUnitHydroComponentinstances. 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 ap_excess_mmorp_excess_incolumn (depending on units). Defaults toIAModel.uh_components (list[IUnitHydroComponent], optional) – Unit hydrograph components. Each must implement
IUnitHydroComponent. Defaults to threeRTKTriangleinstances (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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)#
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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
FieldRecordfor name.
- get_scalar_parameter(name)#
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)#
Retrieve a registered vector parameter by name.
- 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.
- 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
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()#
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()#
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()#
Return whether the model is in the
PREDICTEDstate.
- is_prepared()#
Return whether the model is in the
PREPAREDstate.
- is_validated()#
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()#
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()#
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- 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(orrdii_in),p_excess_mm(orp_excess_in).- Return type:
- 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_inorrainfall_mm(depending on units), and optionallyflow_cfsandtemperature_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().
- 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:
- 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:
- 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_refwhen both are present.- Returns:
Trueif all constraints are satisfied.- Return type:
- property inequality_constraint_descriptions: list[str]#
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]#
Ordered list of registered inequality constraint names.
- 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:
- property output_fields: list[FieldRecord]#
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState#
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
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:
IModelStateful initial-abstraction model implementing the
IModellifecycle.Constructor arguments seed the
initialize()parameter registry. Afterinitialize(), 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
Noneto 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
Noneto 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_availstarts atia_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
Noneto useT_refeverywhere.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.0disables melt).snow_T (float | None) – Rain/snow threshold [°C], or
Noneto disable snow.
- Returns:
Rainfall excess depth series, same length as rainfall_mm.
- Return type:
- 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)#
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand a name in values is not registered.
- finalize()[source]#
Release stored forcing data and advance to FINALIZED.
- Returns:
Nothing.
- Return type:
None
- get_output_field(name)#
Return the
FieldRecordfor name.
- get_scalar_parameter(name)#
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)#
Retrieve a registered vector parameter by name.
- inequality_constraints()#
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- 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
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()#
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()#
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()#
Return whether the model is in the
PREDICTEDstate.
- is_prepared()#
Return whether the model is in the
PREPAREDstate.
- is_validated()#
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()#
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()#
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- predict()[source]#
Compute rainfall excess for the prepared time series.
- Returns:
DataFrame with columns
datetimeand the unit-specific excess column (p_excess_inorp_excess_mm).- Return type:
- 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
datetimeand the unit-specific rainfall column (rainfall_inorrainfall_mm); an optionaltemperature_ccolumn defaults toT_refwhen 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().
- recovery_rate(temperature=None)[source]#
Compute k_rec(T) = k0 + kT * exp(θ*(T - T_ref)), zeroed below T_freeze.
- 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:
- 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:
- 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_availtoia_max(fully recovered state).- Returns:
Nothing.
- Return type:
None
- validate()[source]#
Validate parameter bounds and physical constraint T_freeze < T_ref.
- Returns:
Trueif all parameters are within bounds andT_freeze < T_ref.- Return type:
- property inequality_constraint_descriptions: list[str]#
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]#
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str] = 'initial-abstraction'#
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]#
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- property state: ModelState#
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
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:
objectAdditive ensemble of
RDIIModelinstances — one per RDII pathway.In SWMM each RTK pathway (fast / medium / slow) has its own independent initial-abstraction model.
RTKEnsembleModel.create()wires up n_modelsRDIIModelinstances — each carrying its ownIAModeland n_trianglesRTKTriangleobjects — into a single additiveEnsembleModel.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
IAModelconstructor.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:
IUnitHydroComponentTriangular RTK unit hydrograph component.
- Parameters:
- 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 byCalibrationProblemforVectorParameterelements) sets that single element of the named vector parameter in-place.
- apply_parameter_values(values, *, skip_missing=True)#
Apply a mapping of parameter names to values in-place.
- Parameters:
- Returns:
Names of the parameters that were actually updated.
- Return type:
- Raises:
KeyError – If skip_missing is
Falseand 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 ownR_ifraction.- Parameters:
- Returns:
1-D array of normalized UH ordinates [1/hr].
- Return type:
- get_output_field(name)#
Return the
FieldRecordfor name.
- get_scalar_parameter(name)#
Retrieve a registered scalar parameter by name.
- get_vector_parameter(name)#
Retrieve a registered vector parameter by name.
- inequality_constraints()#
Inequality constraint residuals where
g_j <= 0means feasible.Override in subclasses to expose model-specific constraints to the calibration framework. The default returns an empty list (unconstrained).
- 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
CREATEDstate.- Returns:
Trueif the model has been constructed but not yet initialized.- Return type:
- is_finalized()#
Return whether the model is in the
FINALIZEDstate.- Returns:
Trueiffinalize()has completed.- Return type:
- is_initialized()#
Return whether the model is in the
INITIALIZEDstate.- Returns:
Trueifinitialize()has completed.- Return type:
- is_predicted()#
Return whether the model is in the
PREDICTEDstate.
- is_prepared()#
Return whether the model is in the
PREPAREDstate.
- is_validated()#
Return whether the model is in the
VALIDATEDstate.- Returns:
Trueifvalidate()has completed successfully.- Return type:
- output_field_metadata()#
Return a DataFrame describing every registered output field.
- Returns:
One row per output field with
field,units,calibratableanddescriptioncolumns.- Return type:
- parameters_valid()#
Return whether every registered parameter is within its bounds.
- Returns:
Truewhen all scalar and vector parameters satisfy their bounds;Falseotherwise.- Return type:
- predict()[source]#
Convolve rainfall excess with this triangle’s UH kernel and apply R-scaling.
- Returns:
DataFrame with columns
datetimeandrdii_mm.- Return type:
- 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
datetimeandp_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().
- 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:
- 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:
- 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:
Trueif all parameters are within bounds.- Return type:
- property base_duration: float#
T * (1 + K).
- Returns:
Base duration
T * (1 + K)[hr].- Return type:
- Type:
Total triangle duration in hours
- property inequality_constraint_descriptions: list[str]#
Ordered list of registered inequality constraint descriptions.
- property inequality_constraint_names: list[str]#
Ordered list of registered inequality constraint names.
- model_name: ClassVar[str] = 'rtk-triangle'#
Unique string identifier for this model type. Must be defined by every concrete subclass.
- property output_fields: list[FieldRecord]#
Ordered list of all registered output-field records.
- Returns:
FieldRecordobjects in registration order.- Return type:
- 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:
- property state: ModelState#
Current lifecycle state of the model.
- Returns:
The model’s current lifecycle state.
- Return type:
- 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).
R —
R_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:
- 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:
- Raises:
ValueError – If
dt_hours <= 0.
Calibration#
The sparsehydro.calibration subpackage provides solver-agnostic
abstractions for parameter estimation:
CalibrationProblem— wraps anyIModelwith observed data and objectives.CalibrationResult— stores the Pareto front, per-generation history, and metadata.A library of
IObjectiveimplementations covering MSE, NSE, KGE, and more.Multiple solver backends (see Solvers below).
sparsehydro.calibration — general-purpose model calibration abstractions.
Public API#
Objectives
Name |
Description |
|---|---|
|
Abstract objective function interface |
|
Mean squared error |
|
Root mean squared error |
|
Mean absolute error |
|
Flow-weighted MSE |
|
Nash-Sutcliffe efficiency |
|
Kling-Gupta efficiency |
|
Absolute percent bias |
|
Relative total volume error |
|
NSE on log-transformed flows |
|
Willmott’s index of agreement |
|
Lin’s concordance correlation coefficient |
Problem & results
Name |
Description |
|---|---|
|
Wraps any IModel + observed + objectives |
|
Pareto front + generation history |
|
Per-generation population snapshot |
Solvers
Name |
Description |
|---|---|
|
Abstract solver interface |
|
NSGA-II (requires pymoo) |
|
SMPSO / OMOPSO (requires platypus-opt) |
|
Any Platypus algorithm (requires platypus-opt) |
|
SciPy single-objective (requires scipy) |
- class CalibrationProblem(model, data=None, objectives=None, column_map=None, prepare_fn=None, mask=None, **prepare_kwargs)[source]
Bases:
objectSolver-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
ISolverwithout modification.All column/role mappings are expressed through a single
column_mapdict:Non-reserved entries
{target_col: source_col}— renamedata[source_col]totarget_colbefore callingmodel.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
datais supplied.data (Any) – Input data (any type). Passed through the preprocessing pipeline and then to
model.prepare(). May beNoneif the model is already in PREPARED state, but thencolumn_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_datacallable for complex preprocessing. Mutually exclusive with non-reservedcolumn_maprename 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 likeobserved/predicted. Equivalent tocolumn_map["mask"](the explicit argument wins if both are given). Individual objectives that carry their ownmaskoverride this default. Positions where observed or predicted isNaNare 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 > 0and the model reports inequality constraints, a squared penaltypenalty_weight * Σ max(0, g_j)²is added to steer constraint-unaware solvers toward feasible regions. Passpenalty_weight=0.0when the solver handles constraints natively.Only parameters with
calibrate=Trueare 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_objectivesin minimisation form.- Return type:
- make_copy()[source]
Return a deep-copied
CalibrationProblemsafe 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:
- property constraint_names: list[str]
Ordered list of inequality constraint names (empty if unconstrained).
- 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 param_names: list[str]
Ordered list of calibrated search-dimension names.
Scalar parameters appear by their own name; each calibratable
VectorParametercontributes one entry per element, named"{vector_name}[{index}]".
- class CalibrationResult(history, pareto_X, pareto_F, param_names, objective_names, minimize_flags)[source]
Bases:
objectGeneral-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 byobjective_display_values()andto_pareto_dataframe().- Parameters:
history (list[GenerationRecord]) – One
GenerationRecordper 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]) –
Truefor minimised objectives;Falsefor 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_Fis always in minimisation form, soargminalways selects the best solution.- Parameters:
objective_name (str) – Name matching one of
objective_names.- Returns:
1-D parameter array.
- Return type:
- Raises:
ValueError – If
objective_nameis 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:
- 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(Trueonly for solutions on the final generation’s Pareto front).- Return type:
- class ConcordanceCorrelationCoefficient(mask=None)[source]
Bases:
IObjectiveLin’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"minimize –
False
- 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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class GenerationRecord(generation, X, F, n_pareto)
Bases:
tupleCreate 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:
ABCAbstract calibration objective.
Subclasses must set the class variables
nameandminimizeand implementevaluate().- Variables:
name – Short snake_case identifier (used as column name in result DataFrames).
minimize –
Trueif lower scores are better;Falsefor 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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class ISolver[source]
Bases:
ABCAbstract calibration solver.
All solvers accept a
CalibrationProblemand return aCalibrationResult.solve()accepts**kwargsthat 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:
- class IndexOfAgreement(mask=None)[source]
Bases:
IObjectiveWillmott’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"minimize –
False
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class KGE(mask=None)[source]
Bases:
IObjectiveKling–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"minimize –
False
- Raises:
ValueError – If
std(observed) == 0ormean(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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class LogNSE(epsilon=0.01, mask=None)[source]
Bases:
IObjectiveNash–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
NashSutcliffewhen 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). Default0.01.mask (np.ndarray | None) – Optional boolean array selecting the timesteps to score over.
- Variables:
name –
"log_nse"minimize –
False
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class MAE(mask=None)[source]
Bases:
IObjectiveMean absolute error.
- Variables:
name –
"mae"minimize –
True
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class MSE(mask=None)[source]
Bases:
IObjectiveMean squared error.
- Variables:
name –
"mse"minimize –
True
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class NSGAIISolver(pop_size=100, n_gen=200, seed=42, verbose=False, n_jobs=1, callback=None)[source]
Bases:
ISolverMulti-objective NSGA-II calibration solver.
Works with any
CalibrationProblem. For multi-objective problems the full Pareto front is returned inpareto_Xandpareto_F.- Parameters:
pop_size (int) – Population size per generation.
n_gen (int) – Total number of generations.
seed (int or None) – Random seed for reproducibility (
Nonefor 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:
- class NashSutcliffe(mask=None)[source]
Bases:
IObjectiveNash–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"minimize –
False
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class PBIAS(mask=None)[source]
Bases:
IObjectiveAbsolute 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"minimize –
True
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class ParticleSwarmSolver(swarm_size=100, leader_size=100, n_evaluations=10000, epsilons=None, seed=42, record_frequency=1, callback=None, **algorithm_kwargs)[source]
Bases:
ISolverMulti-objective Particle Swarm solver backed by Platypus.
Selects
platypus.OMOPSO(ε-dominance archive) when epsilons are provided, otherwise usesplatypus.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;
Noneuses SMPSO. Length must equal the number of objectives.seed (int or None) – Random seed (
Nonefor 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:
- class PeakWeightedMSE(power=1.0, mask=None)[source]
Bases:
IObjectivePeak-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.0reduces 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"minimize –
True
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class PlatypusSolver(algorithm_class, n_evaluations=10000, seed=42, record_frequency=1, callback=None, **algorithm_kwargs)[source]
Bases:
ISolverGeneric Platypus multi-objective solver.
Wraps any
platypus.Algorithmsubclass — NSGA-II, NSGA-III, SPEA2, MOEA/D, GDE3, IBEA, OMOPSO, SMPSO, ε-MOEA, etc. — in theISolverinterface.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
randomandnumpy.random(Nonefor non-deterministic runs).record_frequency (int) – Append a
GenerationRecordto 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 intoalgorithm_kwargsand forwarded to the algorithm constructor.
- Returns:
Result with per-iteration history and final Pareto front.
- Return type:
- class ProgressCallback(frequency=1)[source]
Bases:
objectPrints 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:
IObjectiveRoot mean squared error.
- Variables:
name –
"rmse"minimize –
True
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class ScipySolver(method='differential_evolution', objective_index=0, maxiter=1000, seed=42, verbose=False, **kwargs)[source]
Bases:
ISolverSingle-objective SciPy calibration solver.
- Parameters:
method (str) –
"differential_evolution"(default) or anyscipy.optimize.minimizemethod 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:
- class VolumeRelativeError(mask=None)[source]
Bases:
IObjectiveRelative 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"minimize –
True
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
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:
objectSolver-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
ISolverwithout modification.All column/role mappings are expressed through a single
column_mapdict:Non-reserved entries
{target_col: source_col}— renamedata[source_col]totarget_colbefore callingmodel.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
datais supplied.data (Any) – Input data (any type). Passed through the preprocessing pipeline and then to
model.prepare(). May beNoneif the model is already in PREPARED state, but thencolumn_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_datacallable for complex preprocessing. Mutually exclusive with non-reservedcolumn_maprename 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 likeobserved/predicted. Equivalent tocolumn_map["mask"](the explicit argument wins if both are given). Individual objectives that carry their ownmaskoverride this default. Positions where observed or predicted isNaNare 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 > 0and the model reports inequality constraints, a squared penaltypenalty_weight * Σ max(0, g_j)²is added to steer constraint-unaware solvers toward feasible regions. Passpenalty_weight=0.0when the solver handles constraints natively.Only parameters with
calibrate=Trueare 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_objectivesin minimisation form.- Return type:
- make_copy()[source]#
Return a deep-copied
CalibrationProblemsafe 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:
- property constraint_names: list[str]#
Ordered list of inequality constraint names (empty if unconstrained).
- property n_params: int#
Number of calibratable search dimensions (scalars + flattened vector elements).
- property param_names: list[str]#
Ordered list of calibrated search-dimension names.
Scalar parameters appear by their own name; each calibratable
VectorParametercontributes 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:
objectGeneral-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 byobjective_display_values()andto_pareto_dataframe().- Parameters:
history (list[GenerationRecord]) – One
GenerationRecordper 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]) –
Truefor minimised objectives;Falsefor 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_Fis always in minimisation form, soargminalways selects the best solution.- Parameters:
objective_name (str) – Name matching one of
objective_names.- Returns:
1-D parameter array.
- Return type:
- Raises:
ValueError – If
objective_nameis 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:
- class GenerationRecord(generation, X, F, n_pareto)#
Bases:
tuplePer-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 |
|---|---|
|
Mean squared error (minimise) |
|
Root mean squared error (minimise) |
|
Mean absolute error (minimise) |
|
Flow-weighted MSE — penalises peak-flow errors |
|
Nash-Sutcliffe efficiency (maximise) |
|
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 |
|---|---|---|
True |
Mean squared error |
|
True |
Root mean squared error |
|
True |
Mean absolute error |
|
True |
Flow-weighted MSE (peaks penalised) |
|
True |
Absolute percent bias (volume balance) |
|
True |
Relative total runoff volume error |
|
False |
Nash–Sutcliffe efficiency |
|
False |
NSE on log-transformed flows |
|
False |
Kling–Gupta efficiency |
|
False |
Willmott’s Index of Agreement |
|
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:
IObjectiveLin’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"minimize –
False
- 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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class IObjective(mask=None)[source]#
Bases:
ABCAbstract calibration objective.
Subclasses must set the class variables
nameandminimizeand implementevaluate().- Variables:
name – Short snake_case identifier (used as column name in result DataFrames).
minimize –
Trueif lower scores are better;Falsefor 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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class IndexOfAgreement(mask=None)[source]#
Bases:
IObjectiveWillmott’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"minimize –
False
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class KGE(mask=None)[source]#
Bases:
IObjectiveKling–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"minimize –
False
- Raises:
ValueError – If
std(observed) == 0ormean(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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class LogNSE(epsilon=0.01, mask=None)[source]#
Bases:
IObjectiveNash–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
NashSutcliffewhen 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). Default0.01.mask (np.ndarray | None) – Optional boolean array selecting the timesteps to score over.
- Variables:
name –
"log_nse"minimize –
False
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class MAE(mask=None)[source]#
Bases:
IObjectiveMean absolute error.
- Variables:
name –
"mae"minimize –
True
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class MSE(mask=None)[source]#
Bases:
IObjectiveMean squared error.
- Variables:
name –
"mse"minimize –
True
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class NashSutcliffe(mask=None)[source]#
Bases:
IObjectiveNash–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"minimize –
False
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class PBIAS(mask=None)[source]#
Bases:
IObjectiveAbsolute 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"minimize –
True
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class PeakWeightedMSE(power=1.0, mask=None)[source]#
Bases:
IObjectivePeak-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.0reduces 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"minimize –
True
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class RMSE(mask=None)[source]#
Bases:
IObjectiveRoot mean squared error.
- Variables:
name –
"rmse"minimize –
True
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
- class VolumeRelativeError(mask=None)[source]#
Bases:
IObjectiveRelative 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"minimize –
True
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 explicitmaskargument.None(default) uses all values. Column-name / callable mask specifications are resolved byCalibrationProblem, 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
observedorpredictedisNaNare always excluded, in addition to any boolean mask. The effective mask is the explicitmaskargument when supplied, otherwise the objective’s ownmask(an explicit argument wins — this letsCalibrationProblemapply 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
maskisTrueare included.None(default) falls back tomask.
- Returns:
Scalar objective value computed over the selected subset.
- Return type:
- 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:
- Raises:
ValueError – If arrays are incompatible or the score is undefined (e.g. constant observed series for NSE).
Solvers#
All solvers implement ISolver
and return a CalibrationResult.
Class |
Algorithm |
Extra dep |
|---|---|---|
NSGA-II (pymoo) |
|
|
SciPy minimisers |
|
|
Any Platypus algorithm |
|
|
SMPSO / OMOPSO (PSO) |
|
sparsehydro.calibration.solvers — solver abstractions and implementations.
- class ISolver[source]
Bases:
ABCAbstract calibration solver.
All solvers accept a
CalibrationProblemand return aCalibrationResult.solve()accepts**kwargsthat 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:
- class NSGAIISolver(pop_size=100, n_gen=200, seed=42, verbose=False, n_jobs=1, callback=None)[source]
Bases:
ISolverMulti-objective NSGA-II calibration solver.
Works with any
CalibrationProblem. For multi-objective problems the full Pareto front is returned inpareto_Xandpareto_F.- Parameters:
pop_size (int) – Population size per generation.
n_gen (int) – Total number of generations.
seed (int or None) – Random seed for reproducibility (
Nonefor 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:
- class ParticleSwarmSolver(swarm_size=100, leader_size=100, n_evaluations=10000, epsilons=None, seed=42, record_frequency=1, callback=None, **algorithm_kwargs)[source]
Bases:
ISolverMulti-objective Particle Swarm solver backed by Platypus.
Selects
platypus.OMOPSO(ε-dominance archive) when epsilons are provided, otherwise usesplatypus.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;
Noneuses SMPSO. Length must equal the number of objectives.seed (int or None) – Random seed (
Nonefor 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:
- class PlatypusSolver(algorithm_class, n_evaluations=10000, seed=42, record_frequency=1, callback=None, **algorithm_kwargs)[source]
Bases:
ISolverGeneric Platypus multi-objective solver.
Wraps any
platypus.Algorithmsubclass — NSGA-II, NSGA-III, SPEA2, MOEA/D, GDE3, IBEA, OMOPSO, SMPSO, ε-MOEA, etc. — in theISolverinterface.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
randomandnumpy.random(Nonefor non-deterministic runs).record_frequency (int) – Append a
GenerationRecordto 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 intoalgorithm_kwargsand forwarded to the algorithm constructor.
- Returns:
Result with per-iteration history and final Pareto front.
- Return type:
- class ScipySolver(method='differential_evolution', objective_index=0, maxiter=1000, seed=42, verbose=False, **kwargs)[source]
Bases:
ISolverSingle-objective SciPy calibration solver.
- Parameters:
method (str) –
"differential_evolution"(default) or anyscipy.optimize.minimizemethod 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:
Solver Base#
Abstract solver interface.
- class ISolver[source]#
Bases:
ABCAbstract calibration solver.
All solvers accept a
CalibrationProblemand return aCalibrationResult.solve()accepts**kwargsthat 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:
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:
ISolverMulti-objective NSGA-II calibration solver.
Works with any
CalibrationProblem. For multi-objective problems the full Pareto front is returned inpareto_Xandpareto_F.- Parameters:
pop_size (int) – Population size per generation.
n_gen (int) – Total number of generations.
seed (int or None) – Random seed for reproducibility (
Nonefor 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:
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.minimizemethod 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:
ISolverSingle-objective SciPy calibration solver.
- Parameters:
method (str) –
"differential_evolution"(default) or anyscipy.optimize.minimizemethod 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:
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:
ISolverMulti-objective Particle Swarm solver backed by Platypus.
Selects
platypus.OMOPSO(ε-dominance archive) when epsilons are provided, otherwise usesplatypus.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;
Noneuses SMPSO. Length must equal the number of objectives.seed (int or None) – Random seed (
Nonefor 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:
- class PlatypusSolver(algorithm_class, n_evaluations=10000, seed=42, record_frequency=1, callback=None, **algorithm_kwargs)[source]#
Bases:
ISolverGeneric Platypus multi-objective solver.
Wraps any
platypus.Algorithmsubclass — NSGA-II, NSGA-III, SPEA2, MOEA/D, GDE3, IBEA, OMOPSO, SMPSO, ε-MOEA, etc. — in theISolverinterface.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
randomandnumpy.random(Nonefor non-deterministic runs).record_frequency (int) – Append a
GenerationRecordto 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 intoalgorithm_kwargsand forwarded to the algorithm constructor.
- Returns:
Result with per-iteration history and final Pareto front.
- Return type:
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.