示例#1
0
def decompose_symasym(array_in):
    """
    Function that decompose an array (supports array_in(lat,lon),
    array_in(time,lat,lon) and array_in(time,level,lat,lon)) into its symmetric
    and asymmetric parts about the equator.

    The asymmetric part is stored in the Northern Hemisphere as
    SymAsym[lat] = (array_in[lat]-array_in[-lat])/2,
    while the symmetric part is stored in the Southern Hemisphere as
    SymAsym[-lat] = (array_in[lat]+array_in[-lat])/2

    :param array_in:
        Input Aray
    :type array_in: Numpy Array
    :return: SymAsym
    :rtype: Numpy Array
    """
    #Check the dimensions of the array to find out if it has the structure of
    #array_in(lat,lon), array_in(time,lat,lon) or array_in(time,level,lat,lon)
    dim_array  = array_in.shape
    rank_array = len(dim_array)

    if (rank_array>=5):
        raise InputError("Decompose_SymAsym: currently supports up to 4D: rank = {}D"\
                        .format(rank_array))

    #Copy array with same shape as array_in
    #values will be overwritten except when the eq is
    #present in the array

    SymAsym = np.copy(array_in)

    if (rank_array==1):
        for i in range(N):
            # Save symmetric part in the Southern Hemisphere
            SymAsym[i] = 0.5*(array_in[nlat-1-i] + array_in[i])
            # Save antisymmetric part in the Northern Hemisphere
            SymAsym[nlat-1-i] = 0.5*(array_in[nlat-1-i] - array_in[i])
            # Notice that the equator if present is untouched

    if (rank_array==2):
        SymAsym = sym_asym(array_in)

    if (rank_array==3):
        ntim = dim_array[0]
        for t in range(ntim):
            SymAsym[t,:,:] = sym_asym(array_in[t,:,:])

    if (rank_array==4):
        ntim = dim_array[0]
        nlevel = dim_array[1]
        for t in range(ntim):
            for l in range(nlevel):
                SymAsym[t,l,:,:] = sym_asym(array_in[t,l,:,:])

    return SymAsym
示例#2
0
 def import_array(self,array_in,varname):
     if (self.data_status=="Empty"):
         self.data_status = "Numpy array"
         self.file = "array"
         self.varname = varname
         self.data = array_in
         print('An array has been imported')
     else:
         raise InputError("You have already loaded some data")
     return None
示例#3
0
 def import_analysis(self,file):
     if (self.data_status=="Empty"):
         self.data_status = "An analysis file has been imported"
         self.analysis_status = "Imported"
         self.wk_spectra = np.load(file).item()
         self.spd = self.wk_spectra['spd']
         self.nDayWin = self.wk_spectra['nDayWin']
         self.nDaySkip = self.wk_spectra['nDaySkip']
         self.max_freq = self.wk_spectra['max_freq']
         self.max_wn = self.wk_spectra['max_wn']
         self.varname = self.wk_spectra['varname']
         print('The analysis stored in {} has been imported.'.format(file))
     else:
         raise InputError("You have already loaded some data")
     return None
示例#4
0
def sampling_vars(array_in,spd,nDayWin,nDaySkip):

    # Supports only array_in(time,lat,lon)
    ntim,nlat,nlon = array_in.shape

    if ((ntim%spd)!=0):
        raise InputError("Input array must have complete days only ntim%spd = {}".format(ntim%spd))

    # Number of days
    nDayTot = ntim//spd
    # Number of samples per temporal window
    nSampWin = nDayWin*spd
    # Number of samples to skip between window segments.
    # Negative number means overlap
    nSampSkip = nDaySkip*spd

    return (ntim,nlat,nlon,nDayTot,nSampWin,nSampSkip)
示例#5
0
    def import_netcdf(self,file,varname,latname='latitude',latBound=15):
        if (self.data_status=="Empty"):
            self.data_status = "NetCDF File"
            self.file = str(file)
            self.varname = varname
            self.latname = latname
            self.latBound = latBound
            f = nc.Dataset(file, 'r')
            array_out = f.variables[varname][:]
            latitudes = f.variables[latname][:]
            lat_ind = np.where(np.logical_and(latitudes>=-latBound,latitudes<=latBound))[0]
            array_out = array_out[:,lat_ind,:]
            self.data = array_out
            print('The file {} has been imported'.format(self.file))
        else:
            raise InputError("You have already loaded some data")

        return None
