Ejemplo n.º 1
0
def heat_wave_frequency(
    tasmin,
    tasmax,
    thresh_tasmin="22.0 degC",
    thresh_tasmax="30 degC",
    window=3,
    freq="YS",
):
    # Dev note : we should decide if it is deg K or C
    r"""Heat wave frequency

    Number of heat waves over a given period. A heat wave is defined as an event
    where the minimum and maximum daily temperature both exceeds specific thresholds
    over a minimum number of days.

    Parameters
    ----------

    tasmin : xarrray.DataArray
      Minimum daily temperature [℃] or [K]
    tasmax : xarrray.DataArray
      Maximum daily temperature [℃] or [K]
    thresh_tasmin : str
      The minimum temperature threshold needed to trigger a heatwave event [℃] or [K]. Default : '22 degC'
    thresh_tasmax : str
      The maximum temperature threshold needed to trigger a heatwave event [℃] or [K]. Default : '30 degC'
    window : int
      Minimum number of days with temperatures above thresholds to qualify as a heatwave.
    freq : str, optional
      Resampling frequency

    Returns
    -------
    xarray.DataArray
      Number of heatwave at the wanted frequency

    Notes
    -----
    The thresholds of 22° and 25°C for night temperatures and 30° and 35°C for day temperatures were selected by
    Health Canada professionals, following a temperature–mortality analysis. These absolute temperature thresholds
    characterize the occurrence of hot weather events that can result in adverse health outcomes for Canadian
    communities (Casati et al., 2013).

    In Robinson (2001), the parameters would be `thresh_tasmin=27.22, thresh_tasmax=39.44, window=2` (81F, 103F).

    References
    ----------
    Casati, B., A. Yagouti, and D. Chaumont, 2013: Regional Climate Projections of Extreme Heat Events in Nine Pilot
    Canadian Communities for Public Health Planning. J. Appl. Meteor. Climatol., 52, 2669–2698,
    https://doi.org/10.1175/JAMC-D-12-0341.1

    Robinson, P.J., 2001: On the Definition of a Heat Wave. J. Appl. Meteor., 40, 762–775,
    https://doi.org/10.1175/1520-0450(2001)040<0762:OTDOAH>2.0.CO;2
    """
    thresh_tasmax = utils.convert_units_to(thresh_tasmax, tasmax)
    thresh_tasmin = utils.convert_units_to(thresh_tasmin, tasmin)

    cond = (tasmin > thresh_tasmin) & (tasmax > thresh_tasmax)
    group = cond.resample(time=freq)
    return group.apply(rl.windowed_run_events, window=window, dim="time")
Ejemplo n.º 2
0
def sea_ice_area(sic, area, thresh="15 pct"):
    """Return the total sea ice area.

    Sea ice area measures the total sea ice covered area where sea ice concentration is above a threshold,
    usually set to 15%.

    Parameters
    ----------
    sic : xarray.DataArray
      Sea ice concentration [0,1].
    area : xarray.DataArray
      Grid cell area [m²]
    thresh : str
      Minimum sea ice concentration for a grid cell to contribute to the sea ice extent.

    Returns
    -------
    Sea ice area [m²].

    Notes
    -----
    To compute sea ice area over a subregion, first mask or subset the input sea ice concentration data.

    References
    ----------
    `What is the difference between sea ice area and extent
    <https://nsidc.org/arcticseaicenews/faq/#area_extent>`_

    """
    t = utils.convert_units_to(thresh, sic)
    factor = utils.convert_units_to("100 pct", sic)
    out = xarray.dot(sic.where(sic >= t, 0), area) / factor
    out.attrs["units"] = area.units
    return out
Ejemplo n.º 3
0
def rain_on_frozen_ground_days(
    pr: xarray.DataArray,
    tas: xarray.DataArray,
    thresh: str = "1 mm/d",
    freq: str = "YS",
) -> xarray.DataArray:
    """Number of rain on frozen ground events

    Number of days with rain above a threshold after a series of seven days below freezing temperature.
    Precipitation is assumed to be rain when the temperature is above 0℃.

    Parameters
    ----------
    pr : xarray.DataArray
      Mean daily precipitation flux [Kg m-2 s-1] or [mm]
    tas : xarray.DataArray
      Mean daily temperature [℃] or [K]
    thresh : str
      Precipitation threshold to consider a day as a rain event. Default : '1 mm/d'
    freq : str
      Resampling frequency; Defaults to "YS".

    Returns
    -------
    xarray.DataArray
      The number of rain on frozen ground events per period [days]

    Notes
    -----
    Let :math:`PR_i` be the mean daily precipitation and :math:`TG_i` be the mean daily temperature of day :math:`i`.
    Then for a period :math:`j`, rain on frozen grounds days are counted where:

    .. math::

        PR_{i} > Threshold [mm]

    and where

    .. math::

        TG_{i} ≤ 0℃

    is true for continuous periods where :math:`i ≥ 7`

    """
    t = utils.convert_units_to(thresh, pr)
    frz = utils.convert_units_to("0 C", tas)

    def func(x, axis):
        """Check that temperature conditions are below 0 for seven days and above after."""
        frozen = x == np.array([0, 0, 0, 0, 0, 0, 0, 1], bool)
        return frozen.all(axis=axis)

    tcond = (tas > frz).rolling(time=8).reduce(func, allow_lazy=True)
    pcond = pr > t

    return (tcond * pcond * 1).resample(time=freq).sum(dim="time")
