Skip to content

Commit 2d7dbe2

Browse files
committed
Bugfix for spatial preconditioners in generic spectral problem class
1 parent 81495ee commit 2d7dbe2

File tree

4 files changed

+106
-22
lines changed

4 files changed

+106
-22
lines changed

pySDC/implementations/problem_classes/generic_spectral.py

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,11 @@ def __init__(
8484
debug (bool): Make additional tests at extra computational cost
8585
"""
8686
solver_args = {} if solver_args is None else solver_args
87+
8788
preconditioner_args = {} if preconditioner_args is None else preconditioner_args
8889
preconditioner_args['drop_tol'] = preconditioner_args.get('drop_tol', 1e-3)
8990
preconditioner_args['fill_factor'] = preconditioner_args.get('fill_factor', 100)
91+
9092
self._makeAttributeAndRegister(
9193
'max_cached_factorizations',
9294
'useGPU',
@@ -209,7 +211,7 @@ def setup_preconditioner(self, Dirichlet_recombination=True, left_preconditioner
209211

210212
self.Pl = self.spectral.sparse_lib.csc_matrix(R)
211213

212-
if Dirichlet_recombination and type(self.axes[-1]).__name__ in ['ChebychevHelper, Ultraspherical']:
214+
if Dirichlet_recombination and type(self.axes[-1]).__name__ in ['ChebychevHelper', 'UltrasphericalHelper']:
213215
_Pr = self.spectral.get_Dirichlet_recombination_matrix(axis=-1)
214216
else:
215217
_Pr = Id
@@ -234,18 +236,21 @@ def solve_system(self, rhs, dt, u0=None, *args, skip_itransform=False, **kwargs)
234236
if self.spectral_space:
235237
rhs_hat = rhs.copy()
236238
if u0 is not None:
237-
u0_hat = self.Pr.T @ u0.copy().flatten()
239+
u0_hat = u0.copy().flatten()
238240
else:
239241
u0_hat = None
240242
else:
241243
rhs_hat = self.spectral.transform(rhs)
242244
if u0 is not None:
243-
u0_hat = self.Pr.T @ self.spectral.transform(u0).flatten()
245+
u0_hat = self.spectral.transform(u0).flatten()
244246
else:
245247
u0_hat = None
246248

247-
if self.useGPU:
248-
self.xp.cuda.Device().synchronize()
249+
# apply inverse right preconditioner to initial guess
250+
if u0_hat is not None and 'direct' not in self.solver_type:
251+
if not hasattr(self, '_Pr_inv'):
252+
self._PR_inv = self.linalg.splu(self.Pr.astype(complex)).solve
253+
u0_hat[...] = self._PR_inv(u0_hat)
249254

250255
rhs_hat = (self.M @ rhs_hat.flatten()).reshape(rhs_hat.shape)
251256
rhs_hat = self.spectral.put_BCs_in_rhs_hat(rhs_hat)
@@ -255,17 +260,13 @@ def solve_system(self, rhs, dt, u0=None, *args, skip_itransform=False, **kwargs)
255260
A = self.M + dt * self.L
256261
A = self.Pl @ self.spectral.put_BCs_in_matrix(A) @ self.Pr
257262

258-
# import numpy as np
259-
# if A.shape[0] < 200:
260-
# import matplotlib.pyplot as plt
263+
# if A.shape[0] < 200e20:
264+
# import matplotlib.pyplot as plt
261265

262-
# # M = self.spectral.put_BCs_in_matrix(self.L.copy())
263-
# M = A # self.L
264-
# im = plt.imshow((M / abs(M)).real)
265-
# # im = plt.imshow(np.log10(abs(A.toarray())).real)
266-
# # im = plt.imshow(((A.toarray())).real)
267-
# plt.colorbar(im)
268-
# plt.show()
266+
# # M = self.spectral.put_BCs_in_matrix(self.L.copy())
267+
# M = A # self.L
268+
# im = plt.spy(M)
269+
# plt.show()
269270

270271
if 'ilu' in self.solver_type.lower():
271272
if dt not in self.cached_factorizations.keys():
@@ -330,9 +331,6 @@ def solve_system(self, rhs, dt, u0=None, *args, skip_itransform=False, **kwargs)
330331
sol_hat = self.spectral.u_init_forward
331332
sol_hat[...] = (self.Pr @ _sol_hat).reshape(sol_hat.shape)
332333

333-
if self.useGPU:
334-
self.xp.cuda.Device().synchronize()
335-
336334
if self.spectral_space:
337335
return sol_hat
338336
else:

pySDC/tests/test_problems/test_RayleighBenard3D.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,37 @@ def test_libraries():
202202
assert P.axes[2].fft_lib == fft
203203

204204

205+
@pytest.mark.mpi4py
206+
@pytest.mark.parametrize('preconditioning', [True, False])
207+
def test_banded_matrix(preconditioning):
208+
from pySDC.implementations.problem_classes.RayleighBenard3D import RayleighBenard3D
209+
210+
P = RayleighBenard3D(
211+
nx=16, ny=16, nz=16, left_preconditioner=preconditioning, Dirichlet_recombination=preconditioning
212+
)
213+
sp = P.spectral.linalg
214+
215+
A = P.M + P.L
216+
A = P.Pl @ P.spectral.put_BCs_in_matrix(A) @ P.Pr
217+
218+
bandwidth = sp.spbandwidth(A)
219+
if preconditioning:
220+
assert all(250 * me < A.shape[0] for me in bandwidth), 'Preconditioned matrix is not banded!'
221+
else:
222+
assert all(2 * me > A.shape[0] for me in bandwidth), 'Unpreconditioned matrix is unexpectedly banded!'
223+
224+
LU = sp.splu(A)
225+
for me in [LU.L, LU.U]:
226+
227+
print(sp.spbandwidth(me), bandwidth)
228+
assert max(sp.spbandwidth(me)) <= max(
229+
bandwidth
230+
), 'One-sided bandwidth of LU decomposition is larger than that of the full matrix!'
231+
232+
205233
if __name__ == '__main__':
206234
# test_eval_f(2**2, 2**1, 'x', False)
207235
# test_libraries()
208236
# test_Poisson_problems(4, 'u')
209-
test_Poisson_problem_w()
237+
# test_Poisson_problem_w()
238+
test_banded_matrix(False)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import pytest
2+
3+
4+
@pytest.mark.base
5+
@pytest.mark.parametrize('use_ultraspherical', [True, False])
6+
@pytest.mark.parametrize('spectral_space', [True, False])
7+
@pytest.mark.parametrize('solver_type', ['bicgstab'])
8+
@pytest.mark.parametrize('left_preconditioner', [True, False])
9+
@pytest.mark.parametrize('Dirichlet_recombination', [True, False])
10+
def test_initial_guess(
11+
use_ultraspherical, spectral_space, solver_type, left_preconditioner, Dirichlet_recombination, nvars=2**4
12+
):
13+
import numpy as np
14+
15+
if use_ultraspherical:
16+
from pySDC.implementations.problem_classes.HeatEquation_Chebychev import Heat1DUltraspherical as problem_class
17+
else:
18+
from pySDC.implementations.problem_classes.HeatEquation_Chebychev import Heat1DChebychev as problem_class
19+
20+
params = {
21+
'nvars': nvars,
22+
'a': 0,
23+
'b': 1,
24+
'f': 0,
25+
'nu': 1e-2,
26+
'debug': True,
27+
'spectral_space': spectral_space,
28+
'solver_type': solver_type,
29+
'solver_args': {'rtol': 1e-12},
30+
'left_preconditioner': left_preconditioner,
31+
'Dirichlet_recombination': Dirichlet_recombination,
32+
}
33+
34+
P = problem_class(
35+
**params,
36+
)
37+
38+
u0 = P.u_exact(0)
39+
dt = 1e-1
40+
u = P.solve_system(u0, dt)
41+
42+
if spectral_space:
43+
error = max(abs((P.M + dt * P.L) @ u.flatten() - P.M @ u0.flatten()))
44+
assert error < 1e-12, error
45+
46+
iter_1 = P.work_counters[P.solver_type].niter
47+
assert iter_1 > 0
48+
49+
u2 = P.solve_system(u0, u0=u, dt=dt)
50+
iter_2 = P.work_counters[P.solver_type].niter - iter_1
51+
52+
assert iter_2 == 0, f'Did {iter_2} extra iterations after doing {iter_1} iterations first time'
53+
assert np.allclose(u, u2)
54+
55+
56+
if __name__ == '__main__':
57+
test_initial_guess(False, True, 'bicgstab', True, True, 2**4)

pySDC/tests/test_problems/test_heat_chebychev.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
@pytest.mark.parametrize('noise', [0, 1e-3])
99
@pytest.mark.parametrize('use_ultraspherical', [True, False])
1010
@pytest.mark.parametrize('spectral_space', [True, False])
11-
@pytest.mark.parametrize('solver_type', ['cached_direct', 'direct', 'gmres', 'bicgstab', 'gmres+ilu', 'bicgstab+ilu'])
11+
@pytest.mark.parametrize('solver_type', ['cached_direct', 'direct', 'bicgstab', 'gmres+ilu', 'bicgstab+ilu'])
1212
def test_heat1d_chebychev(a, b, f, noise, use_ultraspherical, spectral_space, solver_type, nvars=2**4):
1313
import numpy as np
1414

@@ -150,6 +150,6 @@ def test_SDC():
150150

151151

152152
if __name__ == '__main__':
153-
test_SDC()
154-
# test_heat1d_chebychev(1, 0, 1, 0e-3, True, True, 2**4)
153+
# test_SDC()
154+
test_heat1d_chebychev(1, 0, 1, 0e-3, True, True, 'bicgstab', 2**4)
155155
# test_heat2d_chebychev(0, 0, 0, 2, 2, 'ultraspherical', 'fft', 2**6, 2**6)

0 commit comments

Comments
 (0)