import numpy as np from netCDF4 import Dataset import warnings warnings.filterwarnings("ignore") from scipy.ndimage import uniform_filter as uf import matplotlib.pyplot as plt from scipy.signal import argrelextrema as lmax import datetime as dt from datetime import datetime from glob import glob #============================================================ # Function to convert date number to a date and time string def time_since_inv(datenumber,reftimeandunits): """ Convert a date number (e.g. time units since a date) to a date in string format Input: 1) The date number 2) The units and reference time of the date number: since yyyy-mm-dd HH:MM:SS can be any of the below: * seconds or secs * minutes or mins * hours or hrs * days or dys * weeks or wks Output: A float indicating the current time in the units specified Requires datetime """ # Split units string and make date and time object splitrtu = reftimeandunits.split(" ") unit = splitrtu[0] refdtob = dt.datetime(int(splitrtu[2][0:4]), int(splitrtu[2][5:7]), int(splitrtu[2][8:10]), int(splitrtu[3][0:2]), int(splitrtu[3][3:5]), int(splitrtu[3][6:8])) # Get date number in seconds if unit.lower()=="minutes" or unit=="mins": datenumber = float(datenumber)*60 elif unit.lower()=="hours" or unit=="hrs": datenumber = float(datenumber)*3600 elif unit.lower()=="days" or unit=="dys": datenumber = float(datenumber)*86400 elif unit.lower()=="weeks" or unit=="wks": datenumber = float(datenumber)*604800 # Using timedelta return a string of the current return(str(refdtob+dt.timedelta(seconds=datenumber))) #============================================================ # Load and process data def loadproc_data(inputfile): # Load data from TIMPS file: datasetFin = Dataset(inputfile) time = datasetFin.variables["time"][:] tunt = datasetFin.variables['time'].units area = datasetFin.variables["area"][:] vrr = datasetFin.variables["vrr"][:] # Smooth time-series of area and VRR: fsize = int(len(area)/5) if fsize<5: fsize=5 areaf = uf(area,size=fsize) vrrf = uf(vrr,size=fsize) # Get gradient of area and VRR: dareaf = np.gradient(areaf,time) dvrrf = np.gradient(vrrf,time) return(time,tunt,area,vrr,areaf,vrrf,dareaf,dvrrf) #============================================================ # Function to get mature indices from a time-series def get_mature_inds(ts,lmxi): """ Get mature stage indices for MCS 1) Time-series of area or vrr 2) Indices of local maxima within time-series 3) Factor of the maxima magnitude for which it can be defined as mature stage Output: A list of indices representing the mature stage in the given time-series """ # Get magnitude of each maxima lmx = [ts[i] for i in lmxi] # Get magnitude of minima between each maxima sepmin = [min(ts[lmxi[i]:lmxi[i+1]]) for i in range(len(lmxi)-1)] # Group into sets of maxima sep = [True if ((sepmin[i]sepmin[i]) and \ (lmx[i]*.75>sepmin[i+1])) else False for i in range(len(lmx))] im = [[sepmini[i]+n for n in np.where(ts[ sepmini[i]:sepmini[i+1]]>lmx[i]*.75)[0].tolist()] for i in range(len(mxtf)) if mxtf[i]] return([item for sublist in im for item in sublist]) #============================================================ # Function to check if stages are within certain conditions def maxchecks(ts,gmd): # Ensure growth/decay isn't spuriously defined when a # maxima is too close to the start of the time-series fper = ts[:ts.argmax()+1] if min(fper)>max(fper)*.75 or fper[0]>max(fper)*.75: for i in np.arange(0,ts.argmax(),1): gmd[i]=0 # Ensure growth/decay isn't spuriously defined when # a maxima is too close to the end of the time-series lper = ts[ts.argmax():] if min(lper)>max(lper)*.75 or lper[-1]>max(lper)*.75: for i in np.arange(ts.argmax(),len(ts)-1,1): gmd[i]=0 # Ensure growth or decay doesn't occur until variable # at least below .75 of a maxima for ti in np.arange(ts.argmax(),len(ts),1): if ts[ti]>max(ts)*.9: if gmd[ti]==1 or gmd[ti]==3: gmd[ti]=0 else: break return(gmd) #============================================================ # Calculate mature stages def get_gmd(areaf,vrrf,dareaf,dvrrf): # Calculate all local maxima in filtered VRR and area: mxia = lmax(areaf,np.greater)[0].tolist() mxiv = lmax(vrrf,np.greater)[0].tolist() # Instance where there are insufficient time-series to # calculate the stages if len(mxia)<1 or len(mxiv)<1 \ or max(areaf)*.50 and dvrrf[i]>0) else 3 if (dareaf[i]<0 and dvrrf[i]<0) else 0 for i in np.arange(0,len(areaf),1)] # Checks to ensure growth or decay isn't spuriously # assigned to a maxima that can't be defined as a maxima gmd = maxchecks(areaf,gmd) gmd = maxchecks(vrrf,gmd) # Ensure each phase lasts longer than just two time-steps for i,x in enumerate(gmd): if i==0: xnow=x; lenx=1; inds=[0] elif i==len(gmd)-1: lenx = lenx+1; inds = inds+[i] if lenx<4: gmd = [0 if m in inds else n for m,n in enumerate(gmd)] elif i>0: if xnow==x: lenx = lenx+1; inds = inds+[i] else: if lenx<4: gmd = [0 if m in inds else n for m,n in enumerate(gmd)] xnow=x; lenx=1; inds=[i] # Ensure each growth/decay at least doubles or halves for i,x in enumerate(gmd): if i==0: xnow=x; inds=[0] elif i>0: if xnow==x: lenx = lenx+1; inds = inds+[i] elif i==len(gmd)-1: inds = inds+[i] if max(areaf[inds])*.5