Ejemplo n.º 4
0
def daily_freezethaw_cycles(
    tasmax: xarray.DataArray,
    tasmin: xarray.DataArray,
    thresh_tasmax: str = "UNSET 0 degC",
    thresh_tasmin: str = "UNSET 0 degC",
    freq: str = "YS",
) -> xarray.DataArray:
    r"""Number of days with a diurnal freeze-thaw cycle

    The number of days where Tmax > thresh_tasmax and Tmin <= thresh_tasmin.

    Parameters
    ----------
    tasmax : xarray.DataArray
      Maximum daily temperature [℃] or [K]
    tasmin : xarray.DataArray
      Minimum daily temperature values [℃] or [K]
    thresh_tasmax : str
      The temperature threshold needed to trigger a thaw event [℃] or [K]. Default : '0 degC'
    thresh_tasmin : str
      The temperature threshold needed to trigger a freeze event [℃] or [K]. Default : '0 degC'
    freq : str
      Resampling frequency; Defaults to "YS".

    Returns
    -------
    xarray.DataArray
      Number of days with a diurnal freeze-thaw cycle

    Notes
    -----
    Let :math:`TX_{i}` be the maximum temperature at day :math:`i` and :math:`TN_{i}` be
    the daily minimum temperature at day :math:`i`. Then the number of freeze thaw cycles
    during period :math:`\phi` is given by :

    .. math::

        \sum_{i \in \phi} [ TX_{i} > 0℃ ] [ TN_{i} <  0℃ ]

    where :math:`[P]` is 1 if :math:`P` is true, and 0 if false.
    """
    if thresh_tasmax.startswith("UNSET ") or thresh_tasmin.startswith("UNSET"):
        thresh_tasmax, thresh_tasmin = (
            thresh_tasmax.replace("UNSET ", ""),
            thresh_tasmin.replace("UNSET ", ""),
        )

    thaw_threshold = utils.convert_units_to(thresh_tasmax, tasmax)
    freeze_threshold = utils.convert_units_to(thresh_tasmin, tasmin)

    ft = (tasmin <= freeze_threshold) * (tasmax > thaw_threshold) * 1
    out = ft.resample(time=freq).sum(dim="time")

    return out
Ejemplo n.º 5
0
def tx_tn_days_above(
    tasmin: xarray.DataArray,
    tasmax: xarray.DataArray,
    thresh_tasmin: str = "22 degC",
    thresh_tasmax: str = "30 degC",
    freq: str = "YS",
) -> xarray.DataArray:
    r"""Number of days with both hot maximum and minimum daily temperatures.

    The number of days per period with tasmin above a threshold and tasmax above another threshold.

    Parameters
    ----------
    tasmin : xarray.DataArray
      Minimum daily temperature [℃] or [K]
    tasmax : xarray.DataArray
      Maximum daily temperature [℃] or [K]
    thresh_tasmin : str
      Threshold temperature for tasmin on which to base evaluation [℃] or [K]. Default : '22 degC'
    thresh_tasmax : str
      Threshold temperature for tasmax on which to base evaluation [℃] or [K]. Default : '30 degC'
    freq : str
      Resampling frequency; Defaults to "YS".

    Returns
    -------
    xarray.DataArray
      the number of days with tasmin > thresh_tasmin and
      tasmax > thresh_tasamax per period


    Notes
    -----
    Let :math:`TX_{ij}` be the maximum temperature at day :math:`i` of period :math:`j`, :math:`TN_{ij}`
    the daily minimum temperature at day :math:`i` of period :math:`j`, :math:`TX_{thresh}` the threshold for maximum
    daily temperature, and :math:`TN_{thresh}` the threshold for minimum daily temperature. Then counted is the number
    of days where:

    .. math::

        TX_{ij} > TX_{thresh} [℃]

    and where:

    .. math::

        TN_{ij} > TN_{thresh} [℃]

    """

    thresh_tasmax = utils.convert_units_to(thresh_tasmax, tasmax)
    thresh_tasmin = utils.convert_units_to(thresh_tasmin, tasmin)
    events = ((tasmin > thresh_tasmin) & (tasmax > thresh_tasmax)) * 1
    return events.resample(time=freq).sum(dim="time")
Ejemplo n.º 6
0
def days_over_precip_thresh(pr, per, thresh="1 mm/day", freq="YS"):
    r"""Number of wet days with daily precipitation over a given percentile.

    Number of days over period where the precipitation is above a threshold defining wet days and above a given
    percentile for that day.

    Parameters
    ----------
    pr : xarray.DataArray
      Mean daily precipitation flux [Kg m-2 s-1] or [mm/day]
    per : xarray.DataArray
      Daily percentile of wet day precipitation flux [Kg m-2 s-1] or [mm/day]
    thresh : str
       Precipitation value over which a day is considered wet [Kg m-2 s-1] or [mm/day].
    freq : str, optional
      Resampling frequency

    Returns
    -------
    xarray.DataArray
      Count of days with daily precipitation above the given percentile [days]

    Notes
    -----
    The percentile should be computed for a 5 day window centered on each calendar day for a reference period.

    Example
    -------
    >>> p75 = percentile_doy(historical_pr, per=0.75)
    >>> r75p = days_over_precip_thresh(pr, p75)
    """
    if "dayofyear" not in per.coords.keys():
        raise AttributeError("percentile should have dayofyear coordinates.")

    per = utils.convert_units_to(per, pr)
    thresh = utils.convert_units_to(thresh, pr)

    per = utils.adjust_doy_calendar(per, pr)
    mper = np.maximum(per, thresh)

    # create array of percentile with pr shape and coords
    tp = xr.full_like(pr, np.nan)
    doy = tp.time.dt.dayofyear.values
    tp.data = mper.sel(dayofyear=doy)

    # compute the days where precip is both over the wet day threshold and the percentile threshold.
    over = pr > tp

    return over.resample(time=freq).sum(dim="time")