示例#6
0
    def save_figs(self,name=None,ext='png'):
        if (self.plots_available == "Yes"):
            g_ext = ['png','pdf','eps']
            if ext not in g_ext:
                print('The file extension {} is not supported. Using png instead.'\
                .format(str(ext)))
                ext = 'png'
            if name is None:
                if hasattr(self, 'name'):
                    name = self.name
                else:
                    name = str(self.varname)
            dirname = name+'_plots'
            if not os.path.isdir(dirname):
                os.makedirs(dirname)
            for key in self.plots:
                self.plots[key].savefig(dirname+'/'+name+'_'+key+'.'+ext)
        else:
            raise InputError("You don't have plots to save")

        return None
示例#7
0
    def wheeler_kiladis_spectra(self,spd,nDayWin,nDaySkip,max_freq=0.5,max_wn=20):
        if (self.data_status=="Empty"):
            raise InputError("You need to input some data first.")
        else:
            if (self.analysis_status=="Empty"):
                array_in = self.data
                self.spd = spd
                self.nDayWin = nDayWin
                self.nDaySkip = nDaySkip
                self.max_freq = max_freq
                self.max_wn = max_wn

                ntim,nlat,nlon,nDayTot,nSampWin,nSampSkip = sampling_vars(array_in,spd,nDayWin,nDaySkip)

                # Remove dominant signals
                array_dt = remove_dominant_signals(array_in,spd,nDayWin,nDaySkip)

                # Decompose in Symmetric and Antisymmetric components
                array_as = decompose_symasym(array_dt)

                wavefft,freqfft,peeAS = spectral_coefficients(array_as,spd,nDayWin,nDaySkip)

                # Calculate the power spectrum
                power = (abs(peeAS))**2 # power[window,freq,lat,lon]

                psumanti,psumsym = separate_power(power,nlat,nSampWin,wavefft,freqfft)

                psumb = derive_background(power,nlat,nSampWin,wavefft,freqfft)

                # Cropping the output
                indwave = np.where(np.logical_and(wavefft>=-max_wn,wavefft<=max_wn))[0]
                indfreq = np.where(np.logical_and(freqfft>0,freqfft<=max_freq))[0]

                wavefft = wavefft[indwave]
                freqfft = freqfft[indfreq]

                psumanti = psumanti[indfreq,:]
                psumanti = psumanti[:,indwave]

                psumsym = psumsym[indfreq,:]
                psumsym = psumsym[:,indwave]

                psumb = psumb[indfreq,:]
                psumb = psumb[:,indwave]

                # Log10 scaling
                psumanti_log = np.log10(psumanti)
                psumsym_log = np.log10(psumsym)
                psumb_log = np.log10(psumb)

                psumanti_r = psumanti/psumb
                psumsym_r = psumsym/psumb

                self.wk_spectra = {
                            'psumanti':psumanti,
                            'psumsym':psumsym,
                            'psumb':psumb,
                            'psumanti_log':psumanti_log,
                            'psumsym_log':psumsym_log,
                            'psumb_log':psumb_log,
                            'psumanti_r':psumanti_r,
                            'psumsym_r':psumsym_r,
                            'wavefft':wavefft,
                            'freqfft':freqfft,
                            'spd':spd,
                            'nDayWin':nDayWin,
                            'nDaySkip':nDaySkip,
                            'max_freq':max_freq,
                            'max_wn':max_wn,
                            'varname':self.varname
                            }
                self.analysis_status = "Complete"
                print("The Wheeler-Kiladis Analysis is complete.")
            else:
                raise InputError("You have already done the analysis.")
            return None
