def test_gfz_icgem_costg_download_and_read(): #-- attempt to download from ftp server try: HOST = [ 'icgem.gfz-potsdam.de', '02_COST-G', 'Grace-FO', 'GSM-2_2018152-2018181_GRFO_COSTG_BF01_0100.gfc' ] FILE = gravity_toolkit.utilities.from_ftp(HOST, verbose=True) except: pass #-- attempt to download from http server try: HOST = [ 'http://icgem.gfz-potsdam.de', 'getseries', '02_COST-G', 'Grace-FO', 'GSM-2_2018152-2018181_GRFO_COSTG_BF01_0100.gfc' ] FILE = gravity_toolkit.utilities.from_http(HOST, verbose=True) except: return #-- read as virtual file object Ylms = read_GRACE_harmonics(FILE, 60) keys = ['time', 'start', 'end', 'clm', 'slm', 'eclm', 'eslm', 'header'] test = dict(start=2458270.5, end=2458299.5) assert all((key in Ylms.keys()) for key in keys) assert all((Ylms[key] == val) for key, val in test.items()) assert (Ylms['clm'][2, 0] == -0.484165436067e-03)
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 test_gfz_ftp_download_and_read(username, webdav): HOST = [ 'isdcftp.gfz-potsdam.de', 'grace', 'Level-2', 'CSR', 'RL06', 'GSM-2_2002095-2002120_GRAC_UTCSR_BA01_0600.gz' ] #-- download and read as virtual file object FILE = gravity_toolkit.utilities.from_ftp(HOST, verbose=True) Ylms = read_GRACE_harmonics(FILE, 60) keys = ['time', 'start', 'end', 'clm', 'slm', 'eclm', 'eslm', 'header'] test = dict(start=2452369.5, end=2452394.5) assert all((key in Ylms.keys()) for key in keys) assert all((Ylms[key] == val) for key, val in test.items()) assert (Ylms['clm'][2, 0] == -0.484169355584e-03)
def test_podaac_download_and_read(username, webdav): HOST = [ 'https://podaac-tools.jpl.nasa.gov', 'drive', 'files', 'allData', 'grace', 'L2', 'CSR', 'RL06', 'GSM-2_2002095-2002120_GRAC_UTCSR_BA01_0600.gz' ] #-- download and read as virtual file object FILE = gravity_toolkit.utilities.from_drive(HOST, username=username, password=webdav, verbose=True) Ylms = read_GRACE_harmonics(FILE, 60) keys = ['time', 'start', 'end', 'clm', 'slm', 'eclm', 'eslm', 'header'] test = dict(start=2452369.5, end=2452394.5) assert all((key in Ylms.keys()) for key in keys) assert all((Ylms[key] == val) for key, val in test.items()) assert (Ylms['clm'][2, 0] == -0.484169355584e-03)
def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, missing, SLR_C20, DEG1, MMAX=None, SLR_C30='', MODEL_DEG1=False, DEG1_GIA='', ATM=False, POLE_TIDE=False): """ Reads GRACE/GRACE-FO files for a spherical harmonic degree and order and a date range Replaces Degree 1 with with input values (if specified) Replaces C20 with SLR values (if specified) Replaces C30 with SLR values for months 179+ (if specified) Corrects for ECMWF atmospheric "jumps" using the GAE, GAF and GAG files Corrects for Pole Tide drift following Wahr et al. (2015) Arguments --------- base_dir: Working data directory for GRACE/GRACE-FO data PROC: (CSR/CNES/JPL/GFZ) data processing center DREL: (RL01,RL02,RL03,RL04,RL05,RL06) data release DSET: (GAA/GAB/GAC/GAD/GSM) data product LMAX: Upper bound of Spherical Harmonic Degrees start_mon: starting month to consider in analysis end_mon: ending month to consider in analysis missing: missing months to not consider in analysis SLR_C20: Replaces C20 with SLR values N: use original values CSR: use values from CSR (TN-07,TN-09,TN-11) GSFC: use values from GSFC (TN-14) DEG1: Use Degree 1 coefficients None: No degree 1 Tellus: GRACE/GRACE-FO TN-13 coefficients from PO.DAAC SLR: satellite laser ranging coefficients from CSR SLF: Sutterley and Velicogna coefficients, Remote Sensing (2019) Keyword arguments ----------------- MMAX: Upper bound of Spherical Harmonic Orders SLR_C30: replaces C30 with SLR values None: use original values CSR: use values from CSR (5x5 with 6,1) GSFC: use values from GSFC (TN-14) POLE_TIDE: correct GSM data with pole tides following Wahr et al (2015) ATM: correct data with ECMWF "jump" corrections GAE, GAF and GAG MODEL_DEG1: least-squares model missing degree 1 coefficients (True/False) DEG1_GIA: GIA-correction used when calculating degree 1 coefficients Returns ------- clm: GRACE/GRACE-FO cosine spherical harmonics slm: GRACE/GRACE-FO sine spherical harmonics time: time of each GRACE/GRACE-FO measurement (mid-month) month: GRACE/GRACE-FO months of input datasets l: spherical harmonic degree to LMAX m: spherical harmonic order to MMAX title: string denoting low degree zonals replacement, geocenter usage and corrections directory: directory of exact GRACE/GRACE-FO product """ #-- Directory of exact GRACE product grace_dir = os.path.join(base_dir, PROC, DREL, DSET) #-- upper bound of spherical harmonic orders (default = LMAX) MMAX = np.copy(LMAX) if (MMAX is None) else MMAX #-- Replacing C2,0 with SLR C2,0 #-- Running function read_SLR_C20.py #-- reading SLR C2,0 file for given release if specified if (SLR_C20 == 'CSR'): if (DREL == 'RL04'): SLR_file = os.path.join(base_dir, 'TN-05_C20_SLR.txt') elif (DREL == 'RL05'): SLR_file = os.path.join(base_dir, 'TN-07_C20_SLR.txt') elif (DREL == 'RL06'): SLR_file = os.path.join(base_dir, 'TN-11_C20_SLR.txt') C20_input = read_SLR_C20(SLR_file) C20_str = '_wCSR_C20' elif (SLR_C20 == 'GSFC'): SLR_file = os.path.join(base_dir, 'TN-14_C30_C20_GSFC_SLR.txt') C20_input = read_SLR_C20(SLR_file) C20_str = '_wGSFC_C20' else: C20_str = '' #-- Replacing C3,0 with SLR C3,0 #-- Running function read_SLR_C30.py if (SLR_C30 == 'CSR'): SLR_file = os.path.join(base_dir, 'CSR_Monthly_5x5_Gravity_Harmonics.txt') C30_input = read_SLR_C30(SLR_file) C30_str = '_wCSR_C30' elif (SLR_C30 == 'LARES'): SLR_file = os.path.join(base_dir, 'C30_LARES_filtered.txt') C30_input = read_SLR_C30(SLR_file) C30_str = '_wLARES_C30' elif (SLR_C30 == 'GSFC'): SLR_file = os.path.join(base_dir, 'TN-14_C30_C20_GSFC_SLR.txt') C30_input = read_SLR_C30(SLR_file) C30_str = '_wGSFC_C30' else: C30_str = '' #-- Correcting for Degree 1 (geocenter variations) #-- reading degree 1 file for given release if specified if (DEG1 == 'Tellus'): #-- Tellus (PO.DAAC) degree 1 if DREL in ('RL04', 'RL05'): DEG1_file = os.path.join(base_dir, 'geocenter', 'deg1_coef_{0}.txt'.format(DREL)) JPL = False else: DEG1_file = os.path.join( base_dir, 'geocenter', 'TN-13_GEOC_{0}_{1}.txt'.format(PROC, DREL)) JPL = True #-- Running function read_tellus_geocenter.py DEG1_input = read_tellus_geocenter(DEG1_file, JPL=JPL) DEG1_str = '_w{0}_DEG1'.format(DEG1) elif (DEG1 == 'SLR'): #-- CSR Satellite Laser Ranging (SLR) degree 1 # #-- SLR-derived degree-1 mass variations # #-- ftp://ftp.csr.utexas.edu/pub/slr/geocenter/ # DEG1_file=os.path.join(base_dir,'geocenter','GCN_{0}.txt'.format(DREL)) # DEG1_input=aod_corrected_SLR_geocenter(DEG1_file,DREL,HEADER=16, # COLUMNS=['time','X','Y','Z','X_sigma','Y_sigma','Z_sigma']) # #-- new CF-CM file of degree-1 mass variations # #-- https://cddis.nasa.gov/lw20/docs/2016/papers/14-Ries_paper.pdf # #-- http://download.csr.utexas.edu/pub/slr/geocenter/GCN_L1_L2_30d_CF-CM.txt # DEG1_file = os.path.join(base_dir,'geocenter','GCN_L1_L2_30d_CF-CM.txt') # DEG1_input = aod_corrected_SLR_geocenter(DEG1_file,DREL,HEADER=111, # COLUMNS=['time','X','Y','Z','X_sigma','Y_sigma','Z_sigma']) #-- new file of degree-1 mass variations from Minkang Cheng #-- http://download.csr.utexas.edu/outgoing/cheng/gct2est.220_5s DEG1_file = os.path.join(base_dir, 'geocenter', 'gct2est.220_5s') DEG1_input = aod_corrected_SLR_geocenter(DEG1_file, HEADER=15, RADIUS=6.378136e9, COLUMNS=[ 'MJD', 'time', 'X', 'Y', 'Z', 'XM', 'YM', 'ZM', 'X_sigma', 'Y_sigma', 'Z_sigma', 'XM_sigma', 'YM_sigma', 'ZM_sigma' ]) DEG1_str = '_w{0}_DEG1'.format(DEG1) elif (DEG1 == 'SLF'): #-- read iterated degree one files from Sutterley and Velicogna (2019) #-- that includes self-attraction and loading effects #-- include flag for datasets with different GIA corrections MODEL = dict(RL04='OMCT', RL05='OMCT', RL06='MPIOM') args = (PROC, DREL, MODEL[DREL], 'SLF_iter', DEG1_GIA) DEG1_file = os.path.join(base_dir, 'geocenter', '{0}_{1}_{2}_{3}{4}.txt'.format(*args)) DEG1_input = read_GRACE_geocenter(DEG1_file) DEG1_str = '_w{0}_DEG1'.format(DEG1) else: #-- not using a degree 1 file (non-GSM or only using degree 2+) DEG1_str = '' #-- atmospheric flag if correcting ECMWF "jumps" (using GAE/GAF/GAG files) atm_str = '_wATM' if ATM else '' #-- pole tide flag if correcting for pole tide drift (Wahr et al. 2015) pt_str = '_wPT' if POLE_TIDE else '' #-- full output string (C20, C30, geocenter and atmospheric flags) out_str = C20_str + C30_str + DEG1_str + atm_str + pt_str #-- Range of months from start_mon to end_mon (end_mon+1 to include end_mon) #-- Removing the missing months and months not to consider months = sorted(set(np.arange(start_mon, end_mon + 1)) - set(missing)) #-- number of months to consider in analysis n_cons = len(months) #-- Initializing input data matrices grace_clm = np.zeros((LMAX + 1, MMAX + 1, n_cons)) grace_slm = np.zeros((LMAX + 1, MMAX + 1, n_cons)) tdec = np.zeros((n_cons)) mon = np.zeros((n_cons), dtype=np.int) #-- output dimensions lout = np.arange(LMAX + 1) mout = np.arange(MMAX + 1) #-- associate GRACE/GRACE-FO files with each GRACE/GRACE-FO month grace_files = grace_date(base_dir, PROC=PROC, DREL=DREL, DSET=DSET, OUTPUT=False) #-- importing data from GRACE/GRACE-FO files for i, grace_month in enumerate(months): #-- Effects of Pole tide drift will be compensated if soecified infile = grace_files[grace_month] Ylms = read_GRACE_harmonics(infile, LMAX, MMAX=MMAX, POLE_TIDE=POLE_TIDE) grace_clm[:, :, i] = Ylms['clm'][0:LMAX + 1, 0:MMAX + 1] grace_slm[:, :, i] = Ylms['slm'][0:LMAX + 1, 0:MMAX + 1] tdec[i] = Ylms['time'] mon[i] = np.int(grace_month) #-- Replace C20 with SLR coefficients if SLR_C20 in ('CSR', 'GSFC'): #-- verify that there are replacement C20 months for specified range months_test = sorted(set(months) - set(C20_input['month'])) if months_test: gm = ','.join('{0:03d}'.format(gm) for gm in months_test) raise IOError('No Matching C20 Months ({0})'.format(gm)) #-- replace C20 with SLR coefficients for i, grace_month in enumerate(months): count = np.count_nonzero(C20_input['month'] == grace_month) if (count != 0): k, = np.nonzero(C20_input['month'] == grace_month) grace_clm[2, 0, i] = C20_input['data'][k] #-- Replace C30 with SLR coefficients for single-accelerometer months if SLR_C30 in ('CSR', 'GSFC', 'LARES'): #-- verify that there are replacement C30 months for specified range months_test = sorted(set(mon[mon > 176]) - set(C30_input['month'])) if months_test: gm = ','.join('{0:03d}'.format(gm) for gm in months_test) raise IOError('No Matching C30 Months ({0})'.format(gm)) #-- replace C30 with SLR coefficients for i, grace_month in enumerate(months): count = np.count_nonzero(C30_input['month'] == grace_month) if (count != 0) and (grace_month > 176): k, = np.nonzero(C30_input['month'] == grace_month) grace_clm[3, 0, i] = C30_input['data'][k] #-- Use Degree 1 coefficients #-- Tellus: Tellus Degree 1 (PO.DAAC following Sun et al., 2016) #-- SLR: CSR Satellite Laser Ranging (SLR) Degree 1 - GRACE AOD #-- SLF: OMCT/MPIOM coefficients with Sea Level Fingerprint land-water mass if DEG1 in ('Tellus', 'SLR', 'SLF'): #-- check if modeling degree 1 or if all months are available if MODEL_DEG1: #-- least-squares modeling the degree 1 coefficients #-- fitting annual, semi-annual, linear and quadratic terms C10_model = regress_model(DEG1_input['time'], DEG1_input['C10'], tdec, ORDER=2, CYCLES=[0.5, 1.0], RELATIVE=2003.3) C11_model = regress_model(DEG1_input['time'], DEG1_input['C11'], tdec, ORDER=2, CYCLES=[0.5, 1.0], RELATIVE=2003.3) S11_model = regress_model(DEG1_input['time'], DEG1_input['S11'], tdec, ORDER=2, CYCLES=[0.5, 1.0], RELATIVE=2003.3) else: #-- check that all months are available for a given geocenter months_test = sorted(set(months) - set(DEG1_input['month'])) if months_test: gm = ','.join('{0:03d}'.format(gm) for gm in months_test) raise IOError('No Matching Geocenter Months ({0})'.format(gm)) #-- for each considered date for i, grace_month in enumerate(months): k, = np.nonzero(DEG1_input['month'] == grace_month) count = np.count_nonzero(DEG1_input['month'] == grace_month) #-- Degree 1 is missing for particular month if (count == 0) and MODEL_DEG1: #-- using least-squares modeled coefficients from #-- lsq_model_degree_one.py grace_clm[1, 0, i] = C10_model[i] grace_clm[1, 1, i] = C11_model[i] grace_slm[1, 1, i] = S11_model[i] else: #-- using coefficients from data file grace_clm[1, 0, i] = DEG1_input['C10'][k] grace_clm[1, 1, i] = DEG1_input['C11'][k] grace_slm[1, 1, i] = DEG1_input['S11'][k] #-- read and add/remove the GAE and GAF atmospheric correction coefficients if ATM: #-- read ECMWF correction files from Fagiolini et al. (2015) atm_corr = read_ecmwf_corrections(base_dir, LMAX, months, MMAX=MMAX) #-- Removing GAE/GAF/GAG from RL05 GSM Products if (DSET == 'GSM'): for m in range(0, MMAX + 1): #-- MMAX+1 to include l for l in range(m, LMAX + 1): #-- LMAX+1 to include LMAX grace_clm[l, m, :] -= atm_corr['clm'][l, m, :] grace_slm[l, m, :] -= atm_corr['slm'][l, m, :] #-- Adding GAE/GAF/GAG to RL05 Atmospheric Products (GAA,GAC) elif DSET in ('GAC', 'GAA'): for m in range(0, MMAX + 1): #-- MMAX+1 to include l for l in range(m, LMAX + 1): #-- LMAX+1 to include LMAX grace_clm[l, m, :] += atm_corr['clm'][l, m, :] grace_slm[l, m, :] += atm_corr['slm'][l, m, :] return { 'clm': grace_clm, 'slm': grace_slm, 'time': tdec, 'month': mon, 'l': lout, 'm': mout, 'title': out_str, 'directory': grace_dir }
def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, missing, SLR_C20, DEG1, **kwargs): """ Reads GRACE/GRACE-FO files for a spherical harmonic degree and order and a date range Can include geocenter values for degree 1 coefficients Can replace C20 with SLR values for all months Can replace C21,S21,C22,S22,C30,C50 with SLR values for months 179+ Can correct for ECMWF atmospheric "jumps" using GAE/GAF/GAG files Can correct for Pole Tide drift following Wahr et al. (2015) Arguments --------- base_dir: Working data directory for GRACE/GRACE-FO data PROC: (CSR/CNES/JPL/GFZ) data processing center DREL: (RL01/RL02/RL03/RL04/RL05/RL06) data release DSET: (GAA/GAB/GAC/GAD/GSM) data product LMAX: Upper bound of Spherical Harmonic Degrees start_mon: starting month to consider in analysis end_mon: ending month to consider in analysis missing: missing months to not consider in analysis SLR_C20: Replaces C20 with SLR values N: use original values CSR: use values from CSR (TN-07,TN-09,TN-11) GFZ: use values from GFZ GSFC: use values from GSFC (TN-14) DEG1: Use Degree 1 coefficients None: No degree 1 Tellus: GRACE/GRACE-FO TN-13 coefficients from PO.DAAC SLR: satellite laser ranging coefficients from CSR SLF: Sutterley and Velicogna coefficients, Remote Sensing (2019) Swenson: GRACE-derived coefficients from Sean Swenson GFZ: GRACE/GRACE-FO coefficients from GFZ GravIS Keyword arguments ----------------- MMAX: Upper bound of Spherical Harmonic Orders SLR_21: replaces C21 and S21 with SLR values None: use original values CSR: use values from CSR GFZ: use values from GFZ GravIS GSFC: use values from GSFC SLR_22: replaces C22 and S22 with SLR values None: use original values CSR: use values from CSR SLR_C30: replaces C30 with SLR values None: use original values CSR: use values from CSR (5x5 with 6,1) GFZ: use values from GFZ GravIS GSFC: use values from GSFC (TN-14) SLR_C50: replaces C50 with SLR values None: use original values CSR: use values from CSR (5x5 with 6,1) GSFC: use values from GSFC POLE_TIDE: correct GSM data with pole tides following Wahr et al (2015) ATM: correct data with ECMWF "jump" corrections GAE, GAF and GAG DEG1_FILE: full path to degree 1 coefficients file MODEL_DEG1: least-squares model missing degree 1 coefficients Returns ------- clm: GRACE/GRACE-FO cosine spherical harmonics slm: GRACE/GRACE-FO sine spherical harmonics eclm: GRACE/GRACE-FO uncalibrated cosine spherical harmonic errors eslm: GRACE/GRACE-FO uncalibrated sine spherical harmonic errors time: time of each GRACE/GRACE-FO measurement (mid-month) month: GRACE/GRACE-FO months of input datasets l: spherical harmonic degree to LMAX m: spherical harmonic order to MMAX title: string denoting low degree zonals replacement, geocenter usage and corrections directory: directory of exact GRACE/GRACE-FO product """ #-- set default keyword arguments kwargs.setdefault('MMAX', LMAX) kwargs.setdefault('SLR_21', '') kwargs.setdefault('SLR_22', '') kwargs.setdefault('SLR_C30', '') kwargs.setdefault('SLR_C50', '') kwargs.setdefault('DEG1_FILE', None) kwargs.setdefault('MODEL_DEG1', False) kwargs.setdefault('ATM', False) kwargs.setdefault('POLE_TIDE', False) #-- Directory of exact GRACE product grace_dir = os.path.join(base_dir, PROC, DREL, DSET) #-- test if GRACE product directory exists if not os.access(grace_dir, os.F_OK): raise FileNotFoundError(grace_dir) #-- upper bound of spherical harmonic orders (default = LMAX) MMAX = kwargs.get('MMAX') or np.copy(LMAX) #-- Range of months from start_mon to end_mon (end_mon+1 to include end_mon) #-- Removing the missing months and months not to consider months = sorted(set(np.arange(start_mon, end_mon + 1)) - set(missing)) #-- number of months to consider in analysis n_cons = len(months) #-- Initializing input data matrices grace_Ylms = {} grace_Ylms['clm'] = np.zeros((LMAX + 1, MMAX + 1, n_cons)) grace_Ylms['slm'] = np.zeros((LMAX + 1, MMAX + 1, n_cons)) grace_Ylms['eclm'] = np.zeros((LMAX + 1, MMAX + 1, n_cons)) grace_Ylms['eslm'] = np.zeros((LMAX + 1, MMAX + 1, n_cons)) grace_Ylms['time'] = np.zeros((n_cons)) grace_Ylms['month'] = np.zeros((n_cons), dtype=np.int64) #-- output dimensions grace_Ylms['l'] = np.arange(LMAX + 1) grace_Ylms['m'] = np.arange(MMAX + 1) #-- input directory for product grace_Ylms['directory'] = copy.copy(grace_dir) #-- associate GRACE/GRACE-FO files with each GRACE/GRACE-FO month grace_files = grace_date(base_dir, PROC=PROC, DREL=DREL, DSET=DSET, OUTPUT=False) #-- importing data from GRACE/GRACE-FO files for i, grace_month in enumerate(months): #-- read spherical harmonic data products infile = grace_files[grace_month] if PROC in ('GRAZ', 'Swarm'): #-- Degree 2 zonals will be converted to a tide free state Ylms = read_gfc_harmonics(infile, TIDE='tide_free') else: #-- Effects of Pole tide drift will be compensated if specified Ylms = read_GRACE_harmonics(infile, LMAX, MMAX=MMAX, POLE_TIDE=kwargs['POLE_TIDE']) #-- truncate harmonics to degree and order grace_Ylms['clm'][:, :, i] = Ylms['clm'][0:LMAX + 1, 0:MMAX + 1] grace_Ylms['slm'][:, :, i] = Ylms['slm'][0:LMAX + 1, 0:MMAX + 1] #-- truncate harmonic errors to degree and order grace_Ylms['eclm'][:, :, i] = Ylms['eclm'][0:LMAX + 1, 0:MMAX + 1] grace_Ylms['eslm'][:, :, i] = Ylms['eslm'][0:LMAX + 1, 0:MMAX + 1] #-- copy date variables grace_Ylms['time'][i] = np.copy(Ylms['time']) grace_Ylms['month'][i] = np.int64(grace_month) #-- single accelerometer months single_acc_months = np.copy(grace_Ylms['month'][grace_Ylms['month'] > 176]) #-- SLR low-degree harmonic, geocenter and correction flags FLAGS = [] #-- Replacing C2,0 with SLR C2,0 #-- Running function read_SLR_C20.py #-- reading SLR C2,0 file for given release if specified if (SLR_C20 == 'CSR'): if (DREL == 'RL04'): SLR_file = os.path.join(base_dir, 'TN-05_C20_SLR.txt') elif (DREL == 'RL05'): SLR_file = os.path.join(base_dir, 'TN-07_C20_SLR.txt') elif (DREL == 'RL06'): # SLR_file = os.path.join(base_dir,'TN-11_C20_SLR.txt') SLR_file = os.path.join(base_dir, 'C20_RL06.txt') C20_input = read_SLR_C20(SLR_file) FLAGS.append('_wCSR_C20') elif (SLR_C20 == 'GFZ'): SLR_file = os.path.join(base_dir, 'GFZ_{0}_C20_SLR.dat'.format(DREL)) C20_input = read_SLR_C20(SLR_file) FLAGS.append('_wGFZ_C20') elif (SLR_C20 == 'GSFC'): SLR_file = os.path.join(base_dir, 'TN-14_C30_C20_GSFC_SLR.txt') C20_input = read_SLR_C20(SLR_file) FLAGS.append('_wGSFC_C20') #-- Replacing C2,1/S2,1 with SLR #-- Running function read_SLR_CS2.py if (kwargs['SLR_21'] == 'CSR'): SLR_file = os.path.join(base_dir, 'C21_S21_{0}.txt'.format(DREL)) C21_input = read_SLR_CS2(SLR_file) FLAGS.append('_wCSR_21') elif (kwargs['SLR_21'] == 'GFZ'): GravIS_file = 'GRAVIS-2B_GFZOP_GRACE+SLR_LOW_DEGREES_0002.dat' SLR_file = os.path.join(base_dir, GravIS_file) C21_input = read_SLR_CS2(SLR_file) FLAGS.append('_wGFZ_21') elif (kwargs['SLR_21'] == 'GSFC'): #-- calculate monthly averages from 7-day arcs # SLR_file = os.path.join(base_dir,'GSFC_C21_S21.txt') SLR_file = os.path.join(base_dir, 'gsfc_slr_5x5c61s61.txt') C21_input = read_SLR_CS2(SLR_file, DATE=grace_Ylms['time'], ORDER=1) FLAGS.append('_wGSFC_21') #-- Replacing C2,2/S2,2 with SLR #-- Running function read_SLR_CS2.py if (kwargs['SLR_22'] == 'CSR'): SLR_file = os.path.join(base_dir, 'C22_S22_{0}.txt'.format(DREL)) C22_input = read_SLR_CS2(SLR_file) FLAGS.append('_wCSR_22') elif (kwargs['SLR_22'] == 'GSFC'): SLR_file = os.path.join(base_dir, 'gsfc_slr_5x5c61s61.txt') C22_input = read_SLR_CS2(SLR_file, DATE=grace_Ylms['time'], ORDER=2) FLAGS.append('_wGSFC_22') #-- Replacing C3,0 with SLR C3,0 #-- Running function read_SLR_C30.py if (kwargs['SLR_C30'] == 'CSR'): SLR_file = os.path.join(base_dir, 'CSR_Monthly_5x5_Gravity_Harmonics.txt') C30_input = read_SLR_C30(SLR_file) FLAGS.append('_wCSR_C30') elif (kwargs['SLR_C30'] == 'LARES'): SLR_file = os.path.join(base_dir, 'C30_LARES_filtered.txt') C30_input = read_SLR_C30(SLR_file) FLAGS.append('_wLARES_C30') elif (kwargs['SLR_C30'] == 'GSFC'): SLR_file = os.path.join(base_dir, 'TN-14_C30_C20_GSFC_SLR.txt') C30_input = read_SLR_C30(SLR_file) FLAGS.append('_wGSFC_C30') elif (kwargs['SLR_C30'] == 'GFZ'): GravIS_file = 'GRAVIS-2B_GFZOP_GRACE+SLR_LOW_DEGREES_0002.dat' SLR_file = os.path.join(base_dir, GravIS_file) C30_input = read_SLR_C30(SLR_file) FLAGS.append('_wGFZ_C30') #-- Replacing C5,0 with SLR C5,0 #-- Running function read_SLR_C50.py if (kwargs['SLR_C50'] == 'CSR'): SLR_file = os.path.join(base_dir, 'CSR_Monthly_5x5_Gravity_Harmonics.txt') C50_input = read_SLR_C50(SLR_file) FLAGS.append('_wCSR_C50') elif (kwargs['SLR_C50'] == 'LARES'): SLR_file = os.path.join(base_dir, 'C50_LARES_filtered.txt') C50_input = read_SLR_C50(SLR_file) FLAGS.append('_wLARES_C50') elif (kwargs['SLR_C50'] == 'GSFC'): # SLR_file=os.path.join(base_dir,'GSFC_SLR_C20_C30_C50_GSM_replacement.txt') SLR_file = os.path.join(base_dir, 'gsfc_slr_5x5c61s61.txt') C50_input = read_SLR_C50(SLR_file, DATE=grace_Ylms['time']) FLAGS.append('_wGSFC_C50') #-- Correcting for Degree 1 (geocenter variations) #-- reading degree 1 file for given release if specified if (DEG1 == 'Tellus'): #-- Tellus (PO.DAAC) degree 1 if DREL in ('RL04', 'RL05'): #-- old degree one files default_geocenter = os.path.join(base_dir, 'geocenter', 'deg1_coef_{0}.txt'.format(DREL)) JPL = False else: #-- new TN-13 degree one files default_geocenter = os.path.join( base_dir, 'geocenter', 'TN-13_GEOC_{0}_{1}.txt'.format(PROC, DREL)) JPL = True #-- read degree one files from JPL GRACE Tellus DEG1_file = kwargs.get('DEG1_FILE') or default_geocenter DEG1_input = gravity_toolkit.geocenter().from_tellus(DEG1_file, JPL=JPL) FLAGS.append('_w{0}_DEG1'.format(DEG1)) elif (DEG1 == 'SLR'): #-- CSR Satellite Laser Ranging (SLR) degree 1 # #-- SLR-derived degree-1 mass variations # #-- ftp://ftp.csr.utexas.edu/pub/slr/geocenter/ # DEG1_file=os.path.join(base_dir,'geocenter','GCN_{0}.txt'.format(DREL)) # COLUMNS = ['time','X','Y','Z','X_sigma','Y_sigma','Z_sigma'] # DEG1_input = gravity_toolkit.geocenter().from_SLR(DEG1_file, # AOD=True, release=DREL, header=16, COLUMNS=COLUMNS) # #-- new CF-CM file of degree-1 mass variations # #-- https://cddis.nasa.gov/lw20/docs/2016/papers/14-Ries_paper.pdf # #-- http://download.csr.utexas.edu/pub/slr/geocenter/GCN_L1_L2_30d_CF-CM.txt # DEG1_file = os.path.join(base_dir,'geocenter','GCN_L1_L2_30d_CF-CM.txt') # COLUMNS = ['time','X','Y','Z','X_sigma','Y_sigma','Z_sigma'] # DEG1_input = gravity_toolkit.geocenter().from_SLR(DEG1_file, # AOD=True, release=DREL, header=111, columns=COLUMNS) #-- new file of degree-1 mass variations from Minkang Cheng #-- http://download.csr.utexas.edu/outgoing/cheng/gct2est.220_5s DEG1_file = os.path.join(base_dir, 'geocenter', 'gct2est.220_5s') COLUMNS = [ 'MJD', 'time', 'X', 'Y', 'Z', 'XM', 'YM', 'ZM', 'X_sigma', 'Y_sigma', 'Z_sigma', 'XM_sigma', 'YM_sigma', 'ZM_sigma' ] #-- read degree one files from CSR satellite laser ranging DEG1_input = gravity_toolkit.geocenter(radius=6.378136e9).from_SLR( DEG1_file, AOD=True, release=DREL, header=15, columns=COLUMNS) FLAGS.append('_w{0}_DEG1'.format(DEG1)) elif (DEG1 == 'SLF'): #-- degree one files from Sutterley and Velicogna (2019) #-- default: iterated and with self-attraction and loading effects MODEL = dict(RL04='OMCT', RL05='OMCT', RL06='MPIOM') args = (PROC, DREL, MODEL[DREL], 'SLF_iter') default_geocenter = os.path.join(base_dir, 'geocenter', '{0}_{1}_{2}_{3}.txt'.format(*args)) #-- read degree one files from Sutterley and Velicogna (2019) DEG1_file = kwargs.get('DEG1_FILE') or default_geocenter DEG1_input = gravity_toolkit.geocenter().from_UCI(DEG1_file) FLAGS.append('_w{0}_DEG1'.format(DEG1)) elif (DEG1 == 'Swenson'): #-- degree 1 coefficients provided by Sean Swenson in mm w.e. default_geocenter = os.path.join(base_dir, 'geocenter', 'gad_gsm.{0}.txt'.format(DREL)) #-- read degree one files from Swenson et al. (2008) DEG1_file = kwargs.get('DEG1_FILE') or default_geocenter DEG1_input = gravity_toolkit.geocenter().from_swenson(DEG1_file) FLAGS.append('_w{0}_DEG1'.format(DEG1)) elif (DEG1 == 'GFZ'): #-- degree 1 coefficients provided by GFZ GravIS #-- http://gravis.gfz-potsdam.de/corrections default_geocenter = os.path.join(base_dir, 'geocenter', 'GRAVIS-2B_GFZOP_GEOCENTER_0002.dat') #-- read degree one files from GFZ GravIS DEG1_file = kwargs.get('DEG1_FILE') or default_geocenter DEG1_input = gravity_toolkit.geocenter().from_gravis(DEG1_file) FLAGS.append('_w{0}_DEG1'.format(DEG1)) #-- atmospheric flag if correcting ECMWF "jumps" (using GAE/GAF/GAG files) if kwargs['ATM']: FLAGS.append('_wATM') #-- pole tide flag if correcting for pole tide drift (Wahr et al. 2015) if kwargs['POLE_TIDE']: FLAGS.append('_wPT') #-- full output string (SLR, geocenter and correction flags) grace_Ylms['title'] = ''.join(FLAGS) #-- Replace C20 with SLR coefficients if SLR_C20 in ('CSR', 'GFZ', 'GSFC'): #-- verify that there are replacement C20 months for specified range months_test = sorted(set(months) - set(C20_input['month'])) if months_test: gm = ','.join('{0:03d}'.format(gm) for gm in months_test) raise IOError('No Matching C20 Months ({0})'.format(gm)) #-- replace C20 with SLR coefficients for i, grace_month in enumerate(months): count = np.count_nonzero(C20_input['month'] == grace_month) if (count != 0): k, = np.nonzero(C20_input['month'] == grace_month) grace_Ylms['clm'][2, 0, i] = np.copy(C20_input['data'][k]) grace_Ylms['eclm'][2, 0, i] = np.copy(C20_input['error'][k]) #-- Replace C21/S21 with SLR coefficients for single-accelerometer months if kwargs['SLR_21'] in ('CSR', 'GFZ', 'GSFC'): #-- verify that there are replacement C21/S21 months for specified range months_test = sorted(set(single_acc_months) - set(C21_input['month'])) if months_test: gm = ','.join('{0:03d}'.format(gm) for gm in months_test) raise IOError('No Matching C21/S21 Months ({0})'.format(gm)) #-- replace C21/S21 with SLR coefficients for i, grace_month in enumerate(months): count = np.count_nonzero(C21_input['month'] == grace_month) if (count != 0) and (grace_month > 176): k, = np.nonzero(C21_input['month'] == grace_month) grace_Ylms['clm'][2, 1, i] = np.copy(C21_input['C2m'][k]) grace_Ylms['slm'][2, 1, i] = np.copy(C21_input['S2m'][k]) grace_Ylms['eclm'][2, 1, i] = np.copy(C21_input['eC2m'][k]) grace_Ylms['eslm'][2, 1, i] = np.copy(C21_input['eS2m'][k]) #-- Replace C22/S22 with SLR coefficients for single-accelerometer months if kwargs['SLR_22'] in ('CSR', 'GSFC'): #-- verify that there are replacement C22/S22 months for specified range months_test = sorted(set(single_acc_months) - set(C22_input['month'])) if months_test: gm = ','.join('{0:03d}'.format(gm) for gm in months_test) raise IOError('No Matching C22/S22 Months ({0})'.format(gm)) #-- replace C22/S22 with SLR coefficients for i, grace_month in enumerate(months): count = np.count_nonzero(C22_input['month'] == grace_month) if (count != 0) and (grace_month > 176): k, = np.nonzero(C22_input['month'] == grace_month) grace_Ylms['clm'][2, 2, i] = np.copy(C22_input['C2m'][k]) grace_Ylms['slm'][2, 2, i] = np.copy(C22_input['S2m'][k]) grace_Ylms['eclm'][2, 2, i] = np.copy(C22_input['eC2m'][k]) grace_Ylms['eslm'][2, 2, i] = np.copy(C22_input['eS2m'][k]) #-- Replace C30 with SLR coefficients for single-accelerometer months if kwargs['SLR_C30'] in ('CSR', 'GFZ', 'GSFC', 'LARES'): #-- verify that there are replacement C30 months for specified range months_test = sorted(set(single_acc_months) - set(C30_input['month'])) if months_test: gm = ','.join('{0:03d}'.format(gm) for gm in months_test) raise IOError('No Matching C30 Months ({0})'.format(gm)) #-- replace C30 with SLR coefficients for i, grace_month in enumerate(months): count = np.count_nonzero(C30_input['month'] == grace_month) if (count != 0) and (grace_month > 176): k, = np.nonzero(C30_input['month'] == grace_month) grace_Ylms['clm'][3, 0, i] = np.copy(C30_input['data'][k]) grace_Ylms['eclm'][3, 0, i] = np.copy(C30_input['error'][k]) #-- Replace C50 with SLR coefficients for single-accelerometer months if kwargs['SLR_C50'] in ('CSR', 'GSFC', 'LARES'): #-- verify that there are replacement C50 months for specified range months_test = sorted(set(single_acc_months) - set(C50_input['month'])) if months_test: gm = ','.join('{0:03d}'.format(gm) for gm in months_test) raise IOError('No Matching C50 Months ({0})'.format(gm)) #-- replace C50 with SLR coefficients for i, grace_month in enumerate(months): count = np.count_nonzero(C50_input['month'] == grace_month) if (count != 0) and (grace_month > 176): k, = np.nonzero(C50_input['month'] == grace_month) grace_Ylms['clm'][5, 0, i] = np.copy(C50_input['data'][k]) grace_Ylms['eclm'][5, 0, i] = np.copy(C50_input['error'][k]) #-- Use Degree 1 coefficients #-- Tellus: Tellus Degree 1 (PO.DAAC following Sun et al., 2016) #-- SLR: CSR Satellite Laser Ranging (SLR) Degree 1 - GRACE AOD #-- SLF: OMCT/MPIOM coefficients with Sea Level Fingerprint land-water mass #-- Swenson: GRACE-derived coefficients from Sean Swenson #-- GFZ: GRACE/GRACE-FO coefficients from GFZ GravIS if DEG1 in ('Tellus', 'SLR', 'SLF', 'Swenson', 'GFZ'): #-- check if modeling degree 1 or if all months are available if kwargs['MODEL_DEG1']: #-- least-squares modeling the degree 1 coefficients #-- fitting annual, semi-annual, linear and quadratic terms C10_model = regress_model(DEG1_input.time, DEG1_input.C10, grace_Ylms['time'], ORDER=2, CYCLES=[0.5, 1.0], RELATIVE=2003.3) C11_model = regress_model(DEG1_input.time, DEG1_input.C11, grace_Ylms['time'], ORDER=2, CYCLES=[0.5, 1.0], RELATIVE=2003.3) S11_model = regress_model(DEG1_input.time, DEG1_input.S11, grace_Ylms['time'], ORDER=2, CYCLES=[0.5, 1.0], RELATIVE=2003.3) else: #-- check that all months are available for a given geocenter months_test = sorted(set(months) - set(DEG1_input.month)) if months_test: gm = ','.join('{0:03d}'.format(gm) for gm in months_test) raise IOError('No Matching Geocenter Months ({0})'.format(gm)) #-- for each considered date for i, grace_month in enumerate(months): k, = np.nonzero(DEG1_input.month == grace_month) count = np.count_nonzero(DEG1_input.month == grace_month) #-- Degree 1 is missing for particular month if (count == 0) and kwargs['MODEL_DEG1']: #-- using least-squares modeled coefficients from regress_model grace_Ylms['clm'][1, 0, i] = np.copy(C10_model[i]) grace_Ylms['clm'][1, 1, i] = np.copy(C11_model[i]) grace_Ylms['slm'][1, 1, i] = np.copy(S11_model[i]) else: #-- using coefficients from data file grace_Ylms['clm'][1, 0, i] = np.copy(DEG1_input.C10[k]) grace_Ylms['clm'][1, 1, i] = np.copy(DEG1_input.C11[k]) grace_Ylms['slm'][1, 1, i] = np.copy(DEG1_input.S11[k]) #-- read and add/remove the GAE and GAF atmospheric correction coefficients if kwargs['ATM']: #-- read ECMWF correction files from Fagiolini et al. (2015) atm_corr = read_ecmwf_corrections(base_dir, LMAX, months, MMAX=MMAX) #-- Removing GAE/GAF/GAG from RL05 GSM Products if (DSET == 'GSM'): for m in range(0, MMAX + 1): #-- MMAX+1 to include l for l in range(m, LMAX + 1): #-- LMAX+1 to include LMAX grace_Ylms['clm'][l, m, :] -= atm_corr['clm'][l, m, :] grace_Ylms['slm'][l, m, :] -= atm_corr['slm'][l, m, :] #-- Adding GAE/GAF/GAG to RL05 Atmospheric Products (GAA,GAC) elif DSET in ('GAC', 'GAA'): for m in range(0, MMAX + 1): #-- MMAX+1 to include l for l in range(m, LMAX + 1): #-- LMAX+1 to include LMAX grace_Ylms['clm'][l, m, :] += atm_corr['clm'][l, m, :] grace_Ylms['slm'][l, m, :] += atm_corr['slm'][l, m, :] #-- return the harmonic solutions with possible low-degree replacements #-- return the harmonic dimensions (spectral and temporal) #-- return string specifying processing and correction flags #-- return directory of exact GRACE/GRACE-FO product return grace_Ylms