Ejemplo n.º 7
0
    def test_deprecation(self, tas_series):
        with pytest.warns(FutureWarning):
            out = utils.convert_units_to(0, units.K)
            assert out == 273.15

            out = utils.convert_units_to(10, units.mm / units.day, context='hydro')
            assert out == 10

        with pytest.warns(FutureWarning):
            tas = tas_series(np.arange(365), start='1/1/2001')
            out = ind.tx_days_above(tas, 30)
            out1 = ind.tx_days_above(tas, '30 degC')
            out2 = ind.tx_days_above(tas, '303.15 K')
            np.testing.assert_array_equal(out, out1)
            np.testing.assert_array_equal(out, out2)
Ejemplo n.º 8
0
def precip_accumulation(
    pr: xarray.DataArray,
    tas: xarray.DataArray = None,
    phase: Optional[str] = None,
    freq: str = "YS",
) -> xarray.DataArray:
    r"""Accumulated total (liquid and/or solid) precipitation.

    Resample the original daily mean precipitation flux and accumulate over each period.
    If the daily mean temperature is provided, the phase keyword can be used to only sum precipitation of a certain phase.
    When the mean temperature is over 0 degC, precipitatio is assumed to be liquid rain and snow otherwise.

    Parameters
    ----------
    pr : xarray.DataArray
      Mean daily precipitation flux [Kg m-2 s-1] or [mm].
    tas : xarray.DataArray, optional
      Mean daily temperature [℃] or [K]
    phase : str, optional,
      Which phase to consider, "liquid" or "solid", if None (default), both are considered.
    freq : str
      Resampling frequency as defined in
      http://pandas.pydata.org/pandas-docs/stable/timeseries.html#resampling. Defaults to "YS"

    Returns
    -------
    xarray.DataArray
      The total daily precipitation at the given time frequency for the given phase.

    Notes
    -----
    Let :math:`PR_i` be the mean daily precipitation of day :math:`i`, then for a period :math:`j` starting at
    day :math:`a` and finishing on day :math:`b`:

    .. math::

       PR_{ij} = \sum_{i=a}^{b} PR_i

    If `phase` is "liquid", only times where the daily mean temperature :math:`T_i` is above or equal to 0 °C are considered, inversely for "solid".

    Examples
    --------
    The following would compute for each grid cell of file `pr_day.nc` the total
    precipitation at the seasonal frequency, ie DJF, MAM, JJA, SON, DJF, etc.:

    >>> import xarray as xr
    >>> pr_day = xr.open_dataset('pr_day.nc').pr
    >>> prcp_tot_seasonal = precip_accumulation(pr_day, freq="QS-DEC")
    """

    if phase in ["liquid", "solid"]:
        frz = utils.convert_units_to("0 degC", tas)

        if phase == "liquid":
            pr = pr.where(tas >= frz, 0)
        elif phase == "solid":
            pr = pr.where(tas < frz, 0)

    out = pr.resample(time=freq).sum(dim="time", keep_attrs=True)
    return utils.pint_multiply(out, 1 * units.day, "mm")
Ejemplo n.º 9
0
def wetdays(pr, thresh="1.0 mm/day", freq="YS"):
    r"""Wet days

    Return the total number of days during period with precipitation over threshold.

    Parameters
    ----------
    pr : xarray.DataArray
      Daily precipitation [mm]
    thresh : str
      Precipitation value over which a day is considered wet. Default: '1 mm/day'.
    freq : str, optional
      Resampling frequency defining the periods
      defined in http://pandas.pydata.org/pandas-docs/stable/timeseries.html#resampling.

    Returns
    -------
    xarray.DataArray
      The number of wet days for each period [day]

    Examples
    --------
    The following would compute for each grid cell of file `pr.day.nc` the number days
    with precipitation over 5 mm at the seasonal frequency, ie DJF, MAM, JJA, SON, DJF, etc.:

    >>> pr = xr.open_dataset('pr.day.nc')
    >>> wd = wetdays(pr, pr_min = 5., freq="QS-DEC")
    """
    thresh = utils.convert_units_to(thresh, pr, "hydro")

    wd = (pr >= thresh) * 1
    return wd.resample(time=freq).sum(dim="time")
