def prcptot(pr: xarray.DataArray, input_freq: str = None, freq: str = "YS"): r"""ANUCLIM Accumulated total precipitation. Parameters ---------- pr : xarray.DataArray Total precipitation flux [mm d-1], [mm week-1], [mm month-1] or similar. input_freq : str Input data time frequency - One of 'daily', 'weekly' or 'monthly'. freq : str Resampling frequency; Defaults to "YS". Returns ------- xarray.DataArray Total precipitation [mm]. Notes ----- According to the ANUCLIM user-guide https://fennerschool.anu.edu.au/files/anuclim61.pdf (ch. 6), input values should be at a weekly (or monthly) frequency. However, the xclim.indices implementation here will calculate the result with input data with daily frequency as well. """ if input_freq == "monthly": pr = pint_multiply(pr, 1 * units.month, "mm") elif input_freq == "weekly": pr = pint_multiply(pr, 1 * units.week, "mm") elif input_freq == "daily": pr = pint_multiply(pr, 1 * units.day, "mm") else: raise NotImplementedError( f'Unknown input time frequency "{input_freq}" : input_freq parameter must be ' f'one of "daily", "weekly" or "monthly"') return pr.resample(time=freq).sum(dim="time", keep_attrs=True)
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 = 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 pint_multiply(out, 1 * units.day, "mm")
def prcptot_wetdry_period( pr: xarray.DataArray, *, op: str, src_timestep: str, freq: str = "YS" ) -> xarray.DataArray: r"""ANUCLIM precipitation of the wettest/driest day, week, or month, depending on the time step. Parameters ---------- pr : xarray.DataArray Total precipitation flux [mm d-1], [mm week-1], [mm month-1] or similar. op : str Operation to perform : 'wettest' calculate wettest period ; 'driest' calculate driest period. src_timestep : {'D', 'W', 'M'} Input data time frequency - One of daily, weekly or monthly. freq : str Resampling frequency; Defaults to "YS". Returns ------- xarray.DataArray Total precipitation [mm] of the wettest / driest period. Notes ----- According to the ANUCLIM user-guide https://fennerschool.anu.edu.au/files/anuclim61.pdf (ch. 6), input values should be at a weekly (or monthly) frequency. However, the xclim.indices implementation here will calculate the result with input data with daily frequency as well. As such weekly or monthly input values, if desired, should be calculated prior to calling the function. """ if src_timestep == "M": pr = pint_multiply(pr, 1 * units.month, "mm") elif src_timestep == "W": pr = pint_multiply(pr, 1 * units.week, "mm") elif src_timestep == "D": pr = pint_multiply(pr, 1 * units.day, "mm") else: raise NotImplementedError( f'Unknown input time frequency "{src_timestep}" : src_timestep parameter must be ' f'one of "D", "W" or "M"' ) if op == "wettest": return pr.resample(time=freq).max(dim="time", keep_attrs=True) if op == "driest": return pr.resample(time=freq).min(dim="time", keep_attrs=True) raise NotImplementedError( f'Unknown operation "{op}" ; op parameter but be one of "wettest" or "driest"' )
def daily_pr_intensity(pr: xarray.DataArray, thresh: str = "1 mm/day", freq: str = "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.: >>> from xclim.indices import daily_pr_intensity >>> pr = xr.open_dataset(path_to_pr_file).pr >>> daily_int = daily_pr_intensity(pr, thresh='5 mm/day', freq="QS-DEC") """ t = 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 = pint_multiply(s, 1 * units.day, "mm") # get number of wetdays over period wd = wetdays(pr, thresh=thresh, freq=freq) return sd / wd
def _to_quarter( freq: str, pr: Optional[xarray.DataArray] = None, tas: Optional[xarray.DataArray] = None, ) -> xarray.DataArray: """Convert daily, weekly or monthly time series to quarterly time series according to ANUCLIM specifications.""" if freq.upper().startswith("D"): if tas is not None: tas = tg_mean(tas, freq="7D") if pr is not None: pr = precip_accumulation(pr, freq="7D") pr.attrs["units"] = "mm/week" freq = "W" if freq.upper().startswith("W"): window = 13 u = units.week elif freq.upper().startswith("M"): window = 3 u = units.month else: raise NotImplementedError( f'Unknown input time frequency "{freq}": must be one of "D", "W" or "M".' ) if tas is not None: tas = ensure_chunk_size(tas, time=np.ceil(window / 2)) if pr is not None: pr = ensure_chunk_size(pr, time=np.ceil(window / 2)) with xarray.set_options(keep_attrs=True): if pr is not None: pr = pint_multiply(pr, 1 * u, "mm") out = pr.rolling(time=window, center=False).sum() out.attrs = pr.attrs out.attrs["units"] = "mm" if tas is not None: out = tas.rolling(time=window, center=False).mean(skipna=False) out.attrs = tas.attrs out = ensure_chunk_size(out, time=-1) return out
def max_n_day_precipitation_amount(pr: xarray.DataArray, window: int = 1, freq: str = "YS"): r"""Highest precipitation amount cumulated over a n-day moving window. Calculate the n-day rolling sum of the original daily total precipitation series and determine the maximum value over each period. Parameters ---------- pr : xarray.DataArray Daily precipitation values [Kg m-2 s-1] or [mm] window : int Window size in days. freq : str Resampling frequency; Defaults to "YS" (yearly). Returns ------- xarray.DataArray The highest cumulated n-day precipitation value at the given time frequency. Examples -------- >>> from xclim.indices import max_n_day_precipitation_amount # The following would compute for each grid cell the highest 5-day total precipitation #at an annual frequency: >>> pr = xr.open_dataset(path_to_pr_file).pr >>> out = max_n_day_precipitation_amount(pr, window=5, freq="YS") """ # Rolling sum of the values arr = pr.rolling(time=window).sum(skipna=False) out = arr.resample(time=freq).max(dim="time", keep_attrs=True) out.attrs["units"] = pr.units # Adjust values and units to make sure they are daily return pint_multiply(out, 1 * units.day, "mm")
def test_pint_multiply(self, pr_series): a = pr_series([1, 2, 3]) out = pint_multiply(a, 1 * units.days) assert out[0] == 1 * 60 * 60 * 24 assert out.units == "kg m-2"
def precip_accumulation( pr: xarray.DataArray, tas: xarray.DataArray = None, phase: Optional[str] = None, thresh: str = "0 degC", 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 a daily temperature is provided, the `phase` keyword can be used to sum precipitation of a given phase only. When the temperature is under the provided threshold, precipitation is assumed to be snow, and liquid rain otherwise. This indice is agnostic to the type of daily temperature (tas, tasmax or tasmin) given. Parameters ---------- pr : xarray.DataArray Mean daily precipitation flux [Kg m-2 s-1] or [mm]. tas : xarray.DataArray, optional Mean, maximum or minimum daily temperature. phase : str, optional, Which phase to consider, "liquid" or "solid", if None (default), both are considered. thresh : str, Threshold of `tas` over which the precipication is assumed to be liquid rain. 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 tas and phase are given, the corresponding phase precipitation is estimated before computing the accumulation, using one of `snowfall_approximation` or `rain_approximation` with the `binary` method. Examples -------- The following would compute, for each grid cell of a dataset, the total precipitation at the seasonal frequency, ie DJF, MAM, JJA, SON, DJF, etc.: >>> from xclim.indices import precip_accumulation >>> pr_day = xr.open_dataset(path_to_pr_file).pr >>> prcp_tot_seasonal = precip_accumulation(pr_day, freq="QS-DEC") """ if phase == "liquid": pr = rain_approximation(pr, tas=tas, thresh=thresh, method="binary") elif phase == "solid": pr = snowfall_approximation(pr, tas=tas, thresh=thresh, method="binary") out = pr.resample(time=freq).sum(dim="time", keep_attrs=True) return pint_multiply(out, 1 * units.day, "mm")