diff --git a/doc/source/user_guide/calc_mascon.rst b/doc/source/user_guide/calc_mascon.rst index 90117307..8b54d5e0 100644 --- a/doc/source/user_guide/calc_mascon.rst +++ b/doc/source/user_guide/calc_mascon.rst @@ -74,6 +74,8 @@ Command Line Options * ``'SLF'``: Sutterley and Velicogna coefficients, Remote Sensing (2019) * ``'Swenson'``: GRACE-derived coefficients from Sean Swenson * ``'GFZ'``: GRACE/SLR derived coefficients from GFZ GravIS +- ``--geocenter-file X``: Specific geocenter file if not default +- ``--interpolate-geocenter``: Least-squares model missing Degree 1 coefficients - ``--slr-c20 X``: Replace *C*\ :sub:`20` coefficients with SLR values * ``None``: use original values diff --git a/doc/source/user_guide/grace_mean_harmonics.rst b/doc/source/user_guide/grace_mean_harmonics.rst index c0297614..2a959a5d 100644 --- a/doc/source/user_guide/grace_mean_harmonics.rst +++ b/doc/source/user_guide/grace_mean_harmonics.rst @@ -37,6 +37,8 @@ Command Line Options * ``'SLF'``: Sutterley and Velicogna coefficients, Remote Sensing (2019) * ``'Swenson'``: GRACE-derived coefficients from Sean Swenson * ``'GFZ'``: GRACE/SLR derived coefficients from GFZ GravIS +- ``--geocenter-file X``: Specific geocenter file if not default +- ``--interpolate-geocenter``: Least-squares model missing Degree 1 coefficients - ``--slr-c20 X``: Replace *C*\ :sub:`20` coefficients with SLR values * ``None``: use original values diff --git a/doc/source/user_guide/grace_spatial_error.rst b/doc/source/user_guide/grace_spatial_error.rst index ed8a7314..99a0837b 100644 --- a/doc/source/user_guide/grace_spatial_error.rst +++ b/doc/source/user_guide/grace_spatial_error.rst @@ -59,6 +59,7 @@ Command Line Options * ``'SLF'``: Sutterley and Velicogna coefficients, Remote Sensing (2019) * ``'Swenson'``: GRACE-derived coefficients from Sean Swenson * ``'GFZ'``: GRACE/SLR derived coefficients from GFZ GravIS +- ``--geocenter-file X``: Specific geocenter file if not default - ``--interpolate-geocenter``: Least-squares model missing Degree 1 coefficients - ``--slr-c20 X``: Replace *C*\ :sub:`20` coefficients with SLR values diff --git a/doc/source/user_guide/grace_spatial_maps.rst b/doc/source/user_guide/grace_spatial_maps.rst index 2256051e..5b0dc9c2 100644 --- a/doc/source/user_guide/grace_spatial_maps.rst +++ b/doc/source/user_guide/grace_spatial_maps.rst @@ -74,6 +74,7 @@ Command Line Options * ``'SLF'``: Sutterley and Velicogna coefficients, Remote Sensing (2019) * ``'Swenson'``: GRACE-derived coefficients from Sean Swenson * ``'GFZ'``: GRACE/SLR derived coefficients from GFZ GravIS +- ``--geocenter-file X``: Specific geocenter file if not default - ``--interpolate-geocenter``: Least-squares model missing Degree 1 coefficients - ``--slr-c20 X``: Replace *C*\ :sub:`20` coefficients with SLR values diff --git a/doc/source/user_guide/scale_grace_maps.rst b/doc/source/user_guide/scale_grace_maps.rst index 6e65c8b6..f0c61242 100644 --- a/doc/source/user_guide/scale_grace_maps.rst +++ b/doc/source/user_guide/scale_grace_maps.rst @@ -76,6 +76,7 @@ Command Line Options * ``'SLF'``: Sutterley and Velicogna coefficients, Remote Sensing (2019) * ``'Swenson'``: GRACE-derived coefficients from Sean Swenson * ``'GFZ'``: GRACE/SLR derived coefficients from GFZ GravIS +- ``--geocenter-file X``: Specific geocenter file if not default - ``--interpolate-geocenter``: Least-squares model missing Degree 1 coefficients - ``--slr-c20 X``: Replace *C*\ :sub:`20` coefficients with SLR values diff --git a/gravity_toolkit/__init__.py b/gravity_toolkit/__init__.py index 1e8bb57c..c6b1cf15 100644 --- a/gravity_toolkit/__init__.py +++ b/gravity_toolkit/__init__.py @@ -62,7 +62,7 @@ from gravity_toolkit.read_SLR_CS2 import read_SLR_CS2 from gravity_toolkit.read_SLR_C30 import read_SLR_C30 from gravity_toolkit.read_SLR_C50 import read_SLR_C50 -from gravity_toolkit.read_SLR_harmonics import read_SLR_harmonics +from gravity_toolkit.read_SLR_harmonics import read_SLR_harmonics, convert_weekly from gravity_toolkit.savitzky_golay import savitzky_golay from gravity_toolkit.spatial import spatial from gravity_toolkit.tsamplitude import tsamplitude diff --git a/gravity_toolkit/geocenter.py b/gravity_toolkit/geocenter.py index 5af567e8..df71b681 100644 --- a/gravity_toolkit/geocenter.py +++ b/gravity_toolkit/geocenter.py @@ -16,6 +16,8 @@ UPDATE HISTORY: Updated 12/2021: added netCDF4 reader for UCI iteration files + add cartesian and surface mass density conversions for errors + logging case_insensitive_filename output for debugging Updated 11/2021: converted to class with all data readers and converters Updated 07/2020: added function docstrings Updated 06/2019: added option RADIUS to manually set the Earth's radius @@ -31,6 +33,7 @@ import gzip import time import uuid +import logging import netCDF4 import numpy as np import gravity_toolkit.time @@ -85,6 +88,8 @@ def case_insensitive_filename(self,filename): errmsg = '{0} not found in file system'.format(filename) raise FileNotFoundError(errmsg) self.filename = os.path.join(directory,f.pop()) + #-- print filename + logging.debug(self.filename) return self #-- PURPOSE: read AOD1b geocenter for month and calculate the mean harmonics @@ -734,7 +739,7 @@ def from_dict(self, temp, **kwargs): #-- set default keyword arguments kwargs.setdefault('fields',['time','month', 'C10','C11','S11','eC10','eC11','eS11', - 'X','Y','Z']) + 'X','Y','Z','X_sigma','Y_sigma','Z_sigma']) #-- assign dictionary variables to self for key in kwargs['fields']: try: @@ -809,7 +814,7 @@ def to_dict(self, **kwargs): #-- set default keyword arguments kwargs.setdefault('fields',['time','month', 'C10','C11','S11','eC10','eC11','eS11', - 'X','Y','Z']) + 'X','Y','Z','X_sigma','Y_sigma','Z_sigma']) #-- assign dictionary variables to self for key in kwargs['fields']: try: @@ -844,10 +849,20 @@ def to_cartesian(self, kl=0.0): ----------------- kl: gravitational load love number of degree 1 """ - #-- Stokes Coefficients to geocenter - self.Z = self.C10*self.radius*np.sqrt(3.0)/(1.0 + kl) - self.X = self.C11*self.radius*np.sqrt(3.0)/(1.0 + kl) - self.Y = self.S11*self.radius*np.sqrt(3.0)/(1.0 + kl) + #-- Stokes Coefficients to cartesian geocenter + try: + self.Z = self.C10*self.radius*np.sqrt(3.0)/(1.0 + kl) + self.X = self.C11*self.radius*np.sqrt(3.0)/(1.0 + kl) + self.Y = self.S11*self.radius*np.sqrt(3.0)/(1.0 + kl) + except Exception as e: + pass + #-- convert errors to cartesian geocenter + try: + self.Z_sigma = self.eC10*self.radius*np.sqrt(3.0)/(1.0 + kl) + self.X_sigma = self.eC11*self.radius*np.sqrt(3.0)/(1.0 + kl) + self.Y_sigma = self.eS11*self.radius*np.sqrt(3.0)/(1.0 + kl) + except Exception as e: + pass return self def to_cmwe(self, kl=0.0): @@ -866,6 +881,13 @@ def to_cmwe(self, kl=0.0): self.C10 *= (rho_e*rad_e)/(1.0 + kl) self.C11 *= (rho_e*rad_e)/(1.0 + kl) self.S11 *= (rho_e*rad_e)/(1.0 + kl) + #-- convert errors to centimeters water equivalent + try: + self.eC10 *= (rho_e*rad_e)/(1.0 + kl) + self.eC11 *= (rho_e*rad_e)/(1.0 + kl) + self.eS11 *= (rho_e*rad_e)/(1.0 + kl) + except Exception as e: + pass return self def to_mmwe(self, kl=0.0): @@ -881,6 +903,13 @@ def to_mmwe(self, kl=0.0): self.C10 *= 10.0 self.C11 *= 10.0 self.S11 *= 10.0 + #-- convert errors to millimeters water equivalent + try: + self.eC10 *= 10.0 + self.eC11 *= 10.0 + self.eS11 *= 10.0 + except Exception as e: + pass return self def from_cartesian(self, kl=0.0): @@ -891,10 +920,17 @@ def from_cartesian(self, kl=0.0): ----------------- kl: gravitational load love number of degree 1 """ - #-- geocenter to Stokes Coefficients + #-- cartesian geocenter to Stokes Coefficients self.C10 = (1.0 + kl)*self.Z/(self.radius*np.sqrt(3.0)) self.C11 = (1.0 + kl)*self.X/(self.radius*np.sqrt(3.0)) self.S11 = (1.0 + kl)*self.Y/(self.radius*np.sqrt(3.0)) + #-- convert cartesian geocenter to stokes coefficients + try: + self.eC10 = (1.0 + kl)*self.Z_sigma/(self.radius*np.sqrt(3.0)) + self.eC11 = (1.0 + kl)*self.X_sigma/(self.radius*np.sqrt(3.0)) + self.eS11 = (1.0 + kl)*self.Y_sigma/(self.radius*np.sqrt(3.0)) + except Exception as e: + pass return self def from_cmwe(self, kl=0.0): @@ -913,6 +949,13 @@ def from_cmwe(self, kl=0.0): self.C10 *= (1.0 + kl)/(rho_e*rad_e) self.C11 *= (1.0 + kl)/(rho_e*rad_e) self.S11 *= (1.0 + kl)/(rho_e*rad_e) + #-- convert errors from centimeters water equivalent + try: + self.eC10 *= (1.0 + kl)/(rho_e*rad_e) + self.eC11 *= (1.0 + kl)/(rho_e*rad_e) + self.eS11 *= (1.0 + kl)/(rho_e*rad_e) + except Exception as e: + pass return self def from_mmwe(self, kl=0.0): @@ -928,6 +971,13 @@ def from_mmwe(self, kl=0.0): self.C10 /= 10.0 self.C11 /= 10.0 self.S11 /= 10.0 + #-- convert errors from centimeters water equivalent + try: + self.eC10 /= 10.0 + self.eC11 /= 10.0 + self.eS11 /= 10.0 + except Exception as e: + pass return self def mean(self, apply=False, indices=Ellipsis): diff --git a/gravity_toolkit/grace_input_months.py b/gravity_toolkit/grace_input_months.py index cb4564a6..98754d38 100644 --- a/gravity_toolkit/grace_input_months.py +++ b/gravity_toolkit/grace_input_months.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" grace_input_months.py -Written by Tyler Sutterley (11/2021) +Written by Tyler Sutterley (12/2021) Contributions by Hugo Lecomte and Yara Mohajerani Reads GRACE/GRACE-FO files for a specified spherical harmonic degree and order @@ -85,7 +85,7 @@ 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 + DEG1_FILE: full path to (non-default) degree 1 coefficients file PYTHON DEPENDENCIES: numpy: Scientific Computing Tools For Python @@ -105,6 +105,7 @@ read_gfc_harmonics.py: reads spherical harmonic data from gfc files UPDATE HISTORY: + Updated 12/2021: option to specify a specific geocenter correction file Updated 11/2021: add GSFC low-degree harmonics use gravity_toolkit geocenter class for operations Updated 09/2021: added time-variable gravity data from GRAZ and Swarm @@ -170,8 +171,7 @@ from gravity_toolkit.read_gfc_harmonics import read_gfc_harmonics def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, - missing, SLR_C20, DEG1, MMAX=None, SLR_21='', SLR_22='', SLR_C30='', - SLR_C50='', MODEL_DEG1=False, DEG1_GIA='', ATM=False, POLE_TIDE=False): + missing, SLR_C20, DEG1, **kwargs): """ Reads GRACE/GRACE-FO files for a spherical harmonic degree and order and a date range @@ -226,8 +226,8 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, 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 - MODEL_DEG1: least-squares model missing degree 1 coefficients (True/False) - DEG1_GIA: GIA-correction used when calculating degree 1 coefficients + DEG1_FILE: full path to degree 1 coefficients file + MODEL_DEG1: least-squares model missing degree 1 coefficients Returns ------- @@ -242,6 +242,16 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, 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) @@ -250,7 +260,7 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, raise FileNotFoundError(grace_dir) #-- upper bound of spherical harmonic orders (default = LMAX) - MMAX = np.copy(LMAX) if (MMAX is None) else MMAX + 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 @@ -285,7 +295,7 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, else: #-- Effects of Pole tide drift will be compensated if specified Ylms = read_GRACE_harmonics(infile, LMAX, MMAX=MMAX, - POLE_TIDE=POLE_TIDE) + 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] @@ -325,16 +335,16 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, #-- Replacing C2,1/S2,1 with SLR #-- Running function read_SLR_CS2.py - if (SLR_21 == 'CSR'): + 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 (SLR_21 == 'GFZ'): + 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 (SLR_21 == 'GSFC'): + 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') @@ -343,30 +353,30 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, #-- Replacing C2,2/S2,2 with SLR #-- Running function read_SLR_CS2.py - if (SLR_22 == 'CSR'): + 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 (SLR_22 == 'GSFC'): + 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 (SLR_C30 == 'CSR'): + 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 (SLR_C30 == 'LARES'): + 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 (SLR_C30 == 'GSFC'): + 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 (SLR_C30 == 'GFZ'): + 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) @@ -374,15 +384,15 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, #-- Replacing C5,0 with SLR C5,0 #-- Running function read_SLR_C50.py - if (SLR_C50 == 'CSR'): + 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 (SLR_C50 == 'LARES'): + 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 (SLR_C50 == 'GSFC'): + 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']) @@ -393,14 +403,17 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, if (DEG1 == 'Tellus'): #-- Tellus (PO.DAAC) degree 1 if DREL in ('RL04','RL05'): - DEG1_file = os.path.join(base_dir,'geocenter', + #-- old degree one files + default_geocenter = os.path.join(base_dir,'geocenter', 'deg1_coef_{0}.txt'.format(DREL)) JPL = False else: - DEG1_file = os.path.join(base_dir,'geocenter', + #-- 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 - #-- Running function read_tellus_geocenter.py + #-- 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'): @@ -425,40 +438,44 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, 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'): - #-- 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 + #-- 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',DEG1_GIA) - DEG1_file = os.path.join(base_dir,'geocenter', - '{0}_{1}_{2}_{3}{4}.txt'.format(*args)) + 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. - DEG1_file = os.path.join(base_dir,'geocenter', + default_geocenter = os.path.join(base_dir,'geocenter', 'gad_gsm.{0}.txt'.format(DREL)) - #-- Running function read_swenson_geocenter.py + #-- 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 - DEG1_file = os.path.join(base_dir,'geocenter', + default_geocenter = os.path.join(base_dir,'geocenter', 'GRAVIS-2B_GFZOP_GEOCENTER_0002.dat') - #-- Running function read_gravis_geocenter.py + #-- 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 ATM: + if kwargs['ATM']: FLAGS.append('_wATM') #-- pole tide flag if correcting for pole tide drift (Wahr et al. 2015) - if POLE_TIDE: + if kwargs['POLE_TIDE']: FLAGS.append('_wPT') #-- full output string (SLR, geocenter and correction flags) grace_Ylms['title'] = ''.join(FLAGS) @@ -479,7 +496,7 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, grace_Ylms['eclm'][2,0,i] = np.copy(C20_input['error'][k]) #-- Replace C21/S21 with SLR coefficients for single-accelerometer months - if SLR_21 in ('CSR','GFZ','GSFC'): + 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: @@ -496,7 +513,7 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, grace_Ylms['eslm'][2,1,i] = np.copy(C21_input['eS2m'][k]) #-- Replace C22/S22 with SLR coefficients for single-accelerometer months - if SLR_22 in ('CSR','GSFC'): + 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: @@ -513,7 +530,7 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, grace_Ylms['eslm'][2,2,i] = np.copy(C22_input['eS2m'][k]) #-- Replace C30 with SLR coefficients for single-accelerometer months - if SLR_C30 in ('CSR','GFZ','GSFC','LARES'): + 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: @@ -528,7 +545,7 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, grace_Ylms['eclm'][3,0,i] = np.copy(C30_input['error'][k]) #-- Replace C50 with SLR coefficients for single-accelerometer months - if SLR_C50 in ('CSR','GSFC','LARES'): + 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: @@ -550,7 +567,7 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, #-- 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 MODEL_DEG1: + 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, @@ -570,7 +587,7 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, 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: + 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]) @@ -581,7 +598,7 @@ def grace_input_months(base_dir, PROC, DREL, DSET, LMAX, start_mon, end_mon, grace_Ylms['slm'][1,1,i] = np.copy(DEG1_input.S11[k]) #-- read and add/remove the GAE and GAF atmospheric correction coefficients - if ATM: + 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 diff --git a/gravity_toolkit/harmonics.py b/gravity_toolkit/harmonics.py index 2d216fed..e9d8f239 100644 --- a/gravity_toolkit/harmonics.py +++ b/gravity_toolkit/harmonics.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" harmonics.py -Written by Tyler Sutterley (11/2021) +Written by Tyler Sutterley (12/2021) Contributions by Hugo Lecomte Spherical harmonic data class for processing GRACE/GRACE-FO Level-2 data @@ -29,6 +29,7 @@ destripe_harmonics.py: filters spherical harmonics for correlated errors UPDATE HISTORY: + Updated 12/2021: logging case_insensitive_filename output for debugging Updated 11/2021: kwargs to index, netCDF4 and HDF5 read functions Updated 10/2021: using python logging for handling verbose output Updated 09/2021: added time-variable gravity data from gfc format @@ -120,6 +121,8 @@ def case_insensitive_filename(self,filename): errmsg = '{0} not found in file system'.format(filename) raise FileNotFoundError(errmsg) self.filename = os.path.join(directory,f.pop()) + #-- print filename + logging.debug(self.filename) return self def from_ascii(self, filename, **kwargs): diff --git a/gravity_toolkit/read_SLR_C50.py b/gravity_toolkit/read_SLR_C50.py index e9f6eb0a..355e3eaf 100644 --- a/gravity_toolkit/read_SLR_C50.py +++ b/gravity_toolkit/read_SLR_C50.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" read_SLR_C50.py -Written by Yara Mohajerani and Tyler Sutterley (11/2021) +Written by Yara Mohajerani and Tyler Sutterley (12/2021) Reads monthly degree 5 zonal spherical harmonic data files from SLR @@ -45,6 +45,7 @@ read_SLR_harmonics.py: low-degree spherical harmonic coefficients from SLR UPDATE HISTORY: + Updated 12/2021: use function for converting from 7-day arcs Updated 11/2021: reader for new weekly 5x5+6,1 fields from NASA GSFC Updated 09/2021: use functions for converting to and from GRACE months Updated 05/2021: simplified program similar to other SLR readers @@ -152,24 +153,11 @@ def read_SLR_C50(SLR_file, HEADER=True, C50_MEAN=0.0, DATE=None): elif bool(re.search(r'gsfc_slr_5x5c61s61',SLR_file,re.I)): #-- read 5x5 + 6,1 file from GSFC and extract coefficients Ylms = gravity_toolkit.read_SLR_harmonics(SLR_file, HEADER=True) - #-- duplicate time and harmonics - tdec = np.repeat(Ylms['time'],7) - c50 = np.repeat(Ylms['clm'][5,0],7) - #-- calculate daily dates to use in centered moving average - tdec += (np.mod(np.arange(len(tdec)),7) - 3.5)/365.25 - #-- number of dates to use in average - n_neighbors = 28 #-- calculate 28-day moving-average solution from 7-day arcs - dinput['time'] = np.zeros_like(DATE) - dinput['data'] = np.zeros_like(DATE,dtype='f8') + dinput.update(gravity_toolkit.convert_weekly(Ylms['time'], + Ylms['clm'][5,0,:], DATE=DATE, NEIGHBORS=28)) #-- no estimated spherical harmonic errors dinput['error'] = np.zeros_like(DATE,dtype='f8') - for i,D in enumerate(DATE): - isort = np.argsort((tdec - D)**2)[:n_neighbors] - dinput['time'][i] = np.mean(tdec[isort]) - dinput['data'][i] = np.mean(c50[isort]) - #-- GRACE/GRACE-FO month - dinput['month'] = gravity_toolkit.time.calendar_to_grace(dinput['time']) elif bool(re.search(r'C50_LARES',SLR_file,re.I)): #-- read LARES filtered values LARES_input = np.loadtxt(SLR_file,skiprows=1) diff --git a/gravity_toolkit/read_SLR_harmonics.py b/gravity_toolkit/read_SLR_harmonics.py index 68b73344..8f324d63 100644 --- a/gravity_toolkit/read_SLR_harmonics.py +++ b/gravity_toolkit/read_SLR_harmonics.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" read_SLR_harmonics.py -Written by Tyler Sutterley (11/2021) +Written by Tyler Sutterley (12/2021) Reads in low-degree spherical harmonic coefficients calculated from Satellite Laser Ranging (SLR) measurements @@ -50,6 +50,7 @@ time.py: utilities for calculating time operations UPDATE HISTORY: + Updated 12/2021: added function for converting from 7-day arcs Updated 11/2021: renamed module. added reader for GSFC weekly 5x5 fields Updated 05/2021: define int/float precision to prevent deprecation warning Updated 04/2021: renamed module. new SLR 5x5 format from CSR (see notes) @@ -296,3 +297,46 @@ def read_GSFC_weekly_6x1(input_file, SCALE=1.0, HEADER=True): #-- return spherical harmonic fields and date information return Ylms + +#-- PURPOSE: interpolate harmonics from 7-day to monthly +def convert_weekly(t_in, d_in, DATE=[], NEIGHBORS=28): + """ + Interpolate harmonics from 7-day to 28-day + + Arguments + --------- + t_in: weekly time + d_in: weekly harmonics + + Keyword arguments + ----------------- + DATE: output monthly time for central averages + NEIGHBORS: number of days to use in average + + Returns + ------- + time: output date in year-decimal + month: GRACE/GRACE-FO month + data: monthly spherical harmonic coefficients + """ + #-- duplicate time and harmonics + tdec = np.repeat(t_in,7) + data = np.repeat(d_in,7) + #-- calculate daily dates to use in centered moving average + tdec += (np.mod(np.arange(len(tdec)),7) - 3.5)/365.25 + #-- calculate moving-average solution from 7-day arcs + dinput = {} + dinput['time'] = np.zeros_like(DATE) + dinput['data'] = np.zeros_like(DATE,dtype='f8') + #-- for each output monthly date + for i,D in enumerate(DATE): + #-- find all dates within NEIGHBORS days of mid-point + isort = np.argsort((tdec - D)**2)[:NEIGHBORS] + #-- calculate monthly mean of date and data + dinput['time'][i] = np.mean(tdec[isort]) + dinput['data'][i] = np.mean(data[isort]) + #-- GRACE/GRACE-FO month + dinput['month'] = gravity_toolkit.time.calendar_to_grace(dinput['time']) + dinput['month'] = gravity_toolkit.time.adjust_months(dinput['month']) + #-- return the moving averages + return dinput diff --git a/gravity_toolkit/spatial.py b/gravity_toolkit/spatial.py index 6883fac1..b47983cb 100644 --- a/gravity_toolkit/spatial.py +++ b/gravity_toolkit/spatial.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" spatial.py -Written by Tyler Sutterley (11/2021) +Written by Tyler Sutterley (12/2021) Data class for reading, writing and processing spatial data @@ -24,6 +24,7 @@ hdf5_read.py: reads spatial data from HDF5 UPDATE HISTORY: + Updated 12/2021: logging case_insensitive_filename output for debugging Updated 11/2021: fix kwargs to index and hdf5 read functions Updated 10/2021: using python logging for handling verbose output Updated 09/2021: use functions for converting to and from GRACE months @@ -108,6 +109,8 @@ def case_insensitive_filename(self,filename): errmsg = '{0} not found in file system'.format(filename) raise FileNotFoundError(errmsg) self.filename = os.path.join(directory,f.pop()) + #-- print filename + logging.debug(self.filename) return self def from_ascii(self, filename, date=True, **kwargs): diff --git a/scripts/aod1b_geocenter.py b/scripts/aod1b_geocenter.py index e0a69600..0113c697 100644 --- a/scripts/aod1b_geocenter.py +++ b/scripts/aod1b_geocenter.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" aod1b_geocenter.py -Written by Tyler Sutterley (11/2021) +Written by Tyler Sutterley (12/2021) Contributions by Hugo Lecomte (03/2021) Reads GRACE/GRACE-FO level-1b dealiasing data files for a specific product @@ -34,6 +34,7 @@ utilities.py: download and management utilities for files UPDATED HISTORY: + Updated 12/2021: can use variable loglevels for verbose output Updated 11/2021: use gravity_toolkit geocenter class for operations Updated 10/2021: using python logging for handling verbose output Updated 07/2021: can use default argument files to define options @@ -68,8 +69,11 @@ import gravity_toolkit.utilities as utilities #-- program module to read the degree 1 coefficients of the AOD1b data -def aod1b_geocenter(base_dir, DREL='', DSET='', CLOBBER=False, MODE=0o775, - VERBOSE=False): +def aod1b_geocenter(base_dir, + DREL='', + DSET='', + CLOBBER=False, + MODE=0o775): """ Creates monthly files of geocenter variations at 6-hour or 3-hour intervals from GRACE/GRACE-FO level-1b dealiasing data files @@ -88,13 +92,8 @@ def aod1b_geocenter(base_dir, DREL='', DSET='', CLOBBER=False, MODE=0o775, oba: ocean bottom pressure from OMCT/MPIOM CLOBBER: overwrite existing data MODE: Permission mode of directories and files - VERBOSE: Output information for each output file """ - #-- create logger - loglevel = logging.INFO if VERBOSE else logging.CRITICAL - logging.basicConfig(level=loglevel) - #-- compile regular expressions operators for file dates #-- will extract the year and month from the tar file (.tar.gz) tx = re.compile(r'AOD1B_(\d+)-(\d+)_\d+\.(tar\.gz|tgz)$', re.VERBOSE) @@ -272,19 +271,26 @@ def main(): help='Overwrite existing data') #-- verbose will output information about each output file parser.add_argument('--verbose','-V', - default=False, action='store_true', - help='Verbose output of run') + action='count', default=0, + help='Verbose output of processing run') #-- permissions mode of the local directories and files (number in octal) parser.add_argument('--mode','-M', type=lambda x: int(x,base=8), default=0o775, help='permissions mode of output files') args,_ = parser.parse_known_args() + #-- create logger + loglevels = [logging.CRITICAL,logging.INFO,logging.DEBUG] + logging.basicConfig(level=loglevels[args.verbose]) + #-- for each entered AOD1B dataset for DSET in args.product: #-- run AOD1b geocenter program with parameters - aod1b_geocenter(args.directory,DREL=args.release,DSET=DSET, - CLOBBER=args.clobber,VERBOSE=args.verbose,MODE=args.mode) + aod1b_geocenter(args.directory, + DREL=args.release, + DSET=DSET, + CLOBBER=args.clobber, + MODE=args.mode) #-- run main program if __name__ == '__main__': diff --git a/scripts/aod1b_oblateness.py b/scripts/aod1b_oblateness.py index 33174f9b..c2eda5ba 100644 --- a/scripts/aod1b_oblateness.py +++ b/scripts/aod1b_oblateness.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" aod1b_oblateness.py -Written by Tyler Sutterley (10/2021) +Written by Tyler Sutterley (12/2021) Contributions by Hugo Lecomte (03/2021) Reads GRACE/GRACE-FO level-1b dealiasing data files for a specific product @@ -36,6 +36,7 @@ utilities.py: download and management utilities for files UPDATED HISTORY: + Updated 12/2021: can use variable loglevels for verbose output Updated 10/2021: using python logging for handling verbose output Updated 07/2021: can use default argument files to define options Add 3-hour interval depending on Release @@ -67,8 +68,11 @@ import gravity_toolkit.utilities as utilities #-- program module to read the C20 coefficients of the AOD1b data -def aod1b_oblateness(base_dir, DREL='', DSET='', CLOBBER=False, MODE=0o775, - VERBOSE=False): +def aod1b_oblateness(base_dir, + DREL='', + DSET='', + CLOBBER=False, + MODE=0o775): """ Creates monthly files of oblateness (C20) variations at 6-hour intervals from GRACE/GRACE-FO level-1b dealiasing data files @@ -90,10 +94,6 @@ def aod1b_oblateness(base_dir, DREL='', DSET='', CLOBBER=False, MODE=0o775, VERBOSE: Output information for each output file """ - #-- create logger - loglevel = logging.INFO if VERBOSE else logging.CRITICAL - logging.basicConfig(level=loglevel) - #-- compile regular expressions operators for file dates #-- will extract the year and month from the tar file (.tar.gz) tx = re.compile(r'AOD1B_(\d+)-(\d+)_\d+\.(tar\.gz|tgz)$', re.VERBOSE) @@ -262,19 +262,26 @@ def main(): help='Overwrite existing data') #-- verbose will output information about each output file parser.add_argument('--verbose','-V', - default=False, action='store_true', - help='Verbose output of run') + action='count', default=0, + help='Verbose output of processing run') #-- permissions mode of the local directories and files (number in octal) parser.add_argument('--mode','-M', type=lambda x: int(x,base=8), default=0o775, help='permissions mode of output files') args,_ = parser.parse_known_args() + #-- create logger + loglevels = [logging.CRITICAL,logging.INFO,logging.DEBUG] + logging.basicConfig(level=loglevels[args.verbose]) + #-- for each entered AOD1B dataset for DSET in args.product: #-- run AOD1b oblateness program with parameters - aod1b_oblateness(args.directory,DREL=args.release,DSET=DSET, - CLOBBER=args.clobber,VERBOSE=args.verbose,MODE=args.mode) + aod1b_oblateness(args.directory, + DREL=args.release, + DSET=DSET, + CLOBBER=args.clobber, + MODE=args.mode) #-- run main program if __name__ == '__main__': diff --git a/scripts/calc_mascon.py b/scripts/calc_mascon.py index 4b381a83..97ee2d58 100644 --- a/scripts/calc_mascon.py +++ b/scripts/calc_mascon.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" calc_mascon.py -Written by Tyler Sutterley (11/2021) +Written by Tyler Sutterley (12/2021) Calculates a time-series of regional mass anomalies through a least-squares mascon procedure from GRACE/GRACE-FO time-variable gravity data @@ -156,6 +156,8 @@ https://doi.org/10.1029/2005GL025305 UPDATE HISTORY: + Updated 12/2021: can use variable loglevels for verbose output + option to specify a specific geocenter correction file Updated 11/2021: add GSFC low-degree harmonics Updated 10/2021: using python logging for handling verbose output fix choices for setting input format of the removed files @@ -330,6 +332,8 @@ def calc_mascon(base_dir, PROC, DREL, DSET, LMAX, RAD, ATM=False, POLE_TIDE=False, DEG1=None, + DEG1_FILE=None, + MODEL_DEG1=False, SLR_C20=None, SLR_21=None, SLR_22=None, @@ -409,7 +413,8 @@ def calc_mascon(base_dir, PROC, DREL, DSET, LMAX, RAD, Ylms = grace_input_months(base_dir, PROC, DREL, DSET, LMAX, START, END, MISSING, SLR_C20, DEG1, MMAX=MMAX, SLR_21=SLR_21, SLR_22=SLR_22, SLR_C30=SLR_C30, SLR_C50=SLR_C50, - MODEL_DEG1=True, ATM=ATM, POLE_TIDE=POLE_TIDE) + DEG1_FILE=DEG1_FILE, MODEL_DEG1=MODEL_DEG1, ATM=ATM, + POLE_TIDE=POLE_TIDE) #-- create harmonics object from GRACE/GRACE-FO data GRACE_Ylms = harmonics().from_dict(Ylms) #-- use a mean file for the static field to remove @@ -898,6 +903,12 @@ def main(): metavar='DEG1', type=str, choices=['Tellus','SLR','SLF','Swenson','GFZ'], help='Update Degree 1 coefficients with SLR or derived values') + parser.add_argument('--geocenter-file', + type=lambda p: os.path.abspath(os.path.expanduser(p)), + help='Specific geocenter file if not default') + parser.add_argument('--interpolate-geocenter', + default=False, action='store_true', + help='Least-squares model missing Degree 1 coefficients') #-- replace low degree harmonics with values from Satellite Laser Ranging parser.add_argument('--slr-c20', type=str, default=None, choices=['CSR','GFZ','GSFC'], @@ -974,7 +985,7 @@ def main(): help='Output log file for each job') #-- print information about processing run parser.add_argument('--verbose','-V', - default=False, action='store_true', + action='count', default=0, help='Verbose output of processing run') #-- permissions mode of the local directories and files (number in octal) parser.add_argument('--mode','-M', @@ -983,8 +994,8 @@ def main(): args,_ = parser.parse_known_args() #-- create logger - loglevel = logging.INFO if args.verbose else logging.CRITICAL - logging.basicConfig(level=loglevel) + loglevels = [logging.CRITICAL,logging.INFO,logging.DEBUG] + logging.basicConfig(level=loglevels[args.verbose]) #-- try to run the analysis with listed parameters try: @@ -1010,6 +1021,8 @@ def main(): ATM=args.atm_correction, POLE_TIDE=args.pole_tide, DEG1=args.geocenter, + DEG1_FILE=args.geocenter_file, + MODEL_DEG1=args.interpolate_geocenter, SLR_C20=args.slr_c20, SLR_21=args.slr_21, SLR_22=args.slr_22, diff --git a/scripts/calc_sensitivity_kernel.py b/scripts/calc_sensitivity_kernel.py index 0edb4337..46b52cf4 100644 --- a/scripts/calc_sensitivity_kernel.py +++ b/scripts/calc_sensitivity_kernel.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" calc_sensitivity_kernel.py -Written by Tyler Sutterley (10/2021) +Written by Tyler Sutterley (12/2021) Calculates spatial sensitivity kernels through a least-squares mascon procedure @@ -83,6 +83,7 @@ https://doi.org/10.1029/2009GL039401 UPDATE HISTORY: + Updated 12/2021: can use variable loglevels for verbose output Updated 10/2021: using python logging for handling verbose output Updated 07/2021: simplified file imports using wrappers in harmonics added path to default land-sea mask for mass redistribution @@ -599,7 +600,7 @@ def main(): help='Output log file for each job') #-- print information about processing run parser.add_argument('--verbose','-V', - default=False, action='store_true', + action='count', default=0, help='Verbose output of processing run') #-- permissions mode of the local directories and files (number in octal) parser.add_argument('--mode','-M', @@ -608,8 +609,8 @@ def main(): args,_ = parser.parse_known_args() #-- create logger - loglevel = logging.INFO if args.verbose else logging.CRITICAL - logging.basicConfig(level=loglevel) + loglevels = [logging.CRITICAL,logging.INFO,logging.DEBUG] + logging.basicConfig(level=loglevels[args.verbose]) #-- try to run the analysis with listed parameters try: diff --git a/scripts/cnes_grace_sync.py b/scripts/cnes_grace_sync.py index a252748f..cbdf8ca7 100755 --- a/scripts/cnes_grace_sync.py +++ b/scripts/cnes_grace_sync.py @@ -35,6 +35,7 @@ utilities.py: download and management utilities for syncing files UPDATE HISTORY: + Updated 12/2021: can use variable loglevels for verbose output Updated 10/2021: using python logging for handling verbose output Updated 05/2021: added option for connection timeout (in seconds) Updated 12/2020: use argparse to set command line parameters @@ -227,7 +228,7 @@ def cnes_grace_sync(DIRECTORY, DREL=[], TIMEOUT=None, LOG=False, #-- outputting GRACE filenames to index with open(os.path.join(local_dir,'index.txt'),'w') as fid: for fi in sorted(grace_files): - print('{0}'.format(fi), file=fid) + print(fi, file=fid) #-- change permissions of index file os.chmod(os.path.join(local_dir,'index.txt'), MODE) diff --git a/scripts/combine_harmonics.py b/scripts/combine_harmonics.py index e7d1be86..f8104659 100644 --- a/scripts/combine_harmonics.py +++ b/scripts/combine_harmonics.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" combine_harmonics.py -Written by Tyler Sutterley (10/2021) +Written by Tyler Sutterley (12/2021) Converts a file from the spherical harmonic domain into the spatial domain CALLING SEQUENCE: @@ -76,6 +76,7 @@ utilities.py: download and management utilities for files UPDATE HISTORY: + Updated 12/2021: can use variable loglevels for verbose output Updated 10/2021: using python logging for handling verbose output Updated 09/2021: update grid attributes after allocating for data Updated 08/2021: fix spherical harmonic orders if not set @@ -199,7 +200,6 @@ def combine_harmonics(INPUT_FILE, OUTPUT_FILE, LANDMASK=None, MEAN_FILE=None, DATAFORM=None, - VERBOSE=False, MODE=0o775): #-- verify that output directory exists @@ -333,9 +333,6 @@ def combine_harmonics(INPUT_FILE, OUTPUT_FILE, grid.data[:,:,t] = harmonic_summation(Ylms.clm, Ylms.slm, grid.lon, grid.lat, LMAX=LMAX, PLM=PLM).T - #-- if verbose output: print input and output file names - logging.info('{0}:'.format(os.path.basename(sys.argv[0]))) - logging.info('{0} -->\n\t{1}\n'.format(INPUT_FILE,OUTPUT_FILE)) #-- outputting data to file output_data(grid.squeeze(), FILENAME=OUTPUT_FILE, DATAFORM=DATAFORM, UNITS=UNITS) @@ -440,7 +437,7 @@ def main(): help='Input and output data format') #-- print information about each input and output file parser.add_argument('--verbose','-V', - default=False, action='store_true', + action='count', default=0, help='Verbose output of run') #-- permissions mode of the output files (octal) parser.add_argument('--mode','-M', @@ -449,8 +446,8 @@ def main(): args,_ = parser.parse_known_args() #-- create logger - loglevel = logging.INFO if args.verbose else logging.CRITICAL - logging.basicConfig(level=loglevel) + loglevels = [logging.CRITICAL,logging.INFO,logging.DEBUG] + logging.basicConfig(level=loglevels[args.verbose]) #-- run program with parameters try: @@ -470,7 +467,6 @@ def main(): LANDMASK=args.mask, MEAN_FILE=args.mean, DATAFORM=args.format, - VERBOSE=args.verbose, MODE=args.mode) except Exception as e: #-- if there has been an error exception diff --git a/scripts/convert_harmonics.py b/scripts/convert_harmonics.py index 245a7afd..f4267bd8 100644 --- a/scripts/convert_harmonics.py +++ b/scripts/convert_harmonics.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" convert_harmonics.py -Written by Tyler Sutterley (10/2021) +Written by Tyler Sutterley (12/2021) Converts a file from the spatial domain into the spherical harmonic domain CALLING SEQUENCE: @@ -67,6 +67,7 @@ utilities.py: download and management utilities for files UPDATE HISTORY: + Updated 12/2021: can use variable loglevels for verbose output Updated 10/2021: using python logging for handling verbose output Updated 09/2021: fix to use fill values for input ascii files use functions for converting to and from GRACE months @@ -178,7 +179,6 @@ def convert_harmonics(INPUT_FILE, OUTPUT_FILE, FILL_VALUE=None, HEADER=None, DATAFORM=None, - VERBOSE=False, MODE=0o775): #-- verify that output directory exists @@ -241,9 +241,6 @@ def convert_harmonics(INPUT_FILE, OUTPUT_FILE, Ylms = harmonics().from_list(Ylms_list) Ylms_list = None - #-- if verbose output: print input and output file names - logging.info('{0}:'.format(os.path.basename(sys.argv[0]))) - logging.info('{0} -->\n\t{1}'.format(INPUT_FILE,OUTPUT_FILE)) #-- outputting data to file if (DATAFORM == 'ascii'): #-- ascii (.txt) @@ -319,7 +316,7 @@ def main(): help='Input and output data format') #-- print information about each input and output file parser.add_argument('--verbose','-V', - default=False, action='store_true', + action='count', default=0, help='Verbose output of run') #-- permissions mode of the output files (octal) parser.add_argument('--mode','-M', @@ -328,8 +325,8 @@ def main(): args,_ = parser.parse_known_args() #-- create logger - loglevel = logging.INFO if args.verbose else logging.CRITICAL - logging.basicConfig(level=loglevel) + loglevels = [logging.CRITICAL,logging.INFO,logging.DEBUG] + logging.basicConfig(level=loglevels[args.verbose]) #-- run program with parameters try: @@ -345,7 +342,6 @@ def main(): FILL_VALUE=args.fill_value, HEADER=args.header, DATAFORM=args.format, - VERBOSE=args.verbose, MODE=args.mode) except Exception as e: #-- if there has been an error exception diff --git a/scripts/dealiasing_monthly_mean.py b/scripts/dealiasing_monthly_mean.py index 3cefd7b3..e41d3e5c 100755 --- a/scripts/dealiasing_monthly_mean.py +++ b/scripts/dealiasing_monthly_mean.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" dealiasing_monthly_mean.py -Written by Tyler Sutterley (10/2021) +Written by Tyler Sutterley (12/2021) Reads GRACE/GRACE-FO AOD1B datafiles for a specific product and outputs monthly the mean for a specific GRACE/GRACE-FO processing center and data release @@ -52,6 +52,7 @@ time.py: utilities for calculating time operations UPDATED HISTORY: + Updated 12/2021: can use variable loglevels for verbose output Updated 10/2021: using python logging for handling verbose output Updated 07/2021: can use default argument files to define options added option to output in spherical harmonic model (SHM) format @@ -98,8 +99,8 @@ def dealiasing_monthly_mean(base_dir, PROC=None, DREL=None, DSET=None, LMAX=None, DATAFORM=None, CLOBBER=False, VERBOSE=False, MODE=0o775): #-- create logger - loglevel = logging.INFO if VERBOSE else logging.CRITICAL - logging.basicConfig(level=loglevel) + loglevels = [logging.CRITICAL,logging.INFO,logging.DEBUG] + logging.basicConfig(level=loglevels[VERBOSE]) #-- output data suffix suffix = dict(ascii='txt', netCDF4='nc', HDF5='H5') @@ -355,7 +356,7 @@ def dealiasing_monthly_mean(base_dir, PROC=None, DREL=None, DSET=None, os.chmod(os.path.join(grace_dir,DSET,FILE), MODE) elif not COMPLETE: - print('File {0} not output (incomplete)'.format(FILE)) + logging.info('File {0} not output (incomplete)'.format(FILE)) #-- if outputting as spherical harmonic model files if (DATAFORM == 'SHM'): @@ -365,12 +366,12 @@ def dealiasing_monthly_mean(base_dir, PROC=None, DREL=None, DSET=None, #-- outputting GRACE filenames to index with open(os.path.join(grace_dir,DSET,'index.txt'),'w') as fid: for fi in sorted(grace_files): - print('{0}'.format(fi), file=fid) + print(fi, file=fid) #-- change permissions of index file os.chmod(os.path.join(grace_dir,DSET,'index.txt'), MODE) #-- print completion flag - print('Complete: {0}/{1}/{2}'.format(PROC,DREL,DSET)) + logging.info('Complete: {0}/{1}/{2}'.format(PROC,DREL,DSET)) #-- close the output date file f_out.close() @@ -412,7 +413,7 @@ def to_SHM(self, filename, **kwargs): self.filename = os.path.expanduser(filename) #-- set default verbosity kwargs.setdefault('verbose',False) - print(self.filename) if kwargs['verbose'] else None + logging.info(self.filename) #-- open the output file fid = gzip.open(self.filename, 'wt') #-- print the header informat @@ -706,7 +707,7 @@ def main(): help='Overwrite existing data') #-- verbose will output information about each output file parser.add_argument('--verbose','-V', - default=False, action='store_true', + action='count', default=0, help='Verbose output of run') #-- permissions mode of the local directories and files (number in octal) parser.add_argument('--mode','-M', diff --git a/scripts/esa_costg_swarm_sync.py b/scripts/esa_costg_swarm_sync.py index 04c4b099..0a1c0622 100644 --- a/scripts/esa_costg_swarm_sync.py +++ b/scripts/esa_costg_swarm_sync.py @@ -130,7 +130,7 @@ def esa_costg_swarm_sync(DIRECTORY, RELEASE=None, TIMEOUT=None, LOG=False, TIMEOUT=TIMEOUT, LIST=LIST, CLOBBER=CLOBBER, CHECKSUM=CHECKSUM, MODE=MODE) #-- output Swarm filenames to index - print('{0}'.format(colnames[i]), file=fid) + print(colnames[i], file=fid) #-- change permissions of index file os.chmod(os.path.join(local_dir,'index.txt'), MODE) diff --git a/scripts/gfz_icgem_costg_ftp.py b/scripts/gfz_icgem_costg_ftp.py index 476d9702..c0409c77 100644 --- a/scripts/gfz_icgem_costg_ftp.py +++ b/scripts/gfz_icgem_costg_ftp.py @@ -146,7 +146,7 @@ def gfz_icgem_costg_ftp(DIRECTORY, MISSION=[], RELEASE=None, TIMEOUT=None, with open(os.path.join(local_dir,'index.txt'),'w') as fid: #-- output GRACE/GRACE-FO/Swarm filenames to index for fi in sorted(grace_files): - print('{0}'.format(fi), file=fid) + print(fi, file=fid) #-- change permissions of index file os.chmod(os.path.join(local_dir,'index.txt'), MODE) diff --git a/scripts/gfz_isdc_grace_ftp.py b/scripts/gfz_isdc_grace_ftp.py index 15854927..edd93385 100644 --- a/scripts/gfz_isdc_grace_ftp.py +++ b/scripts/gfz_isdc_grace_ftp.py @@ -183,7 +183,7 @@ def gfz_isdc_grace_ftp(DIRECTORY, PROC, DREL=[], MISSION=[], TIMEOUT=None, #-- outputting GRACE/GRACE-FO filenames to index with open(os.path.join(local_dir,'index.txt'),'w') as fid: for fi in sorted(files): - print('{0}'.format(fi), file=fid) + print(fi, file=fid) #-- change permissions of index file os.chmod(os.path.join(local_dir,'index.txt'), MODE) diff --git a/scripts/grace_mean_harmonics.py b/scripts/grace_mean_harmonics.py index 446cd400..41f17611 100644 --- a/scripts/grace_mean_harmonics.py +++ b/scripts/grace_mean_harmonics.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" grace_mean_harmonics.py -Written by Tyler Sutterley (11/2021) +Written by Tyler Sutterley (12/2021) Calculates the temporal mean of the GRACE/GRACE-FO spherical harmonics for a given date range from a set of parameters @@ -73,6 +73,8 @@ utilities.py: download and management utilities for files UPDATE HISTORY: + Updated 12/2021: can use variable loglevels for verbose output + option to specify a specific geocenter correction file Updated 11/2021: add GSFC low-degree harmonics Updated 10/2021: using python logging for handling verbose output Updated 07/2021: simplified file exports using wrappers in harmonics @@ -134,6 +136,8 @@ def grace_mean_harmonics(base_dir, PROC, DREL, DSET, LMAX, ATM=False, POLE_TIDE=False, DEG1=None, + DEG1_FILE=None, + MODEL_DEG1=False, SLR_C20=None, SLR_21=None, SLR_22=None, @@ -158,7 +162,8 @@ def grace_mean_harmonics(base_dir, PROC, DREL, DSET, LMAX, input_Ylms = grace_input_months(base_dir, PROC, DREL, DSET, LMAX, START, END, MISSING, SLR_C20, DEG1, MMAX=MMAX, SLR_21=SLR_21, SLR_22=SLR_22, SLR_C30=SLR_C30, SLR_C50=SLR_C50, - MODEL_DEG1=False, POLE_TIDE=POLE_TIDE, ATM=ATM) + DEG1_FILE=DEG1_FILE, MODEL_DEG1=MODEL_DEG1, ATM=ATM, + POLE_TIDE=POLE_TIDE) grace_Ylms = harmonics().from_dict(input_Ylms) #-- descriptor string for processing parameters grace_str = input_Ylms['title'] @@ -239,7 +244,7 @@ def to_gfc(self, filename, **kwargs): self.filename = os.path.expanduser(filename) #-- set default verbosity kwargs.setdefault('verbose',False) - print(self.filename) if kwargs['verbose'] else None + logging.info(self.filename) #-- open the output file fid = open(self.filename, 'w') #-- print the header informat @@ -382,6 +387,12 @@ def main(): metavar='DEG1', type=str, choices=['Tellus','SLR','SLF','Swenson','GFZ'], help='Update Degree 1 coefficients with SLR or derived values') + parser.add_argument('--geocenter-file', + type=lambda p: os.path.abspath(os.path.expanduser(p)), + help='Specific geocenter file if not default') + parser.add_argument('--interpolate-geocenter', + default=False, action='store_true', + help='Least-squares model missing Degree 1 coefficients') #-- replace low degree harmonics with values from Satellite Laser Ranging parser.add_argument('--slr-c20', type=str, default=None, choices=['CSR','GFZ','GSFC'], @@ -414,7 +425,7 @@ def main(): help='Output log file for each job') #-- print information about each input and output file parser.add_argument('--verbose','-V', - default=False, action='store_true', + action='count', default=0, help='Verbose output of run') #-- permissions mode of the local directories and files (number in octal) parser.add_argument('--mode','-M', @@ -423,8 +434,8 @@ def main(): args,_ = parser.parse_known_args() #-- create logger - loglevel = logging.INFO if args.verbose else logging.CRITICAL - logging.basicConfig(level=loglevel) + loglevels = [logging.CRITICAL,logging.INFO,logging.DEBUG] + logging.basicConfig(level=loglevels[args.verbose]) #-- try to run the analysis with listed parameters try: @@ -443,6 +454,8 @@ def main(): ATM=args.atm_correction, POLE_TIDE=args.pole_tide, DEG1=args.geocenter, + DEG1_FILE=args.geocenter_file, + MODEL_DEG1=args.interpolate_geocenter, SLR_C20=args.slr_c20, SLR_21=args.slr_21, SLR_22=args.slr_22, diff --git a/scripts/grace_spatial_error.py b/scripts/grace_spatial_error.py index c6908d29..8948ee2c 100755 --- a/scripts/grace_spatial_error.py +++ b/scripts/grace_spatial_error.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" grace_spatial_error.py -Written by Tyler Sutterley (11/2021) +Written by Tyler Sutterley (12/2021) Calculates the GRACE/GRACE-FO errors following Wahr et al. (2006) @@ -121,6 +121,9 @@ http://dx.doi.org/10.1029/2005GL025305 UPDATE HISTORY: + Updated 12/2021: can use variable loglevels for verbose output + option to specify a specific geocenter correction file + fix default file prefix to include center and release information Updated 11/2021: add GSFC low-degree harmonics Updated 10/2021: using python logging for handling verbose output Updated 07/2021: simplified file imports using wrappers in harmonics @@ -255,6 +258,7 @@ def grace_spatial_error(base_dir, PROC, DREL, DSET, LMAX, RAD, ATM=False, POLE_TIDE=False, DEG1=None, + DEG1_FILE=None, MODEL_DEG1=False, SLR_C20=None, SLR_21=None, @@ -305,14 +309,12 @@ def grace_spatial_error(base_dir, PROC, DREL, DSET, LMAX, RAD, Ylms = grace_input_months(base_dir, PROC, DREL, DSET, LMAX, START, END, MISSING, SLR_C20, DEG1, MMAX=MMAX, SLR_21=SLR_21, SLR_22=SLR_22, SLR_C30=SLR_C30, SLR_C50=SLR_C50, - MODEL_DEG1=MODEL_DEG1, ATM=ATM, POLE_TIDE=POLE_TIDE) + DEG1_FILE=DEG1_FILE, MODEL_DEG1=MODEL_DEG1, ATM=ATM, + POLE_TIDE=POLE_TIDE) #-- convert to harmonics object and remove mean if specified GRACE_Ylms = harmonics().from_dict(Ylms) #-- full path to directory for specific GRACE/GRACE-FO product GRACE_Ylms.directory = Ylms['directory'] - #-- default file prefix - if not FILE_PREFIX: - FILE_PREFIX = Ylms['title'] #-- use a mean file for the static field to remove if MEAN_FILE: #-- read data form for input mean file (ascii, netCDF4, HDF5, gfc) @@ -324,6 +326,10 @@ def grace_spatial_error(base_dir, PROC, DREL, DSET, LMAX, RAD, #-- date information of GRACE/GRACE-FO coefficients nfiles = len(GRACE_Ylms.time) + #-- default file prefix + if not FILE_PREFIX: + FILE_PREFIX = '{0}_{1}_{2}{3}_'.format(PROC,DREL,DSET,Ylms['title']) + #-- filter GRACE/GRACE-FO coefficients if DESTRIPE: #-- destriping GRACE/GRACE-FO coefficients @@ -651,6 +657,9 @@ def main(): metavar='DEG1', type=str, choices=['Tellus','SLR','SLF','Swenson','GFZ'], help='Update Degree 1 coefficients with SLR or derived values') + parser.add_argument('--geocenter-file', + type=lambda p: os.path.abspath(os.path.expanduser(p)), + help='Specific geocenter file if not default') parser.add_argument('--interpolate-geocenter', default=False, action='store_true', help='Least-squares model missing Degree 1 coefficients') @@ -690,7 +699,7 @@ def main(): help='Output log file for each job') #-- print information about each input and output file parser.add_argument('--verbose','-V', - default=False, action='store_true', + action='count', default=0, help='Verbose output of run') #-- permissions mode of the local directories and files (number in octal) parser.add_argument('--mode','-M', @@ -699,8 +708,8 @@ def main(): args,_ = parser.parse_known_args() #-- create logger - loglevel = logging.INFO if args.verbose else logging.CRITICAL - logging.basicConfig(level=loglevel) + loglevels = [logging.CRITICAL,logging.INFO,logging.DEBUG] + logging.basicConfig(level=loglevels[args.verbose]) #-- try to run the analysis with listed parameters try: @@ -728,6 +737,7 @@ def main(): ATM=args.atm_correction, POLE_TIDE=args.pole_tide, DEG1=args.geocenter, + DEG1_FILE=args.geocenter_file, MODEL_DEG1=args.interpolate_geocenter, SLR_C20=args.slr_c20, SLR_21=args.slr_21, diff --git a/scripts/grace_spatial_maps.py b/scripts/grace_spatial_maps.py index bf7c4d1a..6ba5d010 100755 --- a/scripts/grace_spatial_maps.py +++ b/scripts/grace_spatial_maps.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" grace_spatial_maps.py -Written by Tyler Sutterley (10/2021) +Written by Tyler Sutterley (12/2021) Reads in GRACE/GRACE-FO spherical harmonic coefficients and exports monthly spatial fields @@ -151,6 +151,9 @@ utilities.py: download and management utilities for files UPDATE HISTORY: + Updated 12/2021: can use variable loglevels for verbose output + option to specify a specific geocenter correction file + fix default file prefix to include center and release information Updated 11/2021: add GSFC low-degree harmonics Updated 10/2021: using python logging for handling verbose output add more choices for setting input format of the removed files @@ -279,6 +282,7 @@ def grace_spatial_maps(base_dir, PROC, DREL, DSET, LMAX, RAD, ATM=False, POLE_TIDE=False, DEG1=None, + DEG1_FILE=None, MODEL_DEG1=False, SLR_C20=None, SLR_21=None, @@ -331,14 +335,11 @@ def grace_spatial_maps(base_dir, PROC, DREL, DSET, LMAX, RAD, Ylms = grace_input_months(base_dir, PROC, DREL, DSET, LMAX, START, END, MISSING, SLR_C20, DEG1, MMAX=MMAX, SLR_21=SLR_21, SLR_22=SLR_22, SLR_C30=SLR_C30, SLR_C50=SLR_C50, - MODEL_DEG1=MODEL_DEG1, ATM=ATM, POLE_TIDE=POLE_TIDE) + DEG1_FILE=DEG1_FILE, MODEL_DEG1=MODEL_DEG1, ATM=ATM, + POLE_TIDE=POLE_TIDE) #-- convert to harmonics object and remove mean if specified GRACE_Ylms = harmonics().from_dict(Ylms) GRACE_Ylms.directory = Ylms['directory'] - GRACE_Ylms.title = Ylms['title'] - #-- default file prefix - if not FILE_PREFIX: - FILE_PREFIX = GRACE_Ylms.title #-- use a mean file for the static field to remove if MEAN_FILE: #-- read data form for input mean file (ascii, netCDF4, HDF5, gfc) @@ -361,6 +362,7 @@ def grace_spatial_maps(base_dir, PROC, DREL, DSET, LMAX, RAD, #-- input GIA spherical harmonic datafiles GIA_Ylms_rate = read_GIA_model(GIA_FILE,GIA=GIA,LMAX=LMAX,MMAX=MMAX) + gia_str = '_{0}'.format(GIA_Ylms_rate['title']) if GIA else '' #-- calculate the monthly mass change from GIA GIA_Ylms = GRACE_Ylms.zeros_like() GIA_Ylms.time[:] = np.copy(GRACE_Ylms.time) @@ -371,6 +373,11 @@ def grace_spatial_maps(base_dir, PROC, DREL, DSET, LMAX, RAD, GIA_Ylms.clm[:,:,t] = GIA_Ylms_rate['clm']*(GIA_Ylms.time[t]-2003.3) GIA_Ylms.slm[:,:,t] = GIA_Ylms_rate['slm']*(GIA_Ylms.time[t]-2003.3) + #-- default file prefix + if not FILE_PREFIX: + fargs = (PROC,DREL,DSET,Ylms['title'],gia_str) + FILE_PREFIX = '{0}_{1}_{2}{3}{4}_'.format(*fargs) + #-- Read Ocean function and convert to Ylms for redistribution if REDISTRIBUTE_REMOVED: #-- read Land-Sea Mask and convert to spherical harmonics @@ -699,6 +706,9 @@ def main(): metavar='DEG1', type=str, choices=['Tellus','SLR','SLF','Swenson','GFZ'], help='Update Degree 1 coefficients with SLR or derived values') + parser.add_argument('--geocenter-file', + type=lambda p: os.path.abspath(os.path.expanduser(p)), + help='Specific geocenter file if not default') parser.add_argument('--interpolate-geocenter', default=False, action='store_true', help='Least-squares model missing Degree 1 coefficients') @@ -756,7 +766,7 @@ def main(): help='Output log file for each job') #-- print information about each input and output file parser.add_argument('--verbose','-V', - default=False, action='store_true', + action='count', default=0, help='Verbose output of run') #-- permissions mode of the local directories and files (number in octal) parser.add_argument('--mode','-M', @@ -765,8 +775,8 @@ def main(): args,_ = parser.parse_known_args() #-- create logger - loglevel = logging.INFO if args.verbose else logging.CRITICAL - logging.basicConfig(level=loglevel) + loglevels = [logging.CRITICAL,logging.INFO,logging.DEBUG] + logging.basicConfig(level=loglevels[args.verbose]) #-- try to run the analysis with listed parameters try: @@ -796,6 +806,7 @@ def main(): ATM=args.atm_correction, POLE_TIDE=args.pole_tide, DEG1=args.geocenter, + DEG1_FILE=args.geocenter_file, MODEL_DEG1=args.interpolate_geocenter, SLR_C20=args.slr_c20, SLR_21=args.slr_21, diff --git a/scripts/itsg_graz_grace_sync.py b/scripts/itsg_graz_grace_sync.py index 4616ed15..e29f972d 100755 --- a/scripts/itsg_graz_grace_sync.py +++ b/scripts/itsg_graz_grace_sync.py @@ -155,7 +155,7 @@ def itsg_graz_grace_sync(DIRECTORY, RELEASE=None, LMAX=None, TIMEOUT=0, #-- outputting GRACE filenames to index with open(os.path.join(local_dir,'index.txt'),'w') as fid: for fi in sorted(grace_files): - print('{0}'.format(fi), file=fid) + print(fi, file=fid) #-- change permissions of index file os.chmod(os.path.join(local_dir,'index.txt'), MODE) diff --git a/scripts/mascon_reconstruct.py b/scripts/mascon_reconstruct.py index 07cd2ea5..3db6621b 100644 --- a/scripts/mascon_reconstruct.py +++ b/scripts/mascon_reconstruct.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" mascon_reconstruct.py -Written by Tyler Sutterley (10/2021) +Written by Tyler Sutterley (12/2021) Calculates the equivalent spherical harmonics from a mascon time series @@ -77,6 +77,7 @@ utilities.py: download and management utilities for files UPDATE HISTORY: + Updated 12/2021: can use variable loglevels for verbose output Updated 10/2021: using python logging for handling verbose output Updated 07/2021: switch from parameter files to argparse arguments added path to default land-sea mask for mass redistribution @@ -433,7 +434,7 @@ def main(): help='Land-sea mask for redistributing mascon mass') #-- print information about processing run parser.add_argument('--verbose','-V', - default=False, action='store_true', + action='count', default=0, help='Verbose output of processing run') #-- permissions mode of the local directories and files (number in octal) parser.add_argument('--mode','-M', @@ -442,8 +443,8 @@ def main(): args,_ = parser.parse_known_args() #-- create logger - loglevel = logging.INFO if args.verbose else logging.CRITICAL - logging.basicConfig(level=loglevel) + loglevels = [logging.CRITICAL,logging.INFO,logging.DEBUG] + logging.basicConfig(level=loglevels[args.verbose]) #-- try to run the analysis with listed parameters try: diff --git a/scripts/podaac_webdav.py b/scripts/podaac_webdav.py index 4c49f922..39bd9463 100644 --- a/scripts/podaac_webdav.py +++ b/scripts/podaac_webdav.py @@ -96,7 +96,7 @@ def podaac_webdav(USER, PASSWORD, parser): #-- Main program that calls podaac_webdav() def main(): - #-- Read the system arguments listed after the program + #-- Read the system arguments listed after the program parser = argparse.ArgumentParser( description="""Retrieves and prints a user's PO.DAAC WebDAV credentials diff --git a/scripts/regress_grace_maps.py b/scripts/regress_grace_maps.py index 5f304576..d70f5023 100755 --- a/scripts/regress_grace_maps.py +++ b/scripts/regress_grace_maps.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" regress_grace_maps.py -Written by Tyler Sutterley (10/2021) +Written by Tyler Sutterley (12/2021) Reads in GRACE/GRACE-FO spatial files from grace_spatial_maps.py and fits a regression model at each grid point @@ -63,6 +63,7 @@ hdf5_write.py: writes output spatial data to HDF5 UPDATE HISTORY: + Updated 12/2021: can use variable loglevels for verbose output Updated 10/2021: using python logging for handling verbose output Updated 06/2021: switch from parameter files to argparse arguments Updated 05/2021: define int/float precision to prevent deprecation warning @@ -526,7 +527,7 @@ def main(): help='Output log file for each job') #-- print information about each input and output file parser.add_argument('--verbose','-V', - default=False, action='store_true', + action='count', default=0, help='Verbose output of run') #-- permissions mode of the local directories and files (number in octal) parser.add_argument('--mode','-M', @@ -535,8 +536,8 @@ def main(): args,_ = parser.parse_known_args() #-- create logger - loglevel = logging.INFO if args.verbose else logging.CRITICAL - logging.basicConfig(level=loglevel) + loglevels = [logging.CRITICAL,logging.INFO,logging.DEBUG] + logging.basicConfig(level=loglevels[args.verbose]) #-- try to run the analysis with listed parameters try: diff --git a/scripts/run_grace_date.py b/scripts/run_grace_date.py index 7d004b92..b13ac65d 100755 --- a/scripts/run_grace_date.py +++ b/scripts/run_grace_date.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" run_grace_date.py -Written by Tyler Sutterley (10/2021) +Written by Tyler Sutterley (12/2021) Wrapper program for running GRACE date and months programs @@ -47,6 +47,7 @@ grace_months_index.py: creates a single file showing the GRACE dates UPDATE HISTORY: + Updated 12/2021: can use variable loglevels for verbose output Updated 10/2021: using python logging for handling verbose output Updated 09/2021: using verbose option to track program progress Updated 05/2021: define int/float precision to prevent deprecation warning @@ -75,8 +76,8 @@ def run_grace_date(base_dir, PROC, DREL, VERBOSE=False, MODE=0o775): #-- create logger - loglevel = logging.INFO if VERBOSE else logging.CRITICAL - logging.basicConfig(level=loglevel) + loglevels = [logging.CRITICAL,logging.INFO,logging.DEBUG] + logging.basicConfig(level=loglevels[VERBOSE]) #-- allocate python dictionaries for each processing center DSET = {} @@ -140,7 +141,7 @@ def main(): help='GRACE/GRACE-FO Data Release') #-- print information about each input and output file parser.add_argument('--verbose','-V', - default=False, action='store_true', + action='count', default=0, help='Verbose output of run') #-- permissions mode of the local directories and files (number in octal) parser.add_argument('--mode','-M', diff --git a/scripts/scale_grace_maps.py b/scripts/scale_grace_maps.py index 19105976..db24b70d 100644 --- a/scripts/scale_grace_maps.py +++ b/scripts/scale_grace_maps.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" scale_grace_maps.py -Written by Tyler Sutterley (11/2021) +Written by Tyler Sutterley (12/2021) Reads in GRACE/GRACE-FO spherical harmonic coefficients and exports monthly scaled spatial fields, estimated scaling errors, @@ -159,6 +159,9 @@ https://doi.org/10.1029/2005GL025305 UPDATE HISTORY: + Updated 12/2021: can use variable loglevels for verbose output + option to specify a specific geocenter correction file + fix default file prefix to include center and release information Updated 11/2021: add GSFC low-degree harmonics Updated 10/2021: using python logging for handling verbose output add more choices for setting input format of the removed files @@ -281,6 +284,7 @@ def scale_grace_maps(base_dir, PROC, DREL, DSET, LMAX, RAD, ATM=False, POLE_TIDE=False, DEG1=None, + DEG1_FILE=None, MODEL_DEG1=False, SLR_C20=None, SLR_21=None, @@ -379,11 +383,11 @@ def scale_grace_maps(base_dir, PROC, DREL, DSET, LMAX, RAD, Ylms = grace_input_months(base_dir, PROC, DREL, DSET, LMAX, START, END, MISSING, SLR_C20, DEG1, MMAX=MMAX, SLR_21=SLR_21, SLR_22=SLR_22, SLR_C30=SLR_C30, SLR_C50=SLR_C50, - MODEL_DEG1=MODEL_DEG1, ATM=ATM, POLE_TIDE=POLE_TIDE) + DEG1_FILE=DEG1_FILE, MODEL_DEG1=MODEL_DEG1, ATM=ATM, + POLE_TIDE=POLE_TIDE) #-- create harmonics object from GRACE/GRACE-FO data GRACE_Ylms = harmonics().from_dict(Ylms) GRACE_Ylms.directory = Ylms['directory'] - GRACE_Ylms.title = Ylms['title'] #-- use a mean file for the static field to remove if MEAN_FILE: #-- read data form for input mean file (ascii, netCDF4, HDF5, gfc) @@ -417,6 +421,11 @@ def scale_grace_maps(base_dir, PROC, DREL, DSET, LMAX, RAD, GIA_Ylms.clm[:,:,t] = GIA_Ylms_rate['clm']*(GIA_Ylms.time[t]-2003.3) GIA_Ylms.slm[:,:,t] = GIA_Ylms_rate['slm']*(GIA_Ylms.time[t]-2003.3) + #-- default file prefix + if not FILE_PREFIX: + fargs = (PROC,DREL,DSET,Ylms['title'],gia_str) + FILE_PREFIX = '{0}_{1}_{2}{3}{4}_'.format(*fargs) + #-- input spherical harmonic datafiles to be removed from the GRACE data #-- Remove sets of Ylms from the GRACE data before returning remove_Ylms = GRACE_Ylms.zeros_like() @@ -842,6 +851,9 @@ def main(): metavar='DEG1', type=str, choices=['Tellus','SLR','SLF','Swenson','GFZ'], help='Update Degree 1 coefficients with SLR or derived values') + parser.add_argument('--geocenter-file', + type=lambda p: os.path.abspath(os.path.expanduser(p)), + help='Specific geocenter file if not default') parser.add_argument('--interpolate-geocenter', default=False, action='store_true', help='Least-squares model missing Degree 1 coefficients') @@ -909,7 +921,7 @@ def main(): help='Output log file for each job') #-- print information about processing run parser.add_argument('--verbose','-V', - default=False, action='store_true', + action='count', default=0, help='Verbose output of processing run') #-- permissions mode of the local directories and files (number in octal) parser.add_argument('--mode','-M', @@ -918,8 +930,8 @@ def main(): args,_ = parser.parse_known_args() #-- create logger - loglevel = logging.INFO if args.verbose else logging.CRITICAL - logging.basicConfig(level=loglevel) + loglevels = [logging.CRITICAL,logging.INFO,logging.DEBUG] + logging.basicConfig(level=loglevels[args.verbose]) #-- try to run the analysis with listed parameters try: @@ -947,6 +959,7 @@ def main(): ATM=args.atm_correction, POLE_TIDE=args.pole_tide, DEG1=args.geocenter, + DEG1_FILE=args.geocenter_file, MODEL_DEG1=args.interpolate_geocenter, SLR_C20=args.slr_c20, SLR_21=args.slr_21, diff --git a/version.txt b/version.txt index dcbf270f..af434fa9 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.2.3 \ No newline at end of file +1.0.2.4