Ejemplo n.º 10
0
def tx_days_above(tasmax, thresh="25.0 degC", freq="YS"):
    r"""Number of summer days

    Number of days where daily maximum temperature exceed a threshold.

    Parameters
    ----------
    tasmax : xarray.DataArray
      Maximum daily temperature [℃] or [K]
    thresh : str
      Threshold temperature on which to base evaluation [℃] or [K]. Default: '25 degC'.
    freq : str, optional
      Resampling frequency

    Returns
    -------
    xarray.DataArray
      Number of summer days.

    Notes
    -----
    Let :math:`TX_{ij}` be the daily maximum temperature at day :math:`i` of period :math:`j`. Then
    counted is the number of days where:

    .. math::

        TX_{ij} > Threshold [℃]
    """
    thresh = utils.convert_units_to(thresh, tasmax)
    f = (tasmax > (thresh)) * 1
    return f.resample(time=freq).sum(dim="time")
Ejemplo n.º 11
0
def growing_degree_days(tas, thresh="4.0 degC", freq="YS"):
    r"""Growing degree-days over threshold temperature value [℃].

    The sum of degree-days over the threshold temperature.

    Parameters
    ---------
    tas : xarray.DataArray
      Mean daily temperature [℃] or [K]
    thresh : str
      Threshold temperature on which to base evaluation [℃] or [K]. Default: '4.0 degC'.
    freq : str, optional
      Resampling frequency

    Returns
    -------
    xarray.DataArray
      The sum of growing degree-days above 4℃

    Notes
    -----
    Let :math:`TG_{ij}` be the daily mean temperature at day :math:`i` of period :math:`j`. Then the
    growing degree days are:

    .. math::

        GD4_j = \sum_{i=1}^I (TG_{ij}-{4} | TG_{ij} > {4}℃)
    """
    thresh = utils.convert_units_to(thresh, tas)
    return (tas.pipe(lambda x: x - thresh).clip(min=0).resample(time=freq).sum(
        dim="time"))
Ejemplo n.º 12
0
def cooling_degree_days(tas, thresh="18 degC", freq="YS"):
    r"""Cooling degree days

    Sum of degree days above the temperature threshold at which spaces are cooled.

    Parameters
    ----------
    tas : xarray.DataArray
      Mean daily temperature [℃] or [K]
    thresh : str
      Temperature threshold above which air is cooled. Default : '18 degC'
    freq : str, optional
      Resampling frequency

    Returns
    -------
    xarray.DataArray
      Cooling degree days

    Notes
    -----
    Let :math:`x_i` be the daily mean temperature at day :math:`i`. Then the cooling degree days above
    temperature threshold :math:`thresh` over period :math:`\phi` is given by:

    .. math::

        \sum_{i \in \phi} (x_{i}-{thresh} [x_i > thresh]

    where :math:`[P]` is 1 if :math:`P` is true, and 0 if false.
    """
    thresh = utils.convert_units_to(thresh, tas)

    return (tas.pipe(lambda x: x - thresh).clip(min=0).resample(time=freq).sum(
        dim="time"))
Ejemplo n.º 13
0
def heating_degree_days(tas, thresh="17.0 degC", freq="YS"):
    r"""Heating degree days

    Sum of degree days below the temperature threshold at which spaces are heated.

    Parameters
    ----------
    tas : xarray.DataArray
      Mean daily temperature [℃] or [K]
    thresh : str
      Threshold temperature on which to base evaluation [℃] or [K]. Default: '17.0 degC'.
    freq : str, optional
      Resampling frequency

    Returns
    -------
    xarray.DataArray
      Heating degree days index.

    Notes
    -----
    Let :math:`TG_{ij}` be the daily mean temperature at day :math:`i` of period :math:`j`. Then the
    heating degree days are:

    .. math::

        HD17_j = \sum_{i=1}^{I} (17℃ - TG_{ij})
    """
    thresh = utils.convert_units_to(thresh, tas)

    return tas.pipe(lambda x: thresh - x).clip(0).resample(time=freq).sum(
        dim="time")
Ejemplo n.º 14
0
def heat_wave_index(tasmax, thresh="25.0 degC", window=5, freq="YS"):
    r"""Heat wave index.

    Number of days that are part of a heatwave, defined as five or more consecutive days over 25℃.

    Parameters
    ----------
    tasmax : xarrray.DataArray
      Maximum daily temperature [℃] or [K]
    thresh : str
      Threshold temperature on which to designate a heatwave [℃] or [K]. Default: '25.0 degC'.
    window : int
      Minimum number of days with temperature above threshold to qualify as a heatwave.
    freq : str, optional
      Resampling frequency

    Returns
    -------
    DataArray
      Heat wave index.
    """
    thresh = utils.convert_units_to(thresh, tasmax)
    over = tasmax > thresh
    group = over.resample(time=freq)

    return group.apply(rl.windowed_run_count, window=window, dim="time")
Ejemplo n.º 15
0
def tn_days_below(tasmin, thresh="-10.0 degC", freq="YS"):
    r"""Number of days with tmin below a threshold in

    Number of days where daily minimum temperature is below a threshold.

    Parameters
    ----------
    tasmin : xarray.DataArray
      Minimum daily temperature [℃] or [K]
    thresh : str
      Threshold temperature on which to base evaluation [℃] or [K] . Default: '-10 degC'.
    freq : str, optional
      Resampling frequency

    Returns
    -------
    xarray.DataArray
      Number of days Tmin < threshold.

    Notes
    -----
    Let :math:`TN_{ij}` be the daily minimum temperature at day :math:`i` of period :math:`j`. Then
    counted is the number of days where:

    .. math::

        TX_{ij} < Threshold [℃]
    """
    thresh = utils.convert_units_to(thresh, tasmin)
    f1 = utils.threshold_count(tasmin, "<", thresh, freq)
    return f1
