From eb34e538f0e981cb59d967e70dda9fee5790e12c Mon Sep 17 00:00:00 2001 From: Tyler Sutterley Date: Mon, 25 Nov 2024 10:17:49 -0800 Subject: [PATCH] fix: deprecated widget object copies for #150 (#151) fix: add polar argument for x == +/-1 to prevent drift feat: allow reading love numbers where degree is infinite --- gravity_toolkit/legendre.py | 4 ++-- gravity_toolkit/legendre_polynomials.py | 8 ++++++-- gravity_toolkit/read_love_numbers.py | 18 +++++++++++++----- gravity_toolkit/tools.py | 17 +++++++++-------- notebooks/GRACE-Spatial-Maps.ipynb | 2 +- scripts/calc_degree_one.py | 2 +- scripts/combine_harmonics.py | 2 +- scripts/convert_harmonics.py | 2 +- scripts/dealiasing_global_uplift.py | 2 +- scripts/grace_raster_grids.py | 2 +- scripts/grace_spatial_error.py | 2 +- scripts/grace_spatial_maps.py | 2 +- scripts/monte_carlo_degree_one.py | 2 +- 13 files changed, 39 insertions(+), 26 deletions(-) diff --git a/gravity_toolkit/legendre.py b/gravity_toolkit/legendre.py index 80ed3811..207b2cec 100644 --- a/gravity_toolkit/legendre.py +++ b/gravity_toolkit/legendre.py @@ -103,7 +103,7 @@ def legendre(l, x, NORMALIZE=False): # Column-by-column recursion for k,mm1 in enumerate(m1): col = ind[k] - # Calculate twocot for underflow case + # Calculate two*cotangent for underflow case twocot = -2.0*x[col]/s[col] P[mm1-1:l+1,col] = 0.0 # Start recursion with proper sign @@ -126,7 +126,7 @@ def legendre(l, x, NORMALIZE=False): count = np.count_nonzero((x != 1) & (np.abs(sn) >= tol)) if (count > 0): nind, = np.nonzero((x != 1) & (np.abs(sn) >= tol)) - # Calculate twocot for normal case + # Calculate two*cotangent for normal case twocot = -2.0*x[nind]/s[nind] # Produce normalization constant for the m = l function d = np.arange(2,2*l+2,2) diff --git a/gravity_toolkit/legendre_polynomials.py b/gravity_toolkit/legendre_polynomials.py index 9554a03c..7f4f2f49 100755 --- a/gravity_toolkit/legendre_polynomials.py +++ b/gravity_toolkit/legendre_polynomials.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" legendre_polynomials.py -Written by Tyler Sutterley (03/2023) +Written by Tyler Sutterley (11/2024) Computes fully normalized Legendre polynomials for an array of x values and their first derivative @@ -33,6 +33,7 @@ http://www.springerlink.com/content/978-3-211-33544-4 UPDATE HISTORY: + Updated 11/2024: add polar argument for x == +/-1 to prevent drift Updated 03/2023: improve typing for variables in docstrings Updated 04/2022: updated docstrings to numpy documentation format Updated 05/2021: define int/float precision to prevent deprecation warning @@ -92,7 +93,8 @@ def legendre_polynomials(lmax, x, ASTYPE=np.float64): # for x=cos(th): u=sin(th) u = np.sqrt(1.0 - x**2) # update where u==0 to eps of data type to prevent invalid divisions - u[u == 0] = np.finfo(u.dtype).eps + u0, = np.nonzero(u == 0) + u[u0] = np.finfo(u.dtype).eps # Initialize the recurrence relation ptemp[0,:] = 1.0 @@ -104,6 +106,8 @@ def legendre_polynomials(lmax, x, ASTYPE=np.float64): ptemp[l,:] = (((2.0*l)-1.0)/l)*x*ptemp[l-1,:] - ((l-1.0)/l)*ptemp[l-2,:] # Normalization is geodesy convention pl[l,:] = np.sqrt((2.0*l)+1.0)*ptemp[l,:] + # Overwrite polar case (x == +/-1) + pl[l,u0] = np.sqrt((2.0*l)+1.0)*x[u0]**l # First derivative of Legendre polynomials for l in range(1,lmax+1): diff --git a/gravity_toolkit/read_love_numbers.py b/gravity_toolkit/read_love_numbers.py index c8742fbe..e018d0b0 100755 --- a/gravity_toolkit/read_love_numbers.py +++ b/gravity_toolkit/read_love_numbers.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" read_love_numbers.py -Written by Tyler Sutterley (05/2024) +Written by Tyler Sutterley (11/2024) Reads sets of load Love numbers from PREM and applies isomorphic parameters Linearly interpolates load Love/Shida numbers for missing degrees @@ -56,6 +56,7 @@ 103(B12), 30205-30229, (1998) UPDATE HISTORY: + Updated 11/2024: allow reading where degree is infinite Updated 05/2024: make subscriptable and allow item assignment Updated 08/2023: add string representation of the love_numbers class Updated 05/2023: use pathlib to define and operate on paths @@ -94,6 +95,9 @@ import numpy as np from gravity_toolkit.utilities import get_data_path +# default maximum degree and order in case of infinite +_default_max_degree = 100000 + # PURPOSE: read load Love/Shida numbers from PREM def read_love_numbers(love_numbers_file, LMAX=None, HEADER=2, COLUMNS=['l','hl','kl','ll'], REFERENCE='CE', FORMAT='tuple'): @@ -179,12 +183,15 @@ def read_love_numbers(love_numbers_file, LMAX=None, HEADER=2, file_contents = extract_love_numbers(love_numbers_file) # compile regular expression operator to find numerical instances - regex_pattern = r'[-+]?(?:(?:\d*\.\d+)|(?:\d+\.?))(?:[Ee][+-]?\d+)?' + regex_pattern = r'[-+]?(?:(?:\d*\.\d+)|(?:\d+\.?)|(?:inf))(?:[Ee][+-]?\d+)?' rx = re.compile(regex_pattern, re.VERBOSE) # extract maximum spherical harmonic degree from final line in file - if LMAX is None: - LMAX = np.int64(rx.findall(file_contents[-1])[COLUMNS.index('l')]) + degree = rx.findall(file_contents[-1])[COLUMNS.index('l')] + if LMAX is None and (degree == 'inf'): + LMAX = np.copy(_default_max_degree) + elif LMAX is None: + LMAX = int(degree) # dictionary of output Love/Shida numbers love = {} @@ -203,7 +210,8 @@ def read_love_numbers(love_numbers_file, LMAX=None, HEADER=2, # replacing fortran double precision exponential love_numbers = rx.findall(file_line.replace('D','E')) # spherical harmonic degree - l = np.int64(love_numbers[COLUMNS.index('l')]) + degree = love_numbers[COLUMNS.index('l')] + l = _default_max_degree if (degree == 'inf') else int(degree) # truncate to spherical harmonic degree LMAX if (l <= LMAX): # convert Love/Shida numbers to float diff --git a/gravity_toolkit/tools.py b/gravity_toolkit/tools.py index 5794e586..27bc8a79 100644 --- a/gravity_toolkit/tools.py +++ b/gravity_toolkit/tools.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" tools.py -Written by Tyler Sutterley (04/2024) +Written by Tyler Sutterley (11/2024) Jupyter notebook, user interface and plotting tools PYTHON DEPENDENCIES: @@ -27,6 +27,7 @@ utilities.py: download and management utilities for files UPDATE HISTORY: + Updated 11/2024: fix deprecated widget object copies Updated 04/2024: add widget for setting endpoint for accessing PODAAC data place colormap registration within try/except to check for existing Updated 05/2023: use pathlib to define and operate on paths @@ -123,7 +124,7 @@ def select_directory(self, **kwargs): self.directory_button ]) else: - self.directory = copy.copy(self.directory_label) + self.directory = self.directory_label # connect directory select button with action self.directory_button.on_click(self.set_directory) @@ -154,7 +155,7 @@ def set_directory(self, b): root.withdraw() root.call('wm', 'attributes', '.', '-topmost', True) b.directory = filedialog.askdirectory() - self.directory_label.value = copy.copy(b.directory) + self.directory_label.value = b.directory def select_product(self): """ @@ -520,7 +521,7 @@ def select_corrections(self, **kwargs): self.GIA_button ]) else: - self.GIA_file = copy.copy(self.GIA_label) + self.GIA_file = self.GIA_label # connect fileselect button with action self.GIA_button.on_click(self.select_GIA_file) @@ -567,7 +568,7 @@ def select_corrections(self, **kwargs): self.remove_button ]) else: - self.remove_file = copy.copy(self.remove_label) + self.remove_file = self.remove_label # connect fileselect button with action self.remove_button.on_click(self.select_remove_file) self.remove_label.observe(self.set_removefile) @@ -615,7 +616,7 @@ def select_corrections(self, **kwargs): self.mask_button ]) else: - self.mask = copy.copy(self.mask_label) + self.mask = self.mask_label # connect fileselect button with action self.mask_button.on_click(self.select_mask_file) @@ -684,7 +685,7 @@ def select_GIA_file(self, b): b.files = filedialog.askopenfilename( filetypes=filetypes, multiple=False) - self.GIA_label.value = copy.copy(b.files) + self.GIA_label.value = b.files def select_remove_file(self, b): """function for removed file selection @@ -730,7 +731,7 @@ def select_mask_file(self, b): defaultextension='nc', filetypes=filetypes, multiple=False) - self.mask_label.value = copy.copy(b.files) + self.mask_label.value = b.files def select_output(self, **kwargs): """ diff --git a/notebooks/GRACE-Spatial-Maps.ipynb b/notebooks/GRACE-Spatial-Maps.ipynb index e0fdb87d..5d654030 100644 --- a/notebooks/GRACE-Spatial-Maps.ipynb +++ b/notebooks/GRACE-Spatial-Maps.ipynb @@ -862,7 +862,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.6" + "version": "3.9.9" }, "vscode": { "interpreter": { diff --git a/scripts/calc_degree_one.py b/scripts/calc_degree_one.py index 8d9861d8..cf48ff3d 100755 --- a/scripts/calc_degree_one.py +++ b/scripts/calc_degree_one.py @@ -471,7 +471,7 @@ def calc_degree_one(base_dir, PROC, DREL, MODEL, LMAX, RAD, dfactor = factors.cmwe # add attributes for earth parameters attributes['earth_radius'] = f'{factors.rad_e:0.3f} cm' - attributes['earth_density'] = f'{factors.rho_e:0.3f} g/cm' + attributes['earth_density'] = f'{factors.rho_e:0.3f} g/cm^3' attributes['earth_gravity_constant'] = f'{factors.GM:0.3f} cm^3/s^2' # Read Smoothed Ocean and Land Functions diff --git a/scripts/combine_harmonics.py b/scripts/combine_harmonics.py index 8daa4617..17df8b35 100644 --- a/scripts/combine_harmonics.py +++ b/scripts/combine_harmonics.py @@ -269,7 +269,7 @@ def combine_harmonics(INPUT_FILE, OUTPUT_FILE, dfactor = factors.get(units) # add attributes for earth parameters attributes['ROOT']['earth_radius'] = f'{factors.rad_e:0.3f} cm' - attributes['ROOT']['earth_density'] = f'{factors.rho_e:0.3f} g/cm' + attributes['ROOT']['earth_density'] = f'{factors.rho_e:0.3f} g/cm^3' attributes['ROOT']['earth_gravity_constant'] = f'{factors.GM:0.3f} cm^3/s^2' # Computing plms for converting to spatial domain diff --git a/scripts/convert_harmonics.py b/scripts/convert_harmonics.py index ca90c247..bc9b97af 100644 --- a/scripts/convert_harmonics.py +++ b/scripts/convert_harmonics.py @@ -183,7 +183,7 @@ def convert_harmonics(INPUT_FILE, OUTPUT_FILE, # add attributes for earth parameters factors = gravtk.units(lmax=LMAX) attributes['earth_radius'] = f'{factors.rad_e:0.3f} cm' - attributes['earth_density'] = f'{factors.rho_e:0.3f} g/cm' + attributes['earth_density'] = f'{factors.rho_e:0.3f} g/cm^3' attributes['earth_gravity_constant'] = f'{factors.GM:0.3f} cm^3/s^2' # calculate associated Legendre polynomials diff --git a/scripts/dealiasing_global_uplift.py b/scripts/dealiasing_global_uplift.py index 422f0bc4..980ff4ec 100644 --- a/scripts/dealiasing_global_uplift.py +++ b/scripts/dealiasing_global_uplift.py @@ -213,7 +213,7 @@ def dealiasing_global_uplift(base_dir, # add attributes for earth parameters factors = gravtk.units(lmax=LMAX).harmonic(*LOVE) attributes['ROOT']['earth_radius'] = f'{factors.rad_e:0.3f} cm' - attributes['ROOT']['earth_density'] = f'{factors.rho_e:0.3f} g/cm' + attributes['ROOT']['earth_density'] = f'{factors.rho_e:0.3f} g/cm^3' attributes['ROOT']['earth_gravity_constant'] = f'{factors.GM:0.3f} cm^3/s^2' # degree dependent factors for converting to output units dfactor = factors.get(UNITS) diff --git a/scripts/grace_raster_grids.py b/scripts/grace_raster_grids.py index 781a6f70..09dcc2a7 100644 --- a/scripts/grace_raster_grids.py +++ b/scripts/grace_raster_grids.py @@ -418,7 +418,7 @@ def grace_raster_grids(base_dir, PROC, DREL, DSET, LMAX, RAD, units_name, units_longname = gravtk.units.get_attributes(units) # add attributes for earth parameters attributes['ROOT']['earth_radius'] = f'{factors.rad_e:0.3f} cm' - attributes['ROOT']['earth_density'] = f'{factors.rho_e:0.3f} g/cm' + attributes['ROOT']['earth_density'] = f'{factors.rho_e:0.3f} g/cm^3' attributes['ROOT']['earth_gravity_constant'] = f'{factors.GM:0.3f} cm^3/s^2' # projection attributes diff --git a/scripts/grace_spatial_error.py b/scripts/grace_spatial_error.py index e5de1c4b..89beb622 100755 --- a/scripts/grace_spatial_error.py +++ b/scripts/grace_spatial_error.py @@ -411,7 +411,7 @@ def grace_spatial_error(base_dir, PROC, DREL, DSET, LMAX, RAD, units_name, units_longname = gravtk.units.get_attributes(units) # add attributes for earth parameters attributes['earth_radius'] = f'{factors.rad_e:0.3f} cm' - attributes['earth_density'] = f'{factors.rho_e:0.3f} g/cm' + attributes['earth_density'] = f'{factors.rho_e:0.3f} g/cm^3' attributes['earth_gravity_constant'] = f'{factors.GM:0.3f} cm^3/s^2' # add attributes to output spatial object attributes['reference'] = f'Output from {pathlib.Path(sys.argv[0]).name}' diff --git a/scripts/grace_spatial_maps.py b/scripts/grace_spatial_maps.py index 39bbf17e..6a814f21 100755 --- a/scripts/grace_spatial_maps.py +++ b/scripts/grace_spatial_maps.py @@ -443,7 +443,7 @@ def grace_spatial_maps(base_dir, PROC, DREL, DSET, LMAX, RAD, units_name, units_longname = gravtk.units.get_attributes(units) # add attributes for earth parameters attributes['earth_radius'] = f'{factors.rad_e:0.3f} cm' - attributes['earth_density'] = f'{factors.rho_e:0.3f} g/cm' + attributes['earth_density'] = f'{factors.rho_e:0.3f} g/cm^3' attributes['earth_gravity_constant'] = f'{factors.GM:0.3f} cm^3/s^2' # add attributes to output spatial object attributes['reference'] = f'Output from {pathlib.Path(sys.argv[0]).name}' diff --git a/scripts/monte_carlo_degree_one.py b/scripts/monte_carlo_degree_one.py index e801ecbc..ad1a3e3a 100644 --- a/scripts/monte_carlo_degree_one.py +++ b/scripts/monte_carlo_degree_one.py @@ -390,7 +390,7 @@ def monte_carlo_degree_one(base_dir, PROC, DREL, LMAX, RAD, dfactor = factors.get('cmwe') # add attributes for earth parameters attributes['earth_radius'] = f'{factors.rad_e:0.3f} cm' - attributes['earth_density'] = f'{factors.rho_e:0.3f} g/cm' + attributes['earth_density'] = f'{factors.rho_e:0.3f} g/cm^3' attributes['earth_gravity_constant'] = f'{factors.GM:0.3f} cm^3/s^2' # Read Smoothed Ocean and Land Functions