Skip to content

Commit 4412bf4

Browse files
Added linear transformation for non-standard domains in Chebychev and Ultraspherical methods (#536)
* Added linear transformation for non-standard domains in Chebychev and Ultraspherical methods Co-authored-by: tlunet * Removed clutter in tests
1 parent a97728a commit 4412bf4

File tree

3 files changed

+75
-28
lines changed

3 files changed

+75
-28
lines changed

pySDC/helpers/spectral_helper.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,9 @@ def __init__(self, *args, transform_type='fft', x0=-1, x1=1, **kwargs):
194194
x0 (float): Coordinate of left boundary. Note that only -1 is currently implented
195195
x1 (float): Coordinate of right boundary. Note that only +1 is currently implented
196196
"""
197-
assert x0 == -1
198-
assert x1 == 1
197+
# need linear transformation y = ax + b with a = (x1-x0)/2 and b = (x1+x0)/2
198+
self.lin_trf_fac = (x1 - x0) / 2
199+
self.lin_trf_off = (x1 + x0) / 2
199200
super().__init__(*args, x0=x0, x1=x1, **kwargs)
200201
self.transform_type = transform_type
201202

@@ -214,7 +215,7 @@ def get_1dgrid(self):
214215
Returns:
215216
numpy.ndarray: 1D grid
216217
'''
217-
return self.xp.cos(np.pi / self.N * (self.xp.arange(self.N) + 0.5))
218+
return self.lin_trf_fac * self.xp.cos(np.pi / self.N * (self.xp.arange(self.N) + 0.5)) + self.lin_trf_off
218219

219220
def get_wavenumbers(self):
220221
"""Get the domain in spectral space"""
@@ -306,7 +307,7 @@ def get_integration_matrix(self, lbnd=0):
306307
(n / (2 * (self.xp.arange(self.N) + 1)))[1::2]
307308
* (-1) ** (self.xp.arange(self.N // 2))
308309
/ (np.append([1], self.xp.arange(self.N // 2 - 1) + 1))
309-
)
310+
) * self.lin_trf_fac
310311
else:
311312
raise NotImplementedError(f'This function allows to integrate only from x=0, you attempted from x={lbnd}.')
312313
return S
@@ -327,7 +328,7 @@ def get_differentiation_matrix(self, p=1):
327328
D[k, j] = 2 * j * ((j - k) % 2)
328329

329330
D[0, :] /= 2
330-
return self.sparse_lib.csc_matrix(self.xp.linalg.matrix_power(D, p))
331+
return self.sparse_lib.csc_matrix(self.xp.linalg.matrix_power(D, p)) / self.lin_trf_fac**p
331332

332333
def get_norm(self, N=None):
333334
'''
@@ -565,7 +566,7 @@ def get_differentiation_matrix(self, p=1):
565566
xp = self.xp
566567
N = self.N
567568
l = p
568-
return 2 ** (l - 1) * factorial(l - 1) * sp.diags(xp.arange(N - l) + l, offsets=l)
569+
return 2 ** (l - 1) * factorial(l - 1) * sp.diags(xp.arange(N - l) + l, offsets=l) / self.lin_trf_fac**p
569570

570571
def get_S(self, lmbda):
571572
"""
@@ -647,8 +648,10 @@ def get_integration_matrix(self):
647648
Returns:
648649
sparse integration matrix
649650
"""
650-
return self.sparse_lib.diags(1 / (self.xp.arange(self.N - 1) + 1), offsets=-1) @ self.get_basis_change_matrix(
651-
p_out=1, p_in=0
651+
return (
652+
self.sparse_lib.diags(1 / (self.xp.arange(self.N - 1) + 1), offsets=-1)
653+
@ self.get_basis_change_matrix(p_out=1, p_in=0)
654+
* self.lin_trf_fac
652655
)
653656

654657
def get_integration_constant(self, u_hat, axis):

pySDC/tests/test_helpers/test_spectral_helper_1d_chebychev.py

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def test_differentiation_matrix(N):
7979
from pySDC.helpers.spectral_helper import ChebychevHelper
8080

8181
cheby = ChebychevHelper(N)
82-
x = np.cos(np.pi / N * (np.arange(N) + 0.5))
82+
x = cheby.get_1dgrid()
8383
coeffs = np.random.random(N)
8484
norm = cheby.get_norm()
8585

@@ -91,6 +91,36 @@ def test_differentiation_matrix(N):
9191
assert np.allclose(exact, du)
9292

9393

94+
@pytest.mark.base
95+
@pytest.mark.parametrize('N', [4, 7, 32])
96+
@pytest.mark.parametrize('x0', [-1, 0])
97+
@pytest.mark.parametrize('x1', [0.789, 1])
98+
@pytest.mark.parametrize('p', [1, 2])
99+
def test_differentiation_non_standard_domain_size(N, x0, x1, p):
100+
import numpy as np
101+
import scipy
102+
from pySDC.helpers.spectral_helper import ChebychevHelper
103+
104+
cheby = ChebychevHelper(N, x0=x0, x1=x1)
105+
x = cheby.get_1dgrid()
106+
assert all(x > x0)
107+
assert all(x < x1)
108+
109+
coeffs = np.random.random(N)
110+
u = np.polynomial.Chebyshev(coeffs)(x)
111+
u_hat = cheby.transform(u)
112+
du_exact = np.polynomial.Chebyshev(coeffs).deriv(p)(x)
113+
du_hat_exact = cheby.transform(du_exact)
114+
115+
D = cheby.get_differentiation_matrix(p)
116+
117+
du_hat = D @ u_hat
118+
du = cheby.itransform(du_hat)
119+
120+
assert np.allclose(du_hat_exact, du_hat), np.linalg.norm(du_hat_exact - du_hat)
121+
assert np.allclose(du, du_exact), np.linalg.norm(du_exact - du)
122+
123+
94124
@pytest.mark.base
95125
@pytest.mark.parametrize('N', [4, 32])
96126
def test_integration_matrix(N):
@@ -121,7 +151,8 @@ def test_transform(N, d, transform_type):
121151
cheby = ChebychevHelper(N, transform_type=transform_type)
122152
u = np.random.random((d, N))
123153
norm = cheby.get_norm()
124-
x = cheby.get_1dgrid()
154+
x = (cheby.get_1dgrid() * cheby.lin_trf_fac + cheby.lin_trf_off) * cheby.lin_trf_fac + cheby.lin_trf_off
155+
x = (cheby.get_1dgrid() - cheby.lin_trf_off) / cheby.lin_trf_fac
125156

126157
itransform = cheby.itransform(u, axis=-1).real
127158

@@ -370,15 +401,3 @@ def test_tau_method2D_diffusion(nz, nx, bc_val, plotting=False):
370401
assert np.allclose(
371402
polys[i](z), sol[0, i, :]
372403
), f'Solution is incorrectly transformed back to real space at x={x[i]}'
373-
374-
375-
if __name__ == '__main__':
376-
test_differentiation_matrix(4, 'T2U')
377-
# test_transform(6, 1, 'fft')
378-
# test_tau_method('T2U', -1.0, N=4, bc_val=3.0)
379-
# test_tau_method2D('T2T', -1, nx=2**7, nz=2**6, bc_val=4.0, plotting=True)
380-
# test_integration_matrix(5, 'T2U')
381-
# test_integration_matrix2D(2**0, 2**2, 'T2U', 'z')
382-
# test_differentiation_matrix2D(2**7, 2**7, 'T2U', 'mixed')
383-
# test_integration_BC(6)
384-
# test_filter(12, 2, 5, 'T2U')

pySDC/tests/test_helpers/test_spectral_helper_1d_ultraspherical.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,37 @@ def test_differentiation_matrix(N, p):
2121
assert np.allclose(exact, du)
2222

2323

24+
@pytest.mark.base
25+
@pytest.mark.parametrize('N', [4, 7, 32])
26+
@pytest.mark.parametrize('x0', [-1, 0])
27+
@pytest.mark.parametrize('x1', [0.789, 1])
28+
@pytest.mark.parametrize('p', [1, 2])
29+
def test_differentiation_non_standard_domain_size(N, x0, x1, p):
30+
import numpy as np
31+
import scipy
32+
from pySDC.helpers.spectral_helper import UltrasphericalHelper
33+
34+
helper = UltrasphericalHelper(N, x0=x0, x1=x1)
35+
x = helper.get_1dgrid()
36+
assert all(x > x0)
37+
assert all(x < x1)
38+
39+
coeffs = np.random.random(N)
40+
u = np.polynomial.Chebyshev(coeffs)(x)
41+
u_hat = helper.transform(u)
42+
du_exact = np.polynomial.Chebyshev(coeffs).deriv(p)(x)
43+
du_hat_exact = helper.transform(du_exact)
44+
45+
D = helper.get_differentiation_matrix(p)
46+
Q = helper.get_basis_change_matrix(p_in=p, p_out=0)
47+
48+
du_hat = Q @ D @ u_hat
49+
du = helper.itransform(du_hat)
50+
51+
assert np.allclose(du_hat_exact, du_hat), np.linalg.norm(du_hat_exact - du_hat)
52+
assert np.allclose(du, du_exact), np.linalg.norm(du_exact - du)
53+
54+
2455
@pytest.mark.base
2556
@pytest.mark.parametrize('N', [4, 7, 32])
2657
def test_integration(N):
@@ -94,9 +125,3 @@ def test_poisson_problem(N, deg, Dirichlet_recombination):
94125

95126
assert np.allclose(u_hat[deg + 3 :], 0)
96127
assert np.allclose(u_exact, u)
97-
98-
99-
if __name__ == '__main__':
100-
# test_differentiation_matrix(6, 2)
101-
test_poisson_problem(6, 1, True)
102-
# test_integration()

0 commit comments

Comments
 (0)