Source code for rameau.core.settings.forecast_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/>.
#
"""
Forecast settings.
"""

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

from rameau.wrapper import CForecastSettings

from rameau.core._abstract_wrapper import AbstractWrapper
from rameau.core._utils import _check_literal, _set_datetime, _get_datetime

[docs] class ForecastSettings(AbstractWrapper): """ Forecast settings. Parameters ---------- emission_date: `datetime.datetime`, optional The date and time on which to issue a forecast. scope: `datetime.timedelta`, optional The duration for which to run the forecast. If not provided, set to one day. year_members: `list` or `ìnt`, optional The years to consider to form the forecast ensemble members. If not provided, all years in record are considered. correction: `str`, optional The approach to use to correct the initial conditions before issuing the forecast. ================= ========================================= correction description ================= ========================================= ``'no'`` No correction is performed. This is the default behaviour. ``'halflife'`` A correction using the observation of the forecast variable on the issue date is applied and then the correction is gradually dampened overtime based on a half-life parameter. ``'enkf'`` A correction using an ensemble Kalman filter approach is used (experimental). ================= ========================================= pumping_date: `datetime.datetime`, optional The date and time on which to start pumping. quantiles_output: `bool`, optional Whether to reduce the forecast ensemble members to specific climatology quantiles. If not provided, all years in record or years specified via the ``year_members`` parameter are considered. The quantiles can be chosen via the ``quantiles`` parameter. quantiles: `list` or `int`, optional The climatology percentiles to include in the forecast ensemble members. Only considered if ``quantiles_output`` is set to `True`. By default, the percentiles computed are 10, 20, 50, 80, and 90. norain: `bool`, optional Whether to include an extra ensemble member corresponding to a completely rain-free year. By default, this member is not included in the forecast output. Returns ------- `ForecastSettings` """ _computed_attributes = ( "emission_date", "scope", "year_members", "correction", "pumping_date", "quantiles_output", "quantiles", "norain" ) _c_class = CForecastSettings def __init__( self, emission_date: Optional[datetime.datetime] = None, scope: Optional[datetime.timedelta] = datetime.timedelta(1), year_members: Optional[list[int]] = None, correction: Optional[Literal["no", "halflife", "enkf"]] = None, pumping_date: Optional[datetime.datetime] = None, quantiles_output: bool = False, quantiles: Optional[list[int]] = [10, 20, 50, 80, 90], norain: bool = False ) -> None: self._init_c() if emission_date is not None: self.emission_date = emission_date else: self.emission_date = datetime.datetime(9999, 12, 31) if pumping_date is not None: self.pumping_date = pumping_date else: self.pumping_date = datetime.datetime(9999, 12, 31) self.scope = scope if correction is None: correction = "no" _check_literal( correction, ["no", "halflife", "enkf"] ) self.correction = correction if year_members is not None: if isinstance(year_members, list): self.year_members = year_members else: raise TypeError(f"Type {type(year_members)} not allowed.") self.quantiles_output = quantiles_output if isinstance(quantiles, list): self.quantiles = quantiles else: raise TypeError(f"Type {type(quantiles)} not allowed.") self.norain = norain @property @_get_datetime def emission_date(self) -> datetime.datetime: """The date and time on which to issue a forecast. Returns ------- `datetime.datetime` """ return self._m.getEmissionDate() @emission_date.setter @_set_datetime def emission_date(self, v: datetime.datetime) -> None: self._m.setEmissionDate(v) @property @_get_datetime def pumping_date(self) -> datetime.datetime: """The date and time on which to start pumping. Returns ------- `datetime.datetime` """ return self._m.getPumpingDate() @pumping_date.setter @_set_datetime def pumping_date(self, v: datetime.datetime) -> None: self._m.setPumpingDate(v) @property def scope(self) -> datetime.timedelta: """The duration for which to run the forecast. Returns ------- `datetime.timedelta` """ return self._m.getScope() @scope.setter def scope(self, v: datetime.timedelta) -> None: self._m.setScope(v) @property def year_members(self) -> list[int]: """The years to consider to form the forecast ensemble members. Returns ------- `list` """ return self._m.getYearMembers() @year_members.setter def year_members(self, v) -> None: if v: self._m.setYearMembers(v) @property def quantiles(self) -> list[float]: """The climatology percentiles to include in the forecast ensemble members. Returns ------- `list` """ return self._m.getQuantiles() @quantiles.setter def quantiles(self, v) -> None: if v: self._m.setQuantiles(v) @property def quantiles_output(self) -> bool: """Whether to reduce the forecast ensemble members to specific climatology quantiles. Returns ------- `bool` """ return self._m.getQuantilesOutput() @quantiles_output.setter def quantiles_output(self, v) -> None: self._m.setQuantilesOutput(v) @property def norain(self) -> bool: """Whether to include an extra ensemble member corresponding to a completely rain-free year. Returns ------- `bool` """ return self._m.getNoRain() @norain.setter def norain(self, v) -> None: self._m.setNoRain(v) @property def correction(self) -> str: """The approach to use to correct the initial conditions before issuing a forecast. Returns ------- `str` """ return self._m.getCorrection() @correction.setter def correction(self, v) -> None: self._m.setCorrection(v)