Coverage for pySDC/implementations/problem_classes/boussinesq_helpers/buildFDMatrix.py: 100%
42 statements
« prev ^ index » next coverage.py v7.16.1, created at 2026-09-23 08:40 +0000
« prev ^ index » next coverage.py v7.16.1, created at 2026-09-23 08:40 +0000
1import scipy.sparse as sp
3from pySDC.helpers.problem_helper import (
4 get_finite_difference_matrix,
5 get_finite_difference_stencil,
6)
9def getUpwindMatrix(N, dx, order):
10 A, _ = get_finite_difference_matrix(
11 derivative=1, order=order, stencil_type='upwind', dx=dx, size=N, dim=1, bc='periodic'
12 )
13 return sp.csc_matrix(A)
16def getMatrix(N, dx, bc_left, bc_right, order):
17 r"""
18 Centered first derivative matrix for homogeneous boundary conditions.
20 For periodic boundaries this is just the generic finite difference matrix. For Neumann and
21 Dirichlet boundaries only the interior stencil is taken from the generic helper, while the
22 rows next to the boundary keep the closures that were derived for this problem.
24 These closures are *not* interchangeable with the ones the generic helper builds, even though
25 the generic ones are more accurate: the Boussinesq operator differentiates the pressure with
26 the Neumann closure and the vertical velocity with the Dirichlet closure, and neutral stability
27 of the resulting wave operator depends on how those two closures relate to each other. Building
28 each of them in isolation, as the generic helper does, gives a discretisation whose spectrum has
29 positive real parts and which therefore grows exponentially in time. See #233.
30 """
31 assert bc_left in ['periodic', 'neumann', 'dirichlet'], "Unknown type of BC"
32 assert bc_right in ['periodic', 'neumann', 'dirichlet'], "Unknown type of BC"
34 if bc_left == 'periodic' or bc_right == 'periodic':
35 assert bc_left == bc_right, "Periodic BC can only be selected for both sides simultaneously"
36 A, _ = get_finite_difference_matrix(
37 derivative=1, order=order, stencil_type='center', dx=dx, size=N, dim=1, bc='periodic'
38 )
39 return sp.csc_matrix(A)
41 assert order in [2, 4], "Neumann and Dirichlet closures are only available for order 2 and 4"
43 coeff, steps = get_finite_difference_stencil(derivative=1, order=order, stencil_type='center')
44 A = sp.lil_matrix(sp.diags(coeff, steps, shape=(N, N)))
46 # Neumann boundary conditions
47 if bc_left == 'neumann':
48 A[0, :] = 0.0
49 if order == 2:
50 A[0, 0] = -2.0 / 3.0
51 A[0, 1] = 2.0 / 3.0
52 elif order == 4:
53 A[0, 0] = -2.0 / 3.0
54 A[0, 1] = 2.0 / 3.0
55 A[1, 0] = -5.0 / 9.0
56 A[1, 1] = -1.0 / 36.0
58 if bc_right == 'neumann':
59 A[N - 1, :] = 0.0
60 if order == 2:
61 A[N - 1, N - 2] = -2.0 / 3.0
62 A[N - 1, N - 1] = 2.0 / 3.0
63 elif order == 4:
64 A[N - 2, N - 1] = 5.0 / 9.0
65 A[N - 2, N - 2] = 1.0 / 36.0
66 A[N - 1, N - 1] = 2.0 / 3.0
67 A[N - 1, N - 2] = -2.0 / 3.0
69 # Dirichlet boundary conditions. For order 2 the ghost value drops out of the stencil, so
70 # there is nothing to do.
71 if bc_left == 'dirichlet' and order == 4:
72 A[0, :] = 0.0
73 A[0, 1] = 1.0 / 2.0
75 if bc_right == 'dirichlet' and order == 4:
76 A[N - 1, :] = 0.0
77 A[N - 1, N - 2] = -1.0 / 2.0
79 return sp.csc_matrix(A / dx)