def ice_days( tasmax: xarray.DataArray, thresh: str = "0 degC", freq: str = "YS" ) -> xarray.DataArray: # noqa: D401 r"""Number of ice/freezing days. Number of days where daily maximum temperatures are below a threshold. Parameters ---------- tasmax : xarray.DataArray Maximum daily temperature. thresh : str Freezing temperature. freq : str Resampling frequency. Returns ------- xarray.DataArray, [time] Number of ice/freezing days. Notes ----- Let :math:`TX_{ij}` be the daily maximum temperature at day :math:`i` of period :math:`j`, and :math`TT` the threshold. Then counted is the number of days where: .. math:: TX_{ij} < TT """ frz = convert_units_to(thresh, tasmax) out = threshold_count(tasmax, "<", frz, freq) return to_agg_units(out, tasmax, "count")
def tn_days_below( tasmin: xarray.DataArray, thresh: str = "-10.0 degC", freq: str = "YS" ): # noqa: D401 r"""Number of days with tmin below a threshold. 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 Resampling frequency; Defaults to "YS". 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 = convert_units_to(thresh, tasmin) f1 = threshold_count(tasmin, "<", thresh, freq) return f1
def tx_days_above( tasmax: xarray.DataArray, thresh: str = "25.0 degC", freq: str = "YS" ): # noqa: D401 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 Resampling frequency; Defaults to "YS". 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 = convert_units_to(thresh, tasmax) f = (tasmax > thresh) * 1 return f.resample(time=freq).sum(dim="time")
def heat_wave_index( tasmax: xarray.DataArray, thresh: str = "25.0 degC", window: int = 5, freq: str = "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 : xarray.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 Resampling frequency; Defaults to "YS". Returns ------- DataArray Heat wave index. """ thresh = convert_units_to(thresh, tasmax) over = tasmax > thresh group = over.resample(time=freq) return group.map(rl.windowed_run_count, window=window, dim="time")
def heating_degree_days( tas: xarray.DataArray, thresh: str = "17.0 degC", freq: str = "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 Resampling frequency; Defaults to "YS". 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 = convert_units_to(thresh, tas) return tas.pipe(lambda x: thresh - x).clip(0).resample(time=freq).sum(dim="time")
def dry_days(pr: xarray.DataArray, thresh: str = "0.2 mm/d", freq: str = "YS"): r"""Dry days. The number of days with daily precipitation below threshold. Parameters ---------- pr : xarray.DataArray Daily precipitation [mm/d or kg/m²/s] thresh : str Threshold temperature on which to base evaluation. Default: '0.2 mm/d'. freq : str Resampling frequency; Defaults to "YS". Returns ------- xarray.DataArray Number of days with daily precipitation below threshold. Notes ----- Let :math:`PR_{ij}` be the daily precipitation at day :math:`i` of period :math:`j`. Then counted is the number of days where: .. math:: \sum PR_{ij} < Threshold [mm/day] """ thresh = convert_units_to(thresh, pr) return pr.pipe(lambda x: (pr < thresh) * 1).resample(time=freq).sum(dim="time")
def growing_degree_days( tas: xarray.DataArray, thresh: str = "4.0 degC", freq: str = "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 Resampling frequency. Default: "YS". Returns ------- xarray.DataArray The sum of growing degree-days above a given threshold. 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 = convert_units_to(thresh, tas) return ( tas.pipe(lambda x: x - thresh).clip(min=0).resample(time=freq).sum(dim="time") )
def sea_ice_extent(sic, area, thresh: str = "15 pct"): """Return the total sea ice extent. Sea ice extent measures the *ice-covered* area, where a region is considered ice-covered if its 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 extent [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 = convert_units_to(thresh, sic) out = xarray.dot(sic >= t, area) out.attrs["units"] = area.units return out
def tropical_nights( tasmin: xarray.DataArray, thresh: str = "20.0 degC", freq: str = "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 Resampling frequency; Defaults to "YS". 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 = convert_units_to(thresh, tasmin) return ( tasmin.pipe(lambda x: (tasmin > thresh) * 1).resample(time=freq).sum(dim="time") )
def last_snowfall( prsn: xarray.DataArray, thresh: str = "0.5 mm/day", freq: str = "AS-JUL", ): r"""Last day with solid precipitation above a threshold. Returns the last day of a period where the solid precipitation exceeds a threshold. WARNING: The default freq is valid for the northern hemisphere. Parameters ---------- prsn : xarray.DataArray Solid precipitation flux. thresh : str Threshold precipitation flux on which to base evaluation. Default '0.5 mm/day'. freq : str Resampling frequency; Defaults to "AS-JUL". Returns ------- xarray.DataArray Last day of the year when the solid precipitation is superior to a threshold, If there is no such day, return np.nan. """ thresh = convert_units_to(thresh, prsn) cond = prsn >= thresh return cond.resample(time=freq).map( rl.last_run, window=1, dim="time", coord="dayofyear", )
def wetdays(pr: xarray.DataArray, thresh: str = "1.0 mm/day", freq: str = "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 Resampling frequency defining the periods defined in http://pandas.pydata.org/pandas-docs/stable/timeseries.html#resampling; Defaults to "YS". 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.: >>> from xclim.indices import wetdays >>> pr = xr.open_dataset(path_to_pr_file).pr >>> wd = wetdays(pr, thresh="5 mm/day", freq="QS-DEC") """ thresh = convert_units_to(thresh, pr, "hydro") wd = (pr >= thresh) * 1 return wd.resample(time=freq).sum(dim="time")
def warm_day_frequency( tasmax: xarray.DataArray, thresh: str = "30 degC", freq: str = "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 Resampling frequency; Defaults to "YS". 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 = convert_units_to(thresh, tasmax) events = (tasmax > thresh) * 1 return events.resample(time=freq).sum(dim="time")
def cold_spell_frequency( tas: xarray.DataArray, thresh: str = "-10 degC", window: int = 5, freq: str = "AS-JUL", ): r"""Cold spell frequency. The number of cold spell events, defined as a sequence of consecutive days with mean daily temperature below a threshold in °C. Parameters ---------- tas : xarray.DataArray Mean daily temperature [℃] or [K] thresh : str Threshold temperature below which a cold spell begins [℃] or [K]. Default: '-10 degC' window : int Minimum number of days with temperature below threshold to qualify as a cold spell. freq : str Resampling frequency; Defaults to "AS-JUL". Returns ------- xarray.DataArray Cold spell frequency. """ t = convert_units_to(thresh, tas) over = tas < t group = over.resample(time=freq) return group.map(rl.windowed_run_events, window=window, dim="time")
def frost_days( tasmin: xarray.DataArray, thresh: str = "0 degC", freq: str = "YS" ) -> xarray.DataArray: r"""Frost days index. Number of days where daily minimum temperatures are below a threshold temperature. Parameters ---------- tasmin : xarray.DataArray Minimum daily temperature. thresh : str Freezing temperature. freq : str Resampling frequency. Returns ------- xarray.DataArray, [time] Frost days index. Notes ----- Let :math:`TN_{ij}` be the daily minimum temperature at day :math:`i` of period :math:`j` and :math`TT` the threshold. Then counted is the number of days where: .. math:: TN_{ij} < TT """ frz = convert_units_to(thresh, tasmin) out = threshold_count(tasmin, "<", frz, freq) return to_agg_units(out, tasmin, "count")
def daily_freezethaw_cycles( tasmin: xarray.DataArray, tasmax: xarray.DataArray, thresh_tasmax: str = "0 degC", thresh_tasmin: str = "0 degC", freq: str = "YS", ) -> xarray.DataArray: # noqa: D401 r"""Number of days with a diurnal freeze-thaw cycle. The number of days where Tmax > thresh_tasmax and Tmin <= thresh_tasmin. Parameters ---------- tasmin : xarray.DataArray Minimum daily temperature. tasmax : xarray.DataArray Maximum daily temperature. thresh_tasmax : str The temperature threshold needed to trigger a thaw event. thresh_tasmin : str The temperature threshold needed to trigger a freeze event. freq : str Resampling frequency. Returns ------- xarray.DataArray, [time] 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. """ thaw_threshold = convert_units_to(thresh_tasmax, tasmax) freeze_threshold = convert_units_to(thresh_tasmin, tasmin) ft = (tasmin <= freeze_threshold) * (tasmax > thaw_threshold) * 1 out = ft.resample(time=freq).sum(dim="time") return to_agg_units(out, tasmin, "count")
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 = convert_units_to(per, pr) thresh = convert_units_to(thresh, pr) tp = np.maximum(per, thresh) if "dayofyear" in per.coords: # Create time series out of doy values. tp = 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")
def latitude_temperature_index( tas: xarray.DataArray, lat: xarray.DataArray, lat_factor: float = 75, freq: str = "YS", ) -> xarray.DataArray: """Latitude-Temperature Index. Mean temperature of the warmest month with a latitude-based scaling factor. Used for categorizing winegrowing regions. Parameters ---------- tas: xarray.DataArray Mean daily temperature. lat: xarray.DataArray Latitude coordinate. lat_factor: float Latitude factor. Maximum poleward latitude. Default: 75. freq : str Resampling frequency. Returns ------- xarray.DataArray, [unitless] Latitude Temperature Index. Notes ----- The latitude factor of `75` is provided for examining the poleward expansion of winegrowing climates under scenarios of climate change. For comparing 20th century/observed historical records, the original scale factor of `60` is more appropriate. Let :math:`Tn_{j}` be the average temperature for a given month :math:`j`, :math:`lat_{f}` be the latitude factor, and :math:`lat` be the latitude of the area of interest. Then the Latitude-Temperature Index (:math:`LTI`) is: .. math:: LTI = max(TN_{j}: j = 1..12)(lat_f - |lat|) References ---------- Indice originally published in Jackson, D. I., & Cherry, N. J. (1988). Prediction of a District’s Grape-Ripening Capacity Using a Latitude-Temperature Index (LTI). American Journal of Enology and Viticulture, 39(1), 19‑28. Modified latitude factor from Kenny, G. J., & Shao, J. (1992). An assessment of a latitude-temperature index for predicting climate suitability for grapes in Europe. Journal of Horticultural Science, 67(2), 239‑246. https://doi.org/10.1080/00221589.1992.11516243 """ tas = convert_units_to(tas, "degC") tas = tas.resample(time="MS").mean(dim="time") mtwm = tas.resample(time=freq).max(dim="time") lat_mask = (abs(lat) >= 0) & (abs(lat) <= lat_factor) lat_coeff = xarray.where(lat_mask, lat_factor - abs(lat), 0) lti = mtwm * lat_coeff lti.attrs["units"] = "" return lti
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, precipitation 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.: >>> 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 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 uniindtemp_compute(da: xr.DataArray, thresh: str = "0.0 degC", freq: str = "YS"): """Docstring""" out = da - convert_units_to(thresh, da) out = out.resample(time=freq).mean() out.attrs["units"] = da.units return out
def retrend(self, da: xr.DataArray): """Put the previously fitted trend back on a DataArray.""" if not self.fitted: raise ValueError("You must call fit() before retrending") trend = self.ds.trend if "units" in da.attrs: trend = convert_units_to(self.ds.trend, da) return self._retrend(da, trend)
def detrend(self, da: xr.DataArray): """Remove the previously fitted trend from a DataArray.""" if not self.fitted: raise ValueError("You must call fit() before detrending.") trend = self.ds.trend if "units" in da.attrs: trend = convert_units_to(self.ds.trend, da) return self._detrend(da, trend)
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 = convert_units_to(tn10, tasmin) # Create time series out of doy values. thresh = resample_doy(tn10, tasmin) below = tasmin < thresh return below.resample(time=freq).map(rl.windowed_run_count, window=window, dim="time")
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. per : xarray.DataArray Daily percentile of wet day precipitation flux. thresh : str Precipitation value over which a day is considered wet. freq : str Resampling frequency. Returns ------- xarray.DataArray, [dimensionless] Fraction of precipitation over threshold during wet days days. """ per = convert_units_to(per, pr) thresh = convert_units_to(thresh, pr) tp = np.maximum(per, thresh) if "dayofyear" in per.coords: # Create time series out of doy values. tp = 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") out = over / total out.attrs["units"] = "" return out
def days_over_precip_thresh( pr: xarray.DataArray, per: xarray.DataArray, thresh: str = "1 mm/day", freq: str = "YS", ) -> xarray.DataArray: # noqa: D401 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. per : xarray.DataArray Daily percentile of wet day precipitation flux. thresh : str Precipitation value over which a day is considered wet. freq : str Resampling frequency. Returns ------- xarray.DataArray, [time] Count of days with daily precipitation above the given percentile [days]. Examples -------- >>> from xclim.indices import days_over_precip_thresh >>> pr = xr.open_dataset(path_to_pr_file).pr >>> p75 = pr.quantile(.75, dim="time", keep_attrs=True) >>> r75p = days_over_precip_thresh(pr, p75) """ per = convert_units_to(per, pr) thresh = convert_units_to(thresh, pr) tp = np.maximum(per, thresh) if "dayofyear" in per.coords: # Create time series out of doy values. tp = resample_doy(tp, pr) # Compute the days where precip is both over the wet day threshold and the percentile threshold. out = threshold_count(pr, ">", tp, freq) return to_agg_units(out, pr, "count")
def blowing_snow( snd: xarray.DataArray, sfcWind: xarray.DataArray, # noqa snd_thresh: str = "5 cm", sfcWind_thresh: str = "15 km/h", # noqa window: int = 3, freq: str = "AS-JUL", ) -> xarray.DataArray: """ Days with blowing snow events Number of days where both snowfall over the last days and daily wind speeds are above respective thresholds. Parameters ---------- snd : xarray.DataArray Surface snow depth. sfcWind : xr.DataArray Wind velocity snd_thresh : str Threshold on net snowfall accumulation over the last `window` days. sfcWind_thresh : str Wind speed threshold. window : int Period over which snow is accumulated before comparing against threshold. freq : str Resampling frequency. Returns ------- xarray.DataArray Number of days where snowfall and wind speeds are above respective thresholds. """ snd_thresh = convert_units_to(snd_thresh, snd) sfcWind_thresh = convert_units_to(sfcWind_thresh, sfcWind) # noqa # Net snow accumulation over the last `window` days snow = snd.diff(dim="time").rolling(time=window, center=False).sum() # Blowing snow conditions cond = (snow >= snd_thresh) * (sfcWind >= sfcWind_thresh) * 1 out = cond.resample(time=freq).sum(dim="time") out.attrs["units"] = to_agg_units(out, snd, "count") return out
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 = convert_units_to(thresh_tasmax, tasmax) thresh_tasmin = convert_units_to(thresh_tasmin, tasmin) cond = (tasmin > thresh_tasmin) & (tasmax > thresh_tasmax) group = cond.resample(time=freq) return group.map(rl.windowed_run_count, args=(window, ), dim="time")
def test_deprecation(self, tas_series): with pytest.warns(FutureWarning): out = convert_units_to(0, units.K) assert out == 273.15 with pytest.warns(FutureWarning): out = 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
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: 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. tasmax : xarray.DataArray Maximum daily temperature. thresh_tasmin : str The minimum temperature threshold needed to trigger a heatwave event. thresh_tasmax : str The maximum temperature threshold needed to trigger a heatwave event. window : int Minimum number of days with temperatures above thresholds to qualify as a heatwave. freq : str Resampling frequency. Returns ------- xarray.DataArray, [time] Total length of heatwave at the requested frequency. Notes ----- See notes and references of `heat_wave_max_length` """ thresh_tasmax = convert_units_to(thresh_tasmax, tasmax) thresh_tasmin = convert_units_to(thresh_tasmin, tasmin) cond = (tasmin > thresh_tasmin) & (tasmax > thresh_tasmax) out = cond.resample(time=freq).map(rl.windowed_run_count, window=window) return to_agg_units(out, tasmin, "count")
def dry_spell_total_length( pr: xarray.DataArray, thresh: str = "1.0 mm", window: int = 3, op: str = "sum", freq: str = "YS", **indexer, ) -> xarray.DataArray: """ Total length of dry spells Total number of days in dry periods of a minimum length, during which the maximum or accumulated precipitation within a window of the same length is under a threshold. Parameters ---------- pr : xarray.DataArray Daily precipitation. thresh : str Accumulated precipitation value under which a period is considered dry. window : int Number of days where the maximum or accumulated precipitation is under threshold. op : {"max", "sum"} Reduce operation. freq : str Resampling frequency. indexer : Indexing parameters to compute the indicator on a temporal subset of the data. It accepts the same arguments as :py:func:`xclim.indices.generic.select_time`. Indexing is done after finding the dry days, but before finding the spells. Returns ------- xarray.DataArray The {freq} total number of days in dry periods of minimum {window} days. Notes ----- The algorithm assumes days before and after the timeseries are "wet", meaning that the condition for being considered part of a dry spell is stricter on the edges. For example, with `window=3` and `op='sum'`, the first day of the series is considered part of a dry spell only if the accumulated precipitation within the first 3 days is under the threshold. In comparison, a day in the middle of the series is considered part of a dry spell if any of the three 3-day periods of which it is part are considered dry (so a total of five days are included in the computation, compared to only 3.) """ pram = rate2amount(pr, out_units="mm") thresh = convert_units_to(thresh, pram) pram_pad = pram.pad(time=(0, window)) mask = getattr(pram_pad.rolling(time=window), op)() < thresh dry = (mask.rolling(time=window).sum() >= 1).shift(time=-(window - 1)) dry = dry.isel(time=slice(0, pram.time.size)).astype(float) out = select_time(dry, **indexer).resample(time=freq).sum("time") return to_agg_units(out, pram, "count")
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