"""Threshold abstract class and ThresholdBuilderInput type."""
from __future__ import annotations
import abc
from collections.abc import Sequence
from typing import TYPE_CHECKING, Any, Callable, TypedDict, Union
import xarray as xr
from xarray import DataArray, Dataset
from icclim._core.model.logical_link import LogicalLink, LogicalLinkRegistry
if TYPE_CHECKING:
from datetime import datetime
import jinja2
import pint
from icclim._core.generic.threshold.bounded import BoundedThreshold
from icclim._core.generic.threshold.threshold_templates import (
ThresholdMetadata,
)
from icclim._core.model.operator import Operator
from icclim._core.model.quantile_interpolation import (
QuantileInterpolation,
)
ThresholdValueType = Union[
str,
float,
int,
Dataset,
DataArray,
Sequence[Union[float, int, str]],
None,
]
[docs]
class Threshold(abc.ABC):
"""
Abstract class for all thresholds.
See :ref:`generic_indices_recipes` for how to use custom thresholds.
"""
operator: Operator | str
value: ThresholdValueType
unit: str | None = None
initial_query: str | None
threshold_min_value: pint.Quantity | None = None
threshold_var_name: str | None
prepare: Callable | None = None
is_ready: bool | None = None
@abc.abstractmethod
@abc.abstractmethod
def __eq__(self, other: Threshold) -> bool:
"""Check if two Threshold are equal."""
...
def __and__(self, other: Threshold) -> BoundedThreshold:
"""Build a BoundedThreshold from two existing Threshold with a "AND" LogicalLink.""" # noqa: E501
from icclim._core.generic.threshold.bounded import BoundedThreshold
return BoundedThreshold(
thresholds=[self, other],
logical_link=LogicalLinkRegistry.LOGICAL_AND,
initial_query=None,
)
def __or__(self, other: Threshold) -> BoundedThreshold:
"""Build a BoundedThreshold from two existing Threshold with a "OR" LogicalLink.""" # noqa: E501
from icclim._core.generic.threshold.bounded import BoundedThreshold
return BoundedThreshold(
thresholds=[self, other],
logical_link=LogicalLinkRegistry.LOGICAL_OR,
initial_query=None,
)
@abc.abstractmethod
[docs]
def compute(
self,
comparison_data: xr.DataArray,
override_op: Callable[[DataArray, DataArray], DataArray] | None = None,
**kwargs,
) -> DataArray:
"""
Compute the exceedance of the threshold.
For example, if the threshold is 10 and the comparison_data is [5, 10, 15],
with a ">" operator, the exceedance will be [False, False, True].
The operator can be overridden by `override_op`.
This is needed when self.operator is REACH.
Parameters
----------
comparison_data: xr.DataArray
Data that must be compared to self threshold
override_op: Callable[[DataArray, DataArray], DataArray] | None
Operator to override self.operator compute function.
Optional.
kwargs:
Keyword arguments passed to the concrete `compute` implementations.
This makes the `compute` interface contract unreliable.
So we accept to not respected LSP here.
"""
...