def from_SHM(self, filename, **kwargs): """ Read a harmonics object from a spherical harmonic model file Inputs: full path of input SHM file Options: keyword arguments for SHM input """ #-- set filename self.case_insensitive_filename(filename) #-- set default verbosity kwargs.setdefault('verbose', False) #-- read data from SHM file Ylms = read_GRACE_harmonics(self.filename, self.lmax, **kwargs) #-- Output file information logging.info(self.filename) logging.info(list(Ylms.keys())) #-- copy variables for gravity model self.clm = Ylms['clm'].copy() self.slm = Ylms['slm'].copy() self.time = Ylms['time'].copy() self.month = np.int64(calendar_to_grace(self.time)) #-- copy header information for gravity model self.header = Ylms['header'] #-- assign shape and ndim attributes self.update_dimensions() return self
def from_HDF5(self, filename, date=True, **kwargs): """ Read a spatial object from a HDF5 file Inputs: full path of input HDF5 file Options: HDF5 file contains date information keyword arguments for HDF5 reader """ #-- set filename self.case_insensitive_filename(filename) #-- set default parameters kwargs.setdefault('verbose', False) kwargs.setdefault('compression', None) kwargs.setdefault('varname', 'z') kwargs.setdefault('lonname', 'lon') kwargs.setdefault('latname', 'lat') kwargs.setdefault('timename', 'time') #-- read data from HDF5 file data = hdf5_read(self.filename, DATE=date, COMPRESSION=kwargs['compression'], VARNAME=kwargs['varname'], LONNAME=kwargs['lonname'], LATNAME=kwargs['latname'], TIMENAME=kwargs['timename']) #-- copy variables to spatial object self.data = data['data'].copy() if '_FillValue' in data['attributes']['data'].keys(): self.fill_value = data['attributes']['_FillValue'] self.mask = np.zeros(self.data.shape, dtype=bool) self.lon = data['lon'].copy() self.lat = data['lat'].copy() #-- if the HDF5 file contains date variables if date: self.time = data['time'].copy() self.month = calendar_to_grace(self.time) #-- adjust months to fix special cases if necessary self.month = adjust_months(self.month) #-- update attributes self.attributes.update(data['attributes']) #-- get spacing and dimensions self.update_spacing() self.update_extents() self.update_dimensions() self.update_mask() return self
def from_ascii(self, filename, date=True, **kwargs): """ Read a spatial object from an ascii file Inputs: full path of input ascii file Options: ascii file contains date information keyword arguments for ascii input """ #-- set filename self.case_insensitive_filename(filename) #-- set default parameters kwargs.setdefault('verbose', False) kwargs.setdefault('compression', None) kwargs.setdefault('columns', ['lon', 'lat', 'data', 'time']) kwargs.setdefault('header', 0) #-- open the ascii file and extract contents logging.info(self.filename) if (kwargs['compression'] == 'gzip'): #-- read input ascii data from gzip compressed file and split lines with gzip.open(self.filename, 'r') as f: file_contents = f.read().decode('ISO-8859-1').splitlines() elif (kwargs['compression'] == 'zip'): #-- read input ascii data from zipped file and split lines base, _ = os.path.splitext(self.filename) with zipfile.ZipFile(self.filename) as z: file_contents = z.read(base).decode('ISO-8859-1').splitlines() elif (kwargs['compression'] == 'bytes'): #-- read input file object and split lines file_contents = self.filename.read().splitlines() else: #-- read input ascii file (.txt, .asc) and split lines with open(self.filename, 'r') as f: file_contents = f.read().splitlines() #-- compile regular expression operator for extracting numerical values #-- from input ascii files of spatial data regex_pattern = r'[-+]?(?:(?:\d*\.\d+)|(?:\d+\.?))(?:[EeD][+-]?\d+)?' rx = re.compile(regex_pattern, re.VERBOSE) #-- output spatial dimensions if (None not in self.extent): self.lat = np.linspace(self.extent[3], self.extent[2], self.shape[0]) self.lon = np.linspace(self.extent[0], self.extent[1], self.shape[1]) else: self.lat = np.zeros((self.shape[0])) self.lon = np.zeros((self.shape[1])) #-- output spatial data self.data = np.zeros((self.shape[0], self.shape[1])) self.mask = np.zeros((self.shape[0], self.shape[1]), dtype=bool) #-- remove time from list of column names if not date columns = [c for c in kwargs['columns'] if (c != 'time')] #-- extract spatial data array and convert to matrix #-- for each line in the file header = kwargs['header'] for line in file_contents[header:]: #-- extract columns of interest and assign to dict #-- convert fortran exponentials if applicable d = { c: r.replace('D', 'E') for c, r in zip(columns, rx.findall(line)) } #-- convert line coordinates to integers ilon = np.int64(np.float64(d['lon']) / self.spacing[0]) ilat = np.int64((90.0 - np.float64(d['lat'])) // self.spacing[1]) self.data[ilat, ilon] = np.float64(d['data']) self.mask[ilat, ilon] = False self.lon[ilon] = np.float64(d['lon']) self.lat[ilat] = np.float64(d['lat']) #-- if the ascii file contains date variables if date: self.time = np.array(d['time'], dtype='f') self.month = calendar_to_grace(self.time) #-- if the ascii file contains date variables if date: #-- adjust months to fix special cases if necessary self.month = adjust_months(self.month) #-- get spacing and dimensions self.update_spacing() self.update_extents() self.update_dimensions() self.update_mask() return self
def convert_harmonics(INPUT_FILE, OUTPUT_FILE, LMAX=None, MMAX=None, UNITS=None, LOVE_NUMBERS=0, REFERENCE=None, DDEG=None, INTERVAL=None, FILL_VALUE=None, HEADER=None, DATAFORM=None, MODE=0o775): #-- verify that output directory exists DIRECTORY = os.path.abspath(os.path.dirname(OUTPUT_FILE)) if not os.access(DIRECTORY, os.F_OK): os.makedirs(DIRECTORY, MODE, exist_ok=True) #-- Grid spacing dlon, dlat = (DDEG, DDEG) if (np.ndim(DDEG) == 0) else (DDEG[0], DDEG[1]) #-- Grid dimensions if (INTERVAL == 1): #-- (0:360, 90:-90) nlon = np.int64((360.0 / dlon) + 1.0) nlat = np.int64((180.0 / dlat) + 1.0) elif (INTERVAL == 2): #-- degree spacing/2 nlon = np.int64((360.0 / dlon)) nlat = np.int64((180.0 / dlat)) #-- read spatial file in data format #-- expand dimensions if (DATAFORM == 'ascii'): #-- ascii (.txt) input_spatial = spatial(spacing=[dlon, dlat], nlat=nlat, nlon=nlon, fill_value=FILL_VALUE).from_ascii( INPUT_FILE, header=HEADER).expand_dims() elif (DATAFORM == 'netCDF4'): #-- netcdf (.nc) input_spatial = spatial().from_netCDF4(INPUT_FILE).expand_dims() elif (DATAFORM == 'HDF5'): #-- HDF5 (.H5) input_spatial = spatial().from_HDF5(INPUT_FILE).expand_dims() #-- convert missing values to zero input_spatial.replace_invalid(0.0) #-- input data shape nlat, nlon, nt = input_spatial.shape #-- read arrays of kl, hl, and ll Love Numbers LOVE = load_love_numbers(LMAX, LOVE_NUMBERS=LOVE_NUMBERS, REFERENCE=REFERENCE) #-- upper bound of spherical harmonic orders (default = LMAX) if MMAX is None: MMAX = np.copy(LMAX) #-- calculate associated Legendre polynomials th = (90.0 - input_spatial.lat) * np.pi / 180.0 PLM, dPLM = plm_holmes(LMAX, np.cos(th)) #-- create list of harmonics objects Ylms_list = [] for i, t in enumerate(input_spatial.time): #-- convert spatial field to spherical harmonics output_Ylms = gen_stokes(input_spatial.data[:, :, i].T, input_spatial.lon, input_spatial.lat, UNITS=UNITS, LMIN=0, LMAX=LMAX, MMAX=MMAX, PLM=PLM, LOVE=LOVE) output_Ylms.time = np.copy(t) output_Ylms.month = calendar_to_grace(t) #-- append to list Ylms_list.append(output_Ylms) #-- convert Ylms list for output spherical harmonics Ylms = harmonics().from_list(Ylms_list) Ylms_list = None #-- outputting data to file if (DATAFORM == 'ascii'): #-- ascii (.txt) Ylms.to_ascii(OUTPUT_FILE) elif (DATAFORM == 'netCDF4'): #-- netCDF4 (.nc) Ylms.to_netCDF4(OUTPUT_FILE) elif (DATAFORM == 'HDF5'): #-- HDF5 (.H5) Ylms.to_HDF5(OUTPUT_FILE) #-- change output permissions level to MODE os.chmod(OUTPUT_FILE, MODE)
def from_ascii(self, filename, **kwargs): """ Read a harmonics object from an ascii file Inputs: full path of input ascii file Options: ascii file contains date information keyword arguments for ascii input """ #-- set filename self.case_insensitive_filename(filename) #-- set default parameters kwargs.setdefault('date', True) kwargs.setdefault('verbose', False) kwargs.setdefault('compression', None) #-- open the ascii file and extract contents logging.info(self.filename) if (kwargs['compression'] == 'gzip'): #-- read input ascii data from gzip compressed file and split lines with gzip.open(self.filename, 'r') as f: file_contents = f.read().decode('ISO-8859-1').splitlines() elif (kwargs['compression'] == 'zip'): #-- read input ascii data from zipped file and split lines base, _ = os.path.splitext(self.filename) with zipfile.ZipFile(self.filename) as z: file_contents = z.read(base).decode('ISO-8859-1').splitlines() elif (kwargs['compression'] == 'bytes'): #-- read input file object and split lines file_contents = self.filename.read().splitlines() else: #-- read input ascii file (.txt, .asc) and split lines with open(self.filename, 'r') as f: file_contents = f.read().splitlines() #-- compile regular expression operator for extracting numerical values #-- from input ascii files of spherical harmonics regex_pattern = r'[-+]?(?:(?:\d*\.\d+)|(?:\d+\.?))(?:[EeD][+-]?\d+)?' rx = re.compile(regex_pattern, re.VERBOSE) #-- find maximum degree and order of harmonics self.lmax = 0 self.mmax = 0 #-- for each line in the file for line in file_contents: if kwargs['date']: l1, m1, clm1, slm1, time = rx.findall(line) else: l1, m1, clm1, slm1 = rx.findall(line) #-- convert line degree and order to integers l1, m1 = np.array([l1, m1], dtype=np.int64) self.lmax = np.copy(l1) if (l1 > self.lmax) else self.lmax self.mmax = np.copy(m1) if (m1 > self.mmax) else self.mmax #-- output spherical harmonics dimensions array self.l = np.arange(self.lmax + 1) self.m = np.arange(self.mmax + 1) #-- output spherical harmonics data self.clm = np.zeros((self.lmax + 1, self.mmax + 1)) self.slm = np.zeros((self.lmax + 1, self.mmax + 1)) #-- if the ascii file contains date variables if kwargs['date']: self.time = np.float64(time) self.month = np.int64(calendar_to_grace(self.time)) #-- adjust months to fix special cases if necessary self.month = adjust_months(self.month) #-- extract harmonics and convert to matrix #-- for each line in the file for line in file_contents: if kwargs['date']: l1, m1, clm1, slm1, time = rx.findall(line) else: l1, m1, clm1, slm1 = rx.findall(line) #-- convert line degree and order to integers ll, mm = np.array([l1, m1], dtype=np.int64) #-- convert fortran exponentials if applicable self.clm[ll, mm] = np.float64(clm1.replace('D', 'E')) self.slm[ll, mm] = np.float64(slm1.replace('D', 'E')) #-- assign shape and ndim attributes self.update_dimensions() return self