Ejemplo n.º 16
0
def warm_day_frequency(tasmax, thresh="30 degC", freq="YS"):
    r"""Frequency of extreme warm days

    Return the number of days with tasmax > thresh per period

    Parameters
    ----------
    tasmax : xarray.DataArray
      Mean daily temperature [℃] or [K]
    thresh : str
      Threshold temperature on which to base evaluation [℃] or [K]. Default : '30 degC'
    freq : str, optional
      Resampling frequency

    Returns
    -------
    xarray.DataArray
      Number of days exceeding threshold.

    Notes:
    Let :math:`TX_{ij}` be the daily maximum temperature at day :math:`i` of period :math:`j`. Then
    counted is the number of days where:

    .. math::

        TN_{ij} > Threshold [℃]

    """
    thresh = utils.convert_units_to(thresh, tasmax)
    events = (tasmax > thresh) * 1
    return events.resample(time=freq).sum(dim="time")
Ejemplo n.º 17
0
def daily_freezethaw_cycles(tasmax, tasmin, freq="YS"):
    r"""Number of days with a diurnal freeze-thaw cycle

    The number of days where Tmax > 0℃ and Tmin < 0℃.

    Parameters
    ----------
    tasmax : xarray.DataArray
      Maximum daily temperature [℃] or [K]
    tasmin : xarray.DataArray
      Minimum daily temperature values [℃] or [K]
    freq : str
      Resampling frequency

    Returns
    -------
    xarray.DataArray
      Number of days with a diurnal freeze-thaw cycle

    Notes
    -----
    Let :math:`TX_{i}` be the maximum temperature at day :math:`i` and :math:`TN_{i}` be
    the daily minimum temperature at day :math:`i`. Then the number of freeze thaw cycles
    during period :math:`\phi` is given by :

    .. math::

        \sum_{i \in \phi} [ TX_{i} > 0℃ ] [ TN_{i} <  0℃ ]

    where :math:`[P]` is 1 if :math:`P` is true, and 0 if false.
    """
    frz = utils.convert_units_to("0 degC", tasmax)
    ft = (tasmin < frz) * (tasmax > frz) * 1
    out = ft.resample(time=freq).sum(dim="time")
    return out
Ejemplo n.º 18
0
def warm_night_frequency(tasmin, thresh='22 degC', freq='YS'):
    r"""Frequency of extreme warm nights

    Return the number of days with tasmin > thresh per period

    Parameters
    ----------
    tasmin : xarray.DataArray
      Minimum daily temperature [℃] or [K]
    thresh : str
      Threshold temperature on which to base evaluation [℃] or [K]. Default : '22 degC'
    freq : str, optional
      Resampling frequency

    Returns
    -------
    xarray.DataArray
      The number of days with tasmin > thresh per period
    """
    thresh = utils.convert_units_to(
        thresh,
        tasmin,
    )
    events = (tasmin > thresh) * 1
    return events.resample(time=freq).sum(dim='time')
Ejemplo n.º 19
0
def tropical_nights(tasmin, thresh="20.0 degC", freq="YS"):
    r"""Tropical nights

    The number of days with minimum daily temperature above threshold.

    Parameters
    ----------
    tasmin : xarray.DataArray
      Minimum daily temperature [℃] or [K]
    thresh : str
      Threshold temperature on which to base evaluation [℃] or [K]. Default: '20 degC'.
    freq : str, optional
      Resampling frequency

    Returns
    -------
    xarray.DataArray
      Number of days with minimum daily temperature above threshold.

    Notes
    -----
    Let :math:`TN_{ij}` be the daily minimum temperature at day :math:`i` of period :math:`j`. Then
    counted is the number of days where:

    .. math::

        TN_{ij} > Threshold [℃]
    """
    thresh = utils.convert_units_to(thresh, tasmin)
    return (tasmin.pipe(lambda x: (tasmin > thresh) * 1).resample(
        time=freq).sum(dim="time"))
Ejemplo n.º 20
0
def fraction_over_precip_thresh(pr, per, thresh="1 mm/day", freq="YS"):
    r"""Fraction of precipitation due to wet days with daily precipitation over a given percentile.

    Percentage of the total precipitation over period occurring in days where the precipitation is above a threshold
    defining wet days and above a given percentile for that day.

    Parameters
    ----------
    pr : xarray.DataArray
      Mean daily precipitation flux [Kg m-2 s-1] or [mm/day]
    per : xarray.DataArray
      Daily percentile of wet day precipitation flux [Kg m-2 s-1] or [mm/day]
    thresh : str
       Precipitation value over which a day is considered wet [Kg m-2 s-1] or [mm/day].
    freq : str, optional
      Resampling frequency

    Returns
    -------
    xarray.DataArray
      Fraction of precipitation over threshold during wet days days.

    Notes
    -----
    The percentile should be computed for a 5 day window centered on each calendar day for a reference period.
    """
    if "dayofyear" not in per.coords.keys():
        raise AttributeError("percentile should have dayofyear coordinates.")

    per = utils.convert_units_to(per, pr)
    thresh = utils.convert_units_to(thresh, pr)

    per = utils.adjust_doy_calendar(per, pr)
    mper = np.maximum(per, thresh)

    # create array of percentile with pr shape and coords
    tp = xr.full_like(pr, np.nan)
    doy = tp.time.dt.dayofyear.values
    tp.data = mper.sel(dayofyear=doy)

    # Total precip during wet days over period
    total = pr.where(pr > thresh).resample(time=freq).sum(dim="time")

    # compute the days where precip is both over the wet day threshold and the percentile threshold.
    over = pr.where(pr > tp).resample(time=freq).sum(dim="time")

    return over / total
