Skip to content

Commit f1bbef5

Browse files
authored
feat: add ability to use a custom weighting function (#181)
useful for integrating over gaussian grids
1 parent 1c3a230 commit f1bbef5

4 files changed

Lines changed: 64 additions & 16 deletions

File tree

doc/source/_assets/geoid_height.svg

Lines changed: 5 additions & 5 deletions
Loading

doc/source/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,9 @@ def filter(self, record):
112112
pygments_style = 'native'
113113
bibtex_bibfiles = ['_assets/gravity-refs.bib']
114114
bibtex_default_style = 'plain'
115+
plot_formats = ['png']
115116
plot_html_show_formats = False
117+
plot_html_show_source_link = False
116118
numfig = True
117119
numfig_secnum_depth = 1
118120

gravity_toolkit/gen_harmonics.py

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
UPDATE HISTORY:
5050
Updated 07/2026: use np.einsum for spherical harmonic summations
5151
use np.radians to convert from degrees to radians
52+
added custom weighting function for gridded data
5253
Updated 03/2023: improve typing for variables in docstrings
5354
Updated 01/2023: refactored associated legendre polynomials
5455
Updated 04/2022: updated docstrings to numpy documentation format
@@ -129,7 +130,16 @@ def gen_harmonics(data, lon, lat, **kwargs):
129130
return Ylms
130131

131132

132-
def integration(data, lon, lat, LMAX=60, MMAX=None, PLM=0, **kwargs):
133+
def integration(
134+
data,
135+
lon,
136+
lat,
137+
LMAX=60,
138+
MMAX=None,
139+
WEIGHT=None,
140+
PLM=0,
141+
**kwargs,
142+
):
133143
"""
134144
Converts data from the spatial domain to spherical harmonic coefficients
135145
@@ -145,6 +155,8 @@ def integration(data, lon, lat, LMAX=60, MMAX=None, PLM=0, **kwargs):
145155
Upper bound of Spherical Harmonic Degrees
146156
MMAX: int or NoneType, default None
147157
Upper bound of Spherical Harmonic Orders
158+
WEIGHT: np.ndarray or NoneType, default None
159+
Custom latitudinal weighting function for gridded data
148160
PLM: float, default 0
149161
input Legendre polynomials
150162
@@ -164,19 +176,28 @@ def integration(data, lon, lat, LMAX=60, MMAX=None, PLM=0, **kwargs):
164176
th = np.radians(90.0 - np.squeeze(lat))
165177
# reformatting longitudes to range 0:360 (if previously -180:180)
166178
phi = np.where(phi < 0, phi + 2.0 * np.pi, phi)
167-
# grid step in radians
168-
dphi = np.abs(phi[1] - phi[0])
169-
dth = np.abs(th[1] - th[0])
179+
# grid dimensions
180+
nlat = np.int64(len(th))
170181

171182
# LMAX+1 as there are LMAX+1 elements between 0 and LMAX
172183
ll = np.arange(LMAX + 1)
173184
mm = np.arange(MMAX + 1)
174185
# Calculating cos/sin of phi arrays (output [m,phi])
175186
m_phi = np.exp(1j * np.einsum('m...,p...->mp...', mm, phi))
176187

177-
# Multiplying sin(th) with differentials of theta and phi
178-
# to calculate the integration factor at each latitude
179-
int_fact = np.sin(th) * dphi * dth
188+
# use an integration factor for gridded data or
189+
# calculate from sin(theta)*dtheta*dphi
190+
int_fact = np.zeros((nlat))
191+
if WEIGHT is not None:
192+
# Weighting function for integrating gridded data
193+
int_fact[:] = np.broadcast_to(np.atleast_1d(WEIGHT), nlat)
194+
else:
195+
# Multiplying sin(th) with differentials of theta and phi
196+
# to calculate the integration factor at each latitude
197+
dphi = np.abs(phi[1] - phi[0])
198+
dth = np.abs(th[1] - th[0])
199+
int_fact[:] = np.sin(th) * dphi * dth
200+
# normalizing coefficients
180201
coeff = 1.0 / (4.0 * np.pi)
181202

182203
# Calculate polynomials using Holmes and Featherstone (2002) relation
@@ -204,7 +225,15 @@ def integration(data, lon, lat, LMAX=60, MMAX=None, PLM=0, **kwargs):
204225
return Ylms
205226

206227

207-
def fourier(data, lon, lat, LMAX=60, MMAX=None, PLM=0, **kwargs):
228+
def fourier(
229+
data,
230+
lon,
231+
lat,
232+
LMAX=60,
233+
MMAX=None,
234+
PLM=0,
235+
**kwargs,
236+
):
208237
"""
209238
Computes the spherical harmonic coefficients of a spatial field
210239

gravity_toolkit/gen_stokes.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
2: Gigatonnes of mass
3030
3: kg/m^2
3131
list: custom degree-dependent unit conversion factor
32+
WEIGHT: custom latitudinal weighting function for gridded data
3233
PLM: input Legendre polynomials
3334
LOVE: input load Love numbers up to degree LMAX (hl,kl,ll)
3435
@@ -45,6 +46,7 @@
4546
UPDATE HISTORY:
4647
Updated 07/2026: use np.einsum for spherical harmonic summations
4748
use np.radians to convert from degrees to radians
49+
added custom weighting function for gridded data
4850
Updated 06/2025: copy latitude and longitude as float64 for numpy 2.0 stability
4951
Updated 04/2023: allow love numbers to be None for custom units case
5052
Updated 03/2023: improve typing for variables in docstrings
@@ -82,7 +84,16 @@
8284

8385

8486
def gen_stokes(
85-
data, lon, lat, LMIN=0, LMAX=60, MMAX=None, UNITS=1, PLM=None, LOVE=None
87+
data,
88+
lon,
89+
lat,
90+
LMIN=0,
91+
LMAX=60,
92+
MMAX=None,
93+
UNITS=1,
94+
WEIGHT=None,
95+
PLM=None,
96+
LOVE=None,
8697
):
8798
r"""
8899
Converts data from the spatial domain to spherical harmonic
@@ -109,6 +120,8 @@ def gen_stokes(
109120
- ``2``: gigatonnes of mass (Gt)
110121
- ``3``: mm water equivalent thickness (mm w.e., kg/m\ :sup:`2`)
111122
- list: custom degree-dependent unit conversion factor
123+
WEIGHT: np.ndarray or NoneType, default None
124+
Custom latitudinal weighting function for gridded data
112125
PLM: np.ndarray or NoneType, default None
113126
Input Legendre polynomials
114127
LOVE: tuple or NoneType, default None
@@ -132,8 +145,6 @@ def gen_stokes(
132145
# upper bound of spherical harmonic orders (default = LMAX)
133146
MMAX = np.copy(LMAX) if (MMAX is None) else MMAX
134147

135-
# grid dimensions
136-
nlat = np.int64(len(lat))
137148
# Longitude in radians
138149
phi = np.radians(np.squeeze(lon.copy()))
139150
# reformatting longitudes to range 0:360 (if previously -180:180)
@@ -143,6 +154,8 @@ def gen_stokes(
143154
# grid step in radians
144155
dphi = np.abs(phi[1] - phi[0])
145156
dth = np.abs(th[1] - th[0])
157+
# grid dimensions
158+
nlat = np.int64(len(th))
146159

147160
# reforming data to lonXlat if input latXlon
148161
sz = np.shape(data)
@@ -173,6 +186,10 @@ def gen_stokes(
173186
int_fact[:] = np.sin(th) * dphi * dth
174187
else:
175188
raise ValueError(f'Unknown units {UNITS}')
189+
# use a custom weighting function for gridded data if provided
190+
if WEIGHT is not None:
191+
# Weighting function for integrating gridded data
192+
int_fact[:] = np.broadcast_to(np.atleast_1d(WEIGHT), nlat)
176193

177194
# Calculating cos/sin of phi arrays
178195
# output [m,phi]

0 commit comments

Comments
 (0)