Skip to content

Commit 317d5b7

Browse files
committed
add gl sampling (f00 quad test failing)
1 parent 6c997be commit 317d5b7

File tree

4 files changed

+68
-19
lines changed

4 files changed

+68
-19
lines changed

s2fft/sampling/s2_samples.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def ntheta(L: int = None, sampling: str = "mw", nside: int = None) -> int:
1010
Defaults to None.
1111
1212
sampling (str, optional): Sampling scheme. Supported sampling schemes include
13-
{"mw", "mwss", "dh", "healpix"}. Defaults to "mw".
13+
{"mw", "mwss", "dh", "gl", "healpix"}. Defaults to "mw".
1414
1515
nside (int, optional): HEALPix Nside resolution parameter. Only required
1616
if sampling="healpix". Defaults to None.
@@ -31,7 +31,7 @@ def ntheta(L: int = None, sampling: str = "mw", nside: int = None) -> int:
3131
f"Sampling scheme sampling={sampling} with L={L} not supported"
3232
)
3333

34-
if sampling.lower() == "mw":
34+
if sampling.lower() in ["mw", "gl"]:
3535
return L
3636

3737
elif sampling.lower() == "mwss":
@@ -93,7 +93,7 @@ def nphi_equiang(L: int, sampling: str = "mw") -> int:
9393
L (int): Harmonic band-limit.
9494
9595
sampling (str, optional): Sampling scheme. Supported sampling schemes include
96-
{"mw", "mwss", "dh"}. Defaults to "mw".
96+
{"mw", "mwss", "dh", "gl"}. Defaults to "mw".
9797
9898
Raises:
9999
ValueError: HEALPix sampling scheme.
@@ -104,7 +104,7 @@ def nphi_equiang(L: int, sampling: str = "mw") -> int:
104104
int: Number of :math:`\phi` samples.
105105
"""
106106

107-
if sampling.lower() == "mw":
107+
if sampling.lower() in ["mw", "gl"]:
108108
return 2 * L - 1
109109

110110
elif sampling.lower() == "mwss":
@@ -129,7 +129,7 @@ def ftm_shape(L: int, sampling: str = "mw", nside: int = None) -> Tuple[int, int
129129
L (int): Harmonic band-limit.
130130
131131
sampling (str, optional): Sampling scheme. Supported sampling schemes include
132-
{"mw", "mwss", "dh", "healpix"}. Defaults to "mw".
132+
{"mw", "mwss", "dh", "gl", "healpix"}. Defaults to "mw".
133133
134134
nside (int, optional): HEALPix Nside resolution parameter.
135135
@@ -144,7 +144,7 @@ def ftm_shape(L: int, sampling: str = "mw", nside: int = None) -> Tuple[int, int
144144
if sampling.lower() in ["mwss", "healpix"]:
145145
return ntheta(L, sampling, nside), 2 * L
146146

147-
elif sampling.lower() in ["mw", "dh"]:
147+
elif sampling.lower() in ["mw", "dh", "gl"]:
148148
return ntheta(L, sampling, nside), 2 * L - 1
149149

150150
else:
@@ -203,14 +203,17 @@ def thetas(L: int = None, sampling: str = "mw", nside: int = None) -> np.ndarray
203203
Defaults to None.
204204
205205
sampling (str, optional): Sampling scheme. Supported sampling schemes include
206-
{"mw", "mwss", "dh", "healpix"}. Defaults to "mw".
206+
{"mw", "mwss", "dh", "gl", "healpix"}. Defaults to "mw".
207207
208208
nside (int, optional): HEALPix Nside resolution parameter. Only required
209209
if sampling="healpix". Defaults to None.
210210
211211
Returns:
212212
np.ndarray: Array of :math:`\theta` samples for given sampling scheme.
213213
"""
214+
if sampling.lower() == "gl":
215+
return np.flip(np.arccos(np.polynomial.legendre.leggauss(L)[0]))
216+
214217
t = np.arange(0, ntheta(L=L, sampling=sampling, nside=nside)).astype(np.float64)
215218