Ejemplo n.º 21
0
def days_over_precip_thresh(
    pr: xarray.DataArray,
    per: xarray.DataArray,
    thresh: str = "1 mm/day",
    freq: str = "YS",
) -> xarray.DataArray:
    r"""Number of wet days with daily precipitation over a given percentile.

    Number of days over period where the precipitation is above a threshold defining wet days and above a given
    percentile for that day.

    Parameters
    ----------
    pr : xarray.DataArray
      Mean daily precipitation flux [Kg m-2 s-1] or [mm/day]
    per : xarray.DataArray
      Daily percentile of wet day precipitation flux [Kg m-2 s-1] or [mm/day].
    thresh : str
       Precipitation value over which a day is considered wet [Kg m-2 s-1] or [mm/day].
    freq : str
      Resampling frequency; Defaults to "YS".

    Returns
    -------
    xarray.DataArray
      Count of days with daily precipitation above the given percentile [days]

    Example
    -------
    >>> import xarray as xr
    >>> import xclim
    >>> pr = xr.open_dataset("precipitation_data.nc").pr
    >>> p75 = pr.quantile(.75, dim="time", keep_attrs=True)
    >>> r75p = xclim.indices.days_over_precip_thresh(pr, p75)
    """
    per = utils.convert_units_to(per, pr)
    thresh = utils.convert_units_to(thresh, pr)

    tp = np.maximum(per, thresh)
    if "dayofyear" in per.coords:
        # Create time series out of doy values.
        tp = utils.resample_doy(tp, pr)

    # Compute the days where precip is both over the wet day threshold and the percentile threshold.
    over = pr > tp

    return over.resample(time=freq).sum(dim="time")
Ejemplo n.º 22
0
def cold_spell_duration_index(tasmin: xarray.DataArray,
                              tn10: xarray.DataArray,
                              window: int = 6,
                              freq: str = "YS") -> xarray.DataArray:
    r"""Cold spell duration index

    Number of days with at least six consecutive days where the daily minimum temperature is below the 10th
    percentile.

    Parameters
    ----------
    tasmin : xarray.DataArray
      Minimum daily temperature.
    tn10 : xarray.DataArray
      10th percentile of daily minimum temperature with `dayofyear` coordinate.
    window : int
      Minimum number of days with temperature below threshold to qualify as a cold spell. Default: 6.
    freq : str
      Resampling frequency; Defaults to "YS".

    Returns
    -------
    xarray.DataArray
      Count of days with at least six consecutive days where the daily minimum temperature is below the 10th
      percentile [days].

    Notes
    -----
    Let :math:`TN_i` be the minimum daily temperature for the day of the year :math:`i` and :math:`TN10_i` the 10th
    percentile of the minimum daily temperature over the 1961-1990 period for day of the year :math:`i`, the cold spell
    duration index over period :math:`\phi` is defined as:

    .. math::

       \sum_{i \in \phi} \prod_{j=i}^{i+6} \left[ TN_j < TN10_j \right]

    where :math:`[P]` is 1 if :math:`P` is true, and 0 if false.

    References
    ----------
    From the Expert Team on Climate Change Detection, Monitoring and Indices (ETCCDMI).

    Example
    -------
    >>> import xclim.utils as xcu
    >>> tn10 = xcu.percentile_doy(historical_tasmin, per=.1)
    >>> cold_spell_duration_index(reference_tasmin, tn10)
    """
    tn10 = utils.convert_units_to(tn10, tasmin)

    # Create time series out of doy values.
    thresh = utils.resample_doy(tn10, tasmin)

    below = tasmin < thresh

    return below.resample(time=freq).apply(rl.windowed_run_count,
                                           window=window,
                                           dim="time")
Ejemplo n.º 23
0
def heat_wave_total_length(
    tasmin: xarray.DataArray,
    tasmax: xarray.DataArray,
    thresh_tasmin: str = "22.0 degC",
    thresh_tasmax: str = "30 degC",
    window: int = 3,
    freq: str = "YS",
) -> xarray.DataArray:
    # Dev note : we should decide if it is deg K or C
    r"""Heat wave total length

    Total length of heat waves over a given period. A heat wave is defined as an event
    where the minimum and maximum daily temperature both exceeds specific thresholds
    over a minimum number of days. This the sum of all days in such events.

    Parameters
    ----------
    tasmin : xarray.DataArray
      Minimum daily temperature [℃] or [K]
    tasmax : xarray.DataArray
      Maximum daily temperature [℃] or [K]
    thresh_tasmin : str
      The minimum temperature threshold needed to trigger a heatwave event [℃] or [K]. Default : '22 degC'
    thresh_tasmax : str
      The maximum temperature threshold needed to trigger a heatwave event [℃] or [K]. Default : '30 degC'
    window : int
      Minimum number of days with temperatures above thresholds to qualify as a heatwave.
    freq : str
      Resampling frequency; Defaults to "YS".

    Returns
    -------
    xarray.DataArray
      Total length of heatwave at the wanted frequency

    Notes
    -----
    See notes and references of `heat_wave_max_length`
    """
    thresh_tasmax = utils.convert_units_to(thresh_tasmax, tasmax)
    thresh_tasmin = utils.convert_units_to(thresh_tasmin, tasmin)

    cond = (tasmin > thresh_tasmin) & (tasmax > thresh_tasmax)
    group = cond.resample(time=freq)
    return group.apply(rl.windowed_run_count, args=(window, ), dim="time")
