Source code for rameau.core.settings.optimization_settings

# Copyright 2025, BRGM
# 
# This file is part of Rameau.
# 
# Rameau is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
# 
# Rameau is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along with
# Rameau. If not, see <https://www.gnu.org/licenses/>.
#
"""
Model optimisation settings.
"""

from __future__ import annotations
from typing import Optional, Union
import datetime

from rameau.wrapper import COptimizationSettings

from rameau.core._abstract_wrapper import AbstractWrapper
from rameau.core._utils import _check_literal, _set_datetime, _get_datetime
from rameau._typing import MethodType, TransformationType, ObjFunctionType
from rameau.core._descriptor import (
    _IntDescriptor,
    _StrDescriptor,
    _DatetimeDescriptor,
    _BoolDescriptor,
    _VectorDescriptor
)

[docs] class OptimizationSettings(AbstractWrapper): """Model optimisation settings. Parameters ---------- maxit: `int`, optional Number of iterations for the Rosenbrock algorithm. If not provided, default value is zero, i.e. no optimisation will be performed. starting_date: `datetime.datetime`, optional The date and time defining the start of the period to consider in the input data for the optimisation run. ending_date: `datetime.datetime`, optional The date and time defining the end of the period to consider in the input data for the optimisation run. method: `str`, optional The approach to use when several gauged watersheds need to be considered in the optimisation run. This is typically the case when several independent watersheds are considered at once (i.e. batch of lumped watersheds), or when a watershed is considered as a collection of interconnected sub-watersheds (i.e. semi-distributed watershed). ================= ========================================= method description ================= ========================================= ``'all'`` All the gauged watersheds are optimised at once. This method is only recommended for a single lumped watershed or for a semi-distributed watershed. This is the default method. ``'independent'`` The gauged watersheds are optimised one after another, based on the order they are provided in the `Tree`. The optimised parameter values are sustained between the optimisation iterations. This method is only recommended for a batch of lumped watersheds. ``'strahler'`` All the gauged locations with the same Strahler order are grouped and considered together. The optimisation is performed sequentially for each group based on increasing Strahler order. This method is only recommended for a semi-distributed watershed. ================= ========================================= transformation: `str`, optional The function to apply to transform the observed and predicted river flow (Q) before computing the objective function. ================= ========================================= transformation description ================= ========================================= ``'no'`` No transformation is performed. This is the default behaviour. ``'square root'`` The square root function f(Q) = √Q is applied. ``'inverse'`` The reciprocal function f(Q) = 1/Q is applied. ``'fifth root'`` The fifth root function f(Q) = ⁵√Q is applied. ``'log'`` The natural logarithm function f(Q) = ln(Q) is applied. ================= ========================================= river_objective_function: `str`, optional The objective function to use to compare the observed and predicted river flow. ========================= =================================== river_objective_function description ========================= =================================== ``'nse'`` The Nash-Sutcliffe Efficiency (NSE) metric is used :cite:p:`1970:nash_river`. ``'kge'`` The original Kling-Gupta efficiency (KGE) metric is used :cite:p:`2009:gupta_decomposition`. ``'kge_2012'`` The modified Kling-Gupta efficiency (KGE\') metric is used :cite:p:`2012:kling_runoff`. ========================= =================================== selected_watersheds: `list` or `int`, optional The indices of the watersheds to consider in the optimisation run. The indices relate to the positions in the sequence of watersheds specified in the `Tree`. If not provided, all gauged watersheds are considered. verbose : `bool`, optional True if the verbose mode is activated. The verbose mode prints the iteration number and the associated objective function value. Returns ------- `OptimizationSettings` """ _computed_attributes = ( "maxit", "starting_date", "ending_date", "method", "transformation", "river_objective_function", "selected_watersheds", "verbose" ) _c_class = COptimizationSettings maxit: int = _IntDescriptor( 0, "Number of iterations for the Rosenbrock algorithm." ) #type: ignore starting_date: datetime.datetime = _DatetimeDescriptor( 0, "The date and time defining the start of the period to consider " "in the input data for the optimisation run." ) #type: ignore ending_date: datetime.datetime = _DatetimeDescriptor( 1, "The date and time defining the end of the period to consider " "in the input data for the optimisation run." ) #type: ignore transformation: str = _StrDescriptor( 0, "The function to apply to transform the observed and predicted " "river flow before computing the objective function." ) #type: ignore river_objective_function: str = _StrDescriptor( 1, "The objective function to use to compare the observed and " "predicted river flow." ) #type: ignore method: str = _StrDescriptor( 2, "The approach to use when several gauged watersheds need to " "be considered in the optimisation run." ) #type: ignore selected_watersheds: Union[list[int], list[tuple]] = _VectorDescriptor( 0, int, "The indices of the watersheds to consider in the optimisation run." ) #type: ignore verbose: bool = _BoolDescriptor( 0, "Whether the verbose mode is activated. True when it is." ) #type: ignore def __init__( self, maxit: int = 0, starting_date: Optional[datetime.datetime] = None, ending_date: Optional[datetime.datetime] = None, method: MethodType = "all", transformation: TransformationType = "no", river_objective_function: ObjFunctionType = 'nse', selected_watersheds: Optional[list[int]] = None, verbose: bool = False ) -> None: self._init_c() self.maxit = maxit if starting_date is not None: self.starting_date = starting_date else: self.starting_date = datetime.datetime(9999, 12, 31) if ending_date is not None: self.ending_date = ending_date else: self.ending_date = datetime.datetime(9999, 12, 31) _check_literal( transformation, ["no", "square root", "inverse", "fifth root", "log"] ) self.transformation = transformation _check_literal( method, ["all", "strahler", "independent"] ) self.method = method _check_literal( river_objective_function, ["nse", "kge", "kge_2012"] ) self.river_objective_function = river_objective_function if selected_watersheds is not None: if isinstance(selected_watersheds, list): self.selected_watersheds = selected_watersheds else: raise TypeError(f"Type {type(selected_watersheds)} not allowed.") self.verbose = verbose