#!/usr/bin/env python # Wenchang Yang (wenchang@princeton.edu) # Sat May 7 12:43:43 EDT 2022 if __name__ == '__main__': import sys from misc.timer import Timer tt = Timer('start ' + ' '.join(sys.argv)) import sys, os.path, os, glob, datetime import xarray as xr, numpy as np, pandas as pd, matplotlib.pyplot as plt #more imports #from misc.landmask import flagland import geoxarray #from misc.landmask import whereland import xclim # if __name__ == '__main__': tt.check('end import') def anom_diff_ts(ts, sm = 15, t_0 = 0): # t_0 is start of year used for accumulation of anomalies (should be in middle of dry season - default is to start from beginning of calendar year) # sm is number of days used to smooth the anomalies (default is 15, ie day +- 7 days) # wrap year at t_0 by shifting all values forwards ts = ts.shift(time = -t_0) # daily anomaly wrt annual mean anom = ts.groupby("time.year") - ts.groupby("time.year").mean("time") #print('anom', anom) #print() #anom.isel(time=slice(0,365)).plot() # cumulative daily anomalies each year #anom_cum = anom.groupby("time.year").cumsum() time_axis = anom.dims.index('time') anom_cum = anom.groupby("time.year").apply(np.cumsum, axis=time_axis) #print('anom_cum', anom_cum); print() #anom_cum.isel(time=slice(0,365)).plot(figsize=(6,4)) # smooth the cumulative anomalies anom_sm = anom_cum.rolling(time = sm, center = True).mean() #anom_sm.isel(time=slice(0,365)).plot(figsize=(6,4)) # differences of smoothed anomalies anom_diff = anom_sm.diff("time") #anom_diff.isel(time=slice(0,365)).plot(figsize=(6,4)) # push the anomalies back to have the correct dates anom_diff = anom_diff.shift(time = t_0) return anom_diff def rainy_season(ts, sm = 15, t_0 = 0): # get differences of smoothed anomalies anom_ts = anom_diff_ts(ts, sm = sm, t_0 = t_0) # count number of consecutive days of positive gradient in cumulative precip rs_length = xclim.indices.run_length.rle(xr.ones_like(anom_ts).where(anom_ts > 0, 0)) #rs_length[0:365].plot(figsize=(6,4)) # tag all days with length of period to which they belong rs_length = rs_length.ffill("time") #rs_length[0:365].plot(figsize=(6,4)) # identify those days that are part of the longest wet period in each year rs = rs_length.where(rs_length.groupby("time.year") - rs_length.groupby("time.year").max() == 0) #rs[0:365].plot(figsize=(6,4)) # convert calendar to Gregorian, matching dates (ensures that DOY is correct, regardless of model calendar) rs = xclim.core.calendar.convert_calendar(rs, "default", align_on = "date") #rs[0:365].plot(figsize=(6,4)) # get start & end of rainy season if 'ens' in rs.dims and rs.ens.size>1: onsets = [] ends = [] for ii in rs.ens.values: onsets.append( rs.sel(ens=ii).time.where(rs.sel(ens=ii) > 0).dropna("time", "any").groupby("time.year").min('time').dt.dayofyear ) ends.append( rs.sel(ens=ii).time.where(rs.sel(ens=ii) > 0).dropna("time", "any").groupby("time.year").max('time').dt.dayofyear ) onsets = xr.concat(onsets, dim='ens') ends = xr.concat(ends, dim='ens') else: onsets = rs.time.where(rs > 0).dropna("time", "any").groupby("time.year").min('time').dt.dayofyear ends = rs.time.where(rs > 0).dropna("time", "any").groupby("time.year").max('time').dt.dayofyear # duration of rainy season durations = ends - onsets return onsets, ends, durations # #start from here #to_degC = lambda x: (x-273.15).assign_attrs(units='degC') #mask = lambda x: x.where(flagland(x)>0.5) #ifile = 't_ref_max_FLOR_HistRCP45_tigercpu_intelmpi_18_576PE_5ens_1860-2100_SouthAsia.nc' #ifile = 'precip_FLOR_HistRCP45_tigercpu_intelmpi_18_576PE_5ens_1860-2100_Pernambuco_masked.nc' #ifile = 'precip_AM2.5C360_amipHadISSTlong_chancorr_tigercpu_intelmpi_18_1080PE_10ens_1871-2021_Pernambuco_masked.nc' #daname = 'precip' #units = 'mm/day' #sel_season = lambda da: da.isel(time=(da.time.dt.month>=6)&(da.time.dt.month<=8)) #sel_season = lambda da: da.isel(time=(da.time.dt.month==6)) #daname = 't_ref' if 't_ref' in sys.argv else 't_ref_max' daname = 'precip' model = 'AM2.5C360' if 'AM2.5C360' in sys.argv else 'FLOR' nens = 3 if model == 'AM2.5C360' else 10 #nens = 10 #units = '$^\circ$C' #func_units = lambda x: (x-273.15).assign_attrs(units=units) if model == 'FLOR': ifiles = 'precip_FLOR_HistRCP45_tigercpu_intelmpi_18_576PE_ens??_1860-2100_WAfrica.nc' else: ifiles = 'precip_AM2.5C360_amipHadISSTrcp45_tigercpu_intelmpi_18_1080PE_ens??_1871-2050_WAfrica.nc' def func(da): """onset/duration; """ return da.load().geo.fldmean().pipe(rainy_season) #ofile = ifile.replace('.nc', '_index.nc') ofile = ifiles.replace('ens??', f'{nens}ens').replace('.nc', f'_onsetindex.nc') if os.path.exists(ofile) and not 'o' in sys.argv: da = xr.open_dataarray(ofile) print('[loaded]:', ofile) else: print('reading...') onsets, ends, durations = xr.open_mfdataset(ifiles)[daname].pipe(func) onsets.to_dataset(name='onset_day').to_netcdf(ofile) print('[saved]:', ofile) ofile_end = ofile.replace('onsetindex', 'endindex') ends.to_dataset(name='end_day').to_netcdf(ofile_end) print('[saved]:', ofile_end) ofile_duration = ofile.replace('onsetindex', 'durationindex') durations.to_dataset(name='duration').to_netcdf(ofile_duration) print('[saved]:', ofile_duration) if __name__ == '__main__': #from wyconfig import * #my plot settings #savefig if len(sys.argv)>1 and 'savefig' in sys.argv[1:]: figname = __file__.replace('.py', f'.png') if 'overwritefig' in sys.argv[1:]: wysavefig(figname, overwritefig=True) else: wysavefig(figname) tt.check(f'**Done**') print() #plt.show()