216219
return t2theta(t, L, sampling, nside)
@@ -228,7 +231,7 @@ def t2theta(
228231
Defaults to None.
229232
230233
sampling (str, optional): Sampling scheme. Supported sampling schemes include
231-
{"mw", "mwss", "dh", "healpix"}. Defaults to "mw".
234+
{"mw", "mwss", "dh", "gl", "healpix"}. Defaults to "mw".
232235
233236
nside (int, optional): HEALPix Nside resolution parameter. Only required
234237
if sampling="healpix". Defaults to None.
@@ -346,7 +349,7 @@ def phis_equiang(L: int, sampling: str = "mw") -> np.ndarray:
346349
L (int, optional): Harmonic band-limit.
347350
348351
sampling (str, optional): Sampling scheme. Supported equiangular sampling
349-
schemes include {"mw", "mwss", "dh"}. Defaults to "mw".
352+
schemes include {"mw", "mwss", "dh", "gl"}. Defaults to "mw".
350353
351354
Returns:
352355
np.ndarray: Array of :math:`\phi` samples for given sampling scheme.
@@ -365,7 +368,7 @@ def p2phi_equiang(L: int, p: int, sampling: str = "mw") -> np.ndarray:
365368
p (int): :math:`\phi` index.
366369
367370
sampling (str, optional): Sampling scheme. Supported equiangular sampling
368-
schemes include {"mw", "mwss", "dh"}. Defaults to "mw".
371+
schemes include {"mw", "mwss", "dh", "gl"}. Defaults to "mw".
369372
370373
Raises:
371374
ValueError: HEALPix sampling not support (only equiangular schemes supported).
@@ -376,7 +379,7 @@ def p2phi_equiang(L: int, p: int, sampling: str = "mw") -> np.ndarray:
376379
np.ndarray: :math:`\phi` sample(s) for given sampling scheme.
377380
"""
378381

379-
if sampling.lower() == "mw":
382+
if sampling.lower() in ["mw", "gl"]:
380383
return 2 * p * np.pi / (2 * L - 1)
381384

382385
elif sampling.lower() == "mwss":
@@ -431,7 +434,7 @@ def f_shape(L: int = None, sampling: str = "mw", nside: int = None) -> Tuple[int
431434
L (int, optional): Harmonic band-limit.
432435
433436
sampling (str, optional): Sampling scheme. Supported sampling schemes include
434-
{"mw", "mwss", "dh", "healpix"}. Defaults to "mw".
437+
{"mw", "mwss", "dh", "gl", "healpix"}. Defaults to "mw".
435438
436439
nside (int, optional): HEALPix Nside resolution parameter. Only required
437440
if sampling="healpix". Defaults to None.

s2fft/utils/quadrature.py

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def quad_weights_transform(
1616
L (int): Harmonic band-limit.
1717
1818
sampling (str, optional): Sampling scheme. Supported sampling schemes include
19-
{"mwss", "dh", "healpix}. Defaults to "mwss".
19+
{"mwss", "dh", "gl", "healpix}. Defaults to "mwss".
2020
2121
spin (int, optional): Harmonic spin. Defaults to 0.
2222
@@ -38,6 +38,9 @@ def quad_weights_transform(
3838
elif sampling.lower() == "dh":
3939
return quad_weights_dh(L)
4040

41+
elif sampling.lower() == "gl":
42+
return quad_weights_gl(L)
43+
4144
elif sampling.lower() == "healpix":
4245
return quad_weights_hp(nside)
4346

@@ -56,7 +59,7 @@ def quad_weights(
5659
Defaults to None.
5760
5861
sampling (str, optional): Sampling scheme. Supported sampling schemes include
59-
{"mw", "mwss", "dh", "healpix"}. Defaults to "mw".
62+
{"mw", "mwss", "dh", "gl", "healpix"}. Defaults to "mw".
6063
6164
spin (int, optional): Harmonic spin. Defaults to 0.
6265
@@ -80,6 +83,9 @@ def quad_weights(
8083
elif sampling.lower() == "dh":
8184
return quad_weights_dh(L)
8285

86+
elif sampling.lower() == "gl":
87+
return quad_weights_gl(L)
88+
8389
elif sampling.lower() == "healpix":
8490
return quad_weights_hp(nside)
8591

@@ -112,6 +118,43 @@ def quad_weights_hp(nside: int) -> np.ndarray:
112118
return hp_weights
113119

114120

121+
def quad_weights_gl(L: int) -> np.ndarray:
122+
r"""Compute GL quadrature weights for :math:`\theta` and :math:`\phi` integration.
123+
124+
Args:
125+
L (int): Harmonic band-limit.
126+
127+
Returns:
128+
np.ndarray: Weights computed for each :math:`\theta` (weights are identical
129+
as :math:`\phi` varies for given :math:`\theta`).
130+
"""
131+
x1, x2 = -1.0, 1.0
132+
ntheta = samples.ntheta(L, "gl")
133+
weights = np.zeros(ntheta, dtype=np.float64)
134+
135+
m = int((L + 1) / 2)
136+
x1 = 0.5 * (x2 - x1)
137+
138+
for i in range(1, m + 1):
139+
z = np.cos(np.pi * (i - 0.25) / (L + 0.5))
140+
z1 = 2.0
141+
while np.abs(z - z1) > 1e-14:
142+
p1 = 1.0
143+
p2 = 0.0
144+
for j in range(1, L + 1):
145+
p3 = p2
146+
p2 = p1
147+
p1 = ((2.0 * j - 1.0) * z * p2 - (j - 1.0) * p3) / j
148+
pp = L * (z * p1 - p2) / (z * z - 1.0)
149+
z1 = z
150+
z = z1 - p1 / pp
151+
152+
weights[i - 1] = 2.0 * x1 / ((1.0 - z**2) * pp * pp)
153+
weights[L + 1 - i - 1] = weights[i - 1]
154+
155+
return weights
156+
157+
115158
def quad_weights_dh(L: int) -> np.ndarray:
116159
r"""Compute DH quadrature weights for :math:`\theta` and :math:`\phi` integration.
117160

tests/test_quadrature.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66

77

88
@pytest.mark.parametrize("L", [5, 6])
9-
@pytest.mark.parametrize("sampling", ["mw", "mwss"])
9+
@pytest.mark.parametrize("sampling", ["gl"])
10+
# @pytest.mark.parametrize("sampling", ["mw", "mwss", "dh", "gl"])
1011
def test_quadrature_mw_weights(flm_generator, L: int, sampling: str):
1112
spin = 0
1213

1314
q = quadrature.quad_weights(L, sampling, spin)
14-
1515
flm = flm_generator(L, spin, reality=False)
1616

1717
f = spherical.inverse(flm, L, spin, sampling)

tests/test_samples.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010

1111
@pytest.mark.parametrize("L", [15, 16])
12-
@pytest.mark.parametrize("sampling", ["mw", "mwss", "dh"])
12+
@pytest.mark.parametrize("sampling", ["mw", "mwss", "dh", "gl"])
1313
def test_samples_n_and_angles(L: int, sampling: str):
1414
# Test ntheta and nphi
1515
ntheta = samples.ntheta(L, sampling)
@@ -18,8 +18,11 @@ def test_samples_n_and_angles(L: int, sampling: str):
1818
assert (ntheta, nphi) == pytest.approx((ntheta_ssht, nphi_ssht))
1919

2020
# Test thetas and phis
21-
t = np.arange(0, ntheta)
22-
thetas = samples.t2theta(t, L, sampling)
21+
if sampling.lower() == "gl":
22+
thetas = samples.thetas(L, sampling)
23+
else:
24+
t = np.arange(0, ntheta)
25+
thetas = samples.t2theta(t, L, sampling)
2326
p = np.arange(0, nphi)
2427
phis = samples.p2phi_equiang(L, p, sampling)
2528
thetas_ssht, phis_ssht = ssht.sample_positions(L, sampling.upper())

0 commit comments

Comments
 (0)