Ejemplo n.º 24
0
def fraction_over_precip_thresh(
    pr: xarray.DataArray,
    per: xarray.DataArray,
    thresh: str = "1 mm/day",
    freq: str = "YS",
) -> xarray.DataArray:
    r"""Fraction of precipitation due to wet days with daily precipitation over a given percentile.

    Percentage of the total precipitation over period occurring in days where the precipitation is above a threshold
    defining wet days and above a given percentile for that day.

    Parameters
    ----------
    pr : xarray.DataArray
      Mean daily precipitation flux [Kg m-2 s-1] or [mm/day].
    per : xarray.DataArray
      Daily percentile of wet day precipitation flux [Kg m-2 s-1] or [mm/day].
    thresh : str
       Precipitation value over which a day is considered wet [Kg m-2 s-1] or [mm/day].
    freq : str
      Resampling frequency; Defaults to "YS".

    Returns
    -------
    xarray.DataArray
      Fraction of precipitation over threshold during wet days days.

    """
    per = utils.convert_units_to(per, pr)
    thresh = utils.convert_units_to(thresh, pr)

    tp = np.maximum(per, thresh)
    if "dayofyear" in per.coords:
        # Create time series out of doy values.
        tp = utils.resample_doy(tp, pr)

    # Total precip during wet days over period
    total = pr.where(pr > thresh).resample(time=freq).sum(dim="time")

    # Compute the days where precip is both over the wet day threshold and the percentile threshold.
    over = pr.where(pr > tp).resample(time=freq).sum(dim="time")

    return over / total
Ejemplo n.º 25
0
def daily_pr_intensity(pr, thresh="1 mm/day", freq="YS"):
    r"""Average daily precipitation intensity

    Return the average precipitation over wet days.

    Parameters
    ----------
    pr : xarray.DataArray
      Daily precipitation [mm/d or kg/m²/s]
    thresh : str
      precipitation value over which a day is considered wet. Default : '1 mm/day'
    freq : str
      Resampling frequency defining the periods defined in
      http://pandas.pydata.org/pandas-docs/stable/timeseries.html#resampling; Defaults to "YS".

    Returns
    -------
    xarray.DataArray
      The average precipitation over wet days for each period

    Notes
    -----
    Let :math:`\mathbf{p} = p_0, p_1, \ldots, p_n` be the daily precipitation and :math:`thresh` be the precipitation
    threshold defining wet days. Then the daily precipitation intensity is defined as

    .. math::

       \frac{\sum_{i=0}^n p_i [p_i \leq thresh]}{\sum_{i=0}^n [p_i \leq thresh]}

    where :math:`[P]` is 1 if :math:`P` is true, and 0 if false.

    Examples
    --------
    The following would compute for each grid cell of file `pr.day.nc` the average
    precipitation fallen over days with precipitation >= 5 mm at seasonal
    frequency, ie DJF, MAM, JJA, SON, DJF, etc.:

    >>> import xarray as xr
    >>> import xclim.indices
    >>> pr = xr.open_dataset("pr_day.nc").pr
    >>> daily_int = xclim.indices.daily_pr_intensity(pr, thresh='5 mm/day', freq="QS-DEC")
    """
    t = utils.convert_units_to(thresh, pr, "hydro")

    # put pr=0 for non wet-days
    pr_wd = xarray.where(pr >= t, pr, 0)
    pr_wd.attrs["units"] = pr.units

    # sum over wanted period
    s = pr_wd.resample(time=freq).sum(dim="time", keep_attrs=True)
    sd = utils.pint_multiply(s, 1 * units.day, "mm")

    # get number of wetdays over period
    wd = wetdays(pr, thresh=thresh, freq=freq)
    return sd / wd
Ejemplo n.º 26
0
    def test_deprecation(self, tas_series):
        with pytest.warns(FutureWarning):
            out = utils.convert_units_to(0, units.K)
            assert out == 273.15

        with pytest.warns(FutureWarning):
            out = utils.convert_units_to(10,
                                         units.mm / units.day,
                                         context="hydro")
            assert out == 10

        with pytest.warns(FutureWarning):
            tas = tas_series(np.arange(365), start="1/1/2001")
            out = indices.tx_days_above(tas, 30)

        out1 = indices.tx_days_above(tas, "30 degC")
        out2 = indices.tx_days_above(tas, "303.15 K")
        np.testing.assert_array_equal(out, out1)
        np.testing.assert_array_equal(out, out2)
        assert out1.name == tas.name
