def test_360_to_366(self): source = xr.DataArray(np.arange(360), coords=[np.arange(1, 361), ], dims='dayofyear') time = pd.date_range('2000-01-01', '2001-12-31', freq='D') target = xr.DataArray(np.arange(len(time)), coords=[time, ], dims='time') out = adjust_doy_calendar(source, target) assert out.sel(dayofyear=1) == source.sel(dayofyear=1) assert out.sel(dayofyear=366) == source.sel(dayofyear=360)
def test_360_to_366(self): source = xr.DataArray(np.arange(360), coords=[np.arange(1, 361)], dims="dayofyear") time = pd.date_range("2000-01-01", "2001-12-31", freq="D") target = xr.DataArray(np.arange(len(time)), coords=[time], dims="time") out = adjust_doy_calendar(source, target) assert out.sel(dayofyear=1) == source.sel(dayofyear=1) assert out.sel(dayofyear=366) == source.sel(dayofyear=360)
def warm_spell_duration_index(tasmax, tx90, window=6, freq="YS"): r"""Warm spell duration index Number of days with at least six consecutive days where the daily maximum temperature is above the 90th percentile. The 90th percentile should be computed for a 5-day window centred on each calendar day in the 1961-1990 period. Parameters ---------- tasmax : xarray.DataArray Maximum daily temperature [℃] or [K] tx90 : float 90th percentile of daily maximum temperature [℃] or [K] window : int Minimum number of days with temperature below threshold to qualify as a warm spell. freq : str, optional Resampling frequency Returns ------- xarray.DataArray Count of days with at least six consecutive days where the daily maximum temperature is above the 90th percentile [days]. References ---------- From the Expert Team on Climate Change Detection, Monitoring and Indices (ETCCDMI). Used in Alexander, L. V., et al. (2006), Global observed changes in daily climate extremes of temperature and precipitation, J. Geophys. Res., 111, D05109, doi: 10.1029/2005JD006290. """ if "dayofyear" not in tx90.coords.keys(): raise AttributeError("tx90 should have dayofyear coordinates.") # The day of year value of the tasmax series. doy = tasmax.indexes["time"].dayofyear # adjustment of tx90 to tasmax doy range tx90 = utils.adjust_doy_calendar(tx90, tasmax) # Create an array with the shape and coords of tasmax, but with values set to tx90 according to the doy index. thresh = xr.full_like(tasmax, np.nan) thresh.data = tx90.sel(dayofyear=doy) above = tasmax > thresh return above.resample(time=freq).apply(rl.windowed_run_count, window=window, dim="time")
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")
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
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")
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')
def cold_spell_duration_index(tasmin, tn10, window=6, freq="YS"): 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 : float 10th percentile of daily minimum temperature. window : int Minimum number of days with temperature below threshold to qualify as a cold spell. Default: 6. freq : str, optional Resampling frequency 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 ------- >>> tn10 = percentile_doy(historical_tasmin, per=.1) >>> cold_spell_duration_index(reference_tasmin, tn10) """ if "dayofyear" not in tn10.coords.keys(): raise AttributeError("tn10 should have dayofyear coordinates.") # The day of year value of the tasmin series. doy = tasmin.indexes["time"].dayofyear tn10 = utils.convert_units_to(tn10, tasmin) # If calendar of `tn10` is different from `tasmin`, interpolate. tn10 = utils.adjust_doy_calendar(tn10, tasmin) # Create an array with the shape and coords of tasmin, but with values set to tx90 according to the doy index. thresh = xr.full_like(tasmin, np.nan) thresh.data = tn10.sel(dayofyear=doy) below = tasmin < thresh return below.resample(time=freq).apply(rl.windowed_run_count, window=window, dim="time")