示例#8
0
def spectral_coefficients(array_in,spd,nDayWin,nDaySkip):

    ntim,nlat,nlon,nDayTot,nSampWin,nSampSkip = sampling_vars(array_in,spd,nDayWin,nDaySkip)

    # Test if there is enought time data for the analysis
    if (ntim<nSampWin):
        raise InputError("The available number of days is less than the sample window")
    else:
        # Count the number of available samples
        nWindow = (ntim-nSampWin)//(nSampWin+nSampSkip)+1


    # Test if longitude and time dimensions are even.
    # The fft algorith gives the nyquist frequency one time for even and two times
    # for odd dimensions
    if (nSampWin%2==0): #if time is even
        if (nlon%2==0): # and longitude is even also
            peeAS = np.zeros((nWindow,nSampWin+1,nlat,nlon+1),dtype='c16')
        else: # but longitude is odd
            peeAS = np.zeros((nWindow,nSampWin+1,nlat,nlon),dtype='c16')
    else: #if time is odd
        if (nlon%2==0): # but longitude is even
            peeAS = np.zeros((nWindow,nSampWin,nlat,nlon+1),dtype='c16')
        else: # but longitude is odd also
            peeAS = np.zeros((nWindow,nSampWin,nlat,nlon),dtype='c16')

    # Create a tapering window(nSampWin,nlat,nlon) using the hanning function.
    # For more information about the hanning function see:
    # http://docs.scipy.org/doc/numpy/reference/generated/numpy.hanning.html
    # Note: Hanning function is different from Hamming function.
    tapering_window = np.repeat(np.hanning(nSampWin), nlat*nlon).reshape(nSampWin,nlat,nlon)

    ntStrt = 0
    ntLast = nSampWin

    for nw in range(nWindow):
        # Detrend temporal window
        temp_window = signal.detrend(array_in[ntStrt:ntLast,:,:],axis=0,type='linear')
        # Taper temporal window in the time dimension
        temp_window = temp_window*tapering_window
        # Apply fft to time and longitude
        fourier_fft = np.fft.fft2(temp_window,axes=(0,2))
        # normalize by # time samples
        fourier_fft = fourier_fft/(nlon*nSampWin)
        # fourier_fft(nSampWin,nlat,nlon) contains the
        # complex space-time spectrum for each latitude


        # Special reordering to resolve the Progressive and Retrogressive waves
        # based on Hayashi (1971).

        fourier_fft = np.fft.fftshift(fourier_fft, axes=(0,2))


        if (nSampWin%2==0): #if time is even
            if (nlon%2==0): # and longitude is even also
                varspacetime = np.zeros((nSampWin+1,nlat,nlon+1),dtype='c16')
                varspacetime[:nSampWin,:,:nlon] = fourier_fft
                varspacetime[nSampWin,:,:] = varspacetime[0,:,:]
                varspacetime[:,:,nlon] = varspacetime[:,:,0]
            else: # but longitude is odd
                varspacetime = np.zeros((nSampWin+1,nlat,nlon),dtype='c16')
                varspacetime[:nSampWin,:,:] = fourier_fft
                varspacetime[nSampWin,:,:] = varspacetime[0,:,:]
        else: #if time is odd
            if (nlon%2==0): # but longitude is even
                varspacetime = np.zeros((nSampWin,nlat,nlon+1),dtype='c16')
                varspacetime[:,:,:nlon] = fourier_fft
                varspacetime[:,:,nlon] = varspacetime[:,:,0]
            else: # but longitude is odd also
                varspacetime = np.zeros((nSampWin,nlat,nlon),dtype='c16')
                varspacetime[:,:,:] = fourier_fft

        fourier_fft = varspacetime

        # To correct that a positive freq in
        # fourier corresponds to a negative wave freq
        # i.e. Fourier -> e^i(kx+wt) != Wave -> e^i(kx-wt)
        fourier_fft = fourier_fft[:,:,::-1]
        # Save the Fourier Coefficients for each window
        peeAS[nw,:,:,:] = fourier_fft
        # Set index for next temporal window
        ntStrt = ntLast+nSampSkip
        ntLast = ntStrt+nSampWin
        del fourier_fft, temp_window

    wavefft = np.arange(-int(nlon/2),int(nlon/2)+1.,1.)
    freqfft = np.arange(-1.*int(nDayWin*spd/2),1.*int(nDayWin*spd/2)+1.,1)/(nDayWin)# Calculate the power spectrum
    return (wavefft,freqfft,peeAS)