Ejemplo n.º 27
0
def tx10p(tasmax, t10, freq="YS"):
    r"""Number of days with daily maximum temperature below the 10th percentile.

    Number of days with daily maximum temperature below the 10th percentile.

    Parameters
    ----------
    tasmax : xarray.DataArray
      Maximum daily temperature [℃] or [K]
    t10 : xarray.DataArray
      10th percentile of daily maximum temperature [℃] or [K]
    freq : str, optional
      Resampling frequency

    Returns
    -------
    xarray.DataArray
      Count of days with daily maximum temperature below the 10th percentile [days]

    Notes
    -----
    The 10th percentile should be computed for a 5 day window centered on each calendar day for a reference period.

    Example
    -------
    >>> t10 = percentile_doy(historical_tas, per=0.1)
    >>> cold_days = tg10p(tas, t10)
    """
    if "dayofyear" not in t10.coords.keys():
        raise AttributeError("t10 should have dayofyear coordinates.")

    t10 = utils.convert_units_to(t10, tasmax)

    # adjustment of t10 to tas doy range
    t10 = utils.adjust_doy_calendar(t10, tasmax)

    # create array of percentile with tas shape and coords
    thresh = xr.full_like(tasmax, np.nan)
    doy = thresh.time.dt.dayofyear.values
    thresh.data = t10.sel(dayofyear=doy)

    # compute the cold days
    below = tasmax < thresh

    return below.resample(time=freq).sum(dim="time")
Ejemplo n.º 28
0
def tg90p(tas, t90, freq='YS'):
    r"""Number of days with daily mean temperature over the 90th percentile.

    Number of days with daily mean temperature over the 90th percentile.

    Parameters
    ----------
    tas : xarray.DataArray
      Mean daily temperature [℃] or [K]
    t90 : xarray.DataArray
      90th percentile of daily mean temperature [℃] or [K]
    freq : str, optional
      Resampling frequency

    Returns
    -------
    xarray.DataArray
      Count of days with daily mean temperature below the 10th percentile [days]

    Notes
    -----
    The 90th percentile should be computed for a 5 day window centered on each calendar day for a reference period.

    Example
    -------
    >>> t90 = percentile_doy(historical_tas, per=0.9)
    >>> hot_days = tg90p(tas, t90)
    """
    if 'dayofyear' not in t90.coords.keys():
        raise AttributeError("t10 should have dayofyear coordinates.")

    t90 = utils.convert_units_to(t90, tas)

    # adjustment of t90 to tas doy range
    t90 = utils.adjust_doy_calendar(t90, tas)

    # create array of percentile with tas shape and coords
    thresh = xr.full_like(tas, np.nan)
    doy = thresh.time.dt.dayofyear.values
    thresh.data = t90.sel(dayofyear=doy)

    # compute the cold days
    over = (tas > thresh)

    return over.resample(time=freq).sum(dim='time')
Ejemplo n.º 29
0
def tn10p(tasmin: xarray.DataArray,
          t10: xarray.DataArray,
          freq: str = "YS") -> xarray.DataArray:
    r"""Number of days with daily minimum temperature below the 10th percentile.

    Number of days with daily minimum temperature below the 10th percentile.

    Parameters
    ----------

    tasmin : xarray.DataArray
      Mean daily temperature [℃] or [K]
    t10 : xarray.DataArray
      10th percentile of daily minimum temperature [℃] or [K]
    freq : str
      Resampling frequency; Defaults to "YS".

    Returns
    -------
    xarray.DataArray
      Count of days with daily minimum temperature below the 10th percentile [days]

    Notes
    -----
    The 10th percentile should be computed for a 5 day window centered on each calendar day for a reference period.

    Example
    -------
    >>> import xarray as xr
    >>> import xclim.utils
    >>> tas = xr.open_dataset("temperature_data.nc").tas
    >>> t10 = xclim.utils.percentile_doy(tas, per=0.1)
    >>> cold_days = tg10p(tas, t10)
    """
    t10 = utils.convert_units_to(t10, tasmin)

    # Create time series out of doy values.
    thresh = utils.resample_doy(t10, tasmin)

    # Identify the days below the 10th percentile
    below = tasmin < thresh

    return below.resample(time=freq).sum(dim="time")
Ejemplo n.º 30
0
def freshet_start(
    tas: xarray.DataArray, thresh: str = "0 degC", window: int = 5, freq: str = "YS"
):
    r"""First day consistently exceeding threshold temperature.

    Returns first day of period where a temperature threshold is exceeded
    over a given number of days.

    Parameters
    ----------
    tas : xarray.DataArray
      Mean daily temperature [℃] or [K]
    thresh : str
      Threshold temperature on which to base evaluation [℃] or [K]. Default '0 degC'
    window : int
      Minimum number of days with temperature above threshold needed for evaluation
    freq : str
      Resampling frequency; Defaults to "YS".

    Returns
    -------
    xarray.DataArray
      Day of the year when temperature exceeds threshold over a given number of days for the first time. If there are
      no such day, return np.nan.

    Notes
    -----
    Let :math:`x_i` be the daily mean temperature at day of the year :math:`i` for values of :math:`i` going from 1
    to 365 or 366. The start date of the freshet is given by the smallest index :math:`i` for which

    .. math::

       \prod_{j=i}^{i+w} [x_j > thresh]

    is true, where :math:`w` is the number of days the temperature threshold should be exceeded,  and :math:`[P]` is
    1 if :math:`P` is true, and 0 if false.
    """
    thresh = utils.convert_units_to(thresh, tas)
    over = tas > thresh
    return over.resample(time=freq).map(
        rl.first_run, dim="time", window=window, coord="dayofyear"
    )