Coverage for pySDC/implementations/problem_classes/AdvectionEquation_ND_FD.py: 100%
23 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-17 13:41 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-17 13:41 +0000
1from pySDC.implementations.problem_classes.generic_ND_FD import GenericNDimFinDiff
4# noinspection PyUnusedLocal
5class advectionNd(GenericNDimFinDiff):
6 r"""
7 Example implementing the unforced ND advection equation with periodic
8 or Dirichlet boundary conditions in :math:`[0,1]^N`
10 .. math::
11 \frac{\partial u}{\partial t} = -c \frac{\partial u}{\partial x},
13 and initial solution of the form
15 .. math::
16 u({\bf x},0) = \prod_{i=1}^N \sin(f\pi x_i),
18 with :math:`x_i` the coordinate in :math:`i^{th}` dimension.
19 Discretization uses central finite differences.
21 Parameters
22 ----------
23 nvars : int of tuple, optional
24 Spatial resolution (same in all dimensions). Using a tuple allows to
25 consider several dimensions, e.g ``nvars=(16,16)`` for a 2D problem.
26 c : float, optional
27 Advection speed (same in all dimensions).
28 freq : int of tuple, optional
29 Spatial frequency :math:`f` of the initial conditions, can be tuple.
30 stencil_type : str, optional
31 Type of the finite difference stencil.
32 order : int, optional
33 Order of the finite difference discretization.
34 lintol : float, optional
35 Tolerance for spatial solver (GMRES).
36 liniter : int, optional
37 Max. iterations number for GMRES.
38 solver_type : str, optional
39 Solve the linear system directly or using GMRES or CG
40 bc : str, optional
41 Boundary conditions, either ``'periodic'`` or ``'dirichlet'``.
42 dtype : dtype-like, optional
43 Precision the state is stored at, ``float64`` by default. See :class:`GenericNDimFinDiff`.
44 useGPU : bool, optional
45 Run on the GPU with CuPy instead of on the CPU with NumPy.
46 solve_precision : dtype-like or None, optional
47 Precision the implicit solve runs at, independently of ``dtype``. See :class:`GenericNDimFinDiff`.
48 sigma : float, optional
49 If ``freq=-1`` and ``ndim=1``, uses a Gaussian initial solution of the form
51 .. math::
52 u(x,0) = e^{
53 \frac{\displaystyle 1}{\displaystyle 2}
54 \left(
55 \frac{\displaystyle x-1/2}{\displaystyle \sigma}
56 \right)^2
57 }
59 Attributes
60 ----------
61 A : sparse matrix (CSC)
62 FD discretization matrix of the ND grad operator.
63 Id : sparse matrix (CSC)
64 Identity matrix of the same dimension as A.
66 Note
67 ----
68 Args can be set as values or as tuples, which will increase the dimension.
69 Do, however, take care that all spatial parameters have the same dimension.
70 """
72 def __init__(
73 self,
74 nvars=512,
75 c=1.0,
76 freq=2,
77 stencil_type='center',
78 order=2,
79 lintol=1e-12,
80 liniter=10000,
81 solver_type='direct',
82 bc='periodic',
83 sigma=6e-2,
84 dtype='float64',
85 useGPU=False,
86 solve_precision=None,
87 ):
88 """Initialization routine"""
89 super().__init__(
90 nvars,
91 -c,
92 1,
93 freq,
94 stencil_type,
95 order,
96 lintol,
97 liniter,
98 solver_type,
99 bc,
100 dtype=dtype,
101 useGPU=useGPU,
102 solve_precision=solve_precision,
103 )
105 if solver_type == 'CG': # pragma: no cover
106 self.logger.warning('CG is not usually used for advection equation')
107 self._makeAttributeAndRegister('c', localVars=locals(), readOnly=True)
108 self._makeAttributeAndRegister('sigma', localVars=locals())
110 def u_exact(self, t, **kwargs):
111 r"""
112 Routine to compute the exact solution at time :math:`t`.
114 Parameters
115 ----------
116 t : float
117 Time of the exact solution.
118 **kwargs : dict
119 Additional arguments (that won't be used).
121 Returns
122 -------
123 sol : dtype_u
124 The exact solution.
125 """
126 if 'u_init' in kwargs.keys() or 't_init' in kwargs.keys():
127 self.logger.warning(
128 f'{type(self).__name__} uses an analytic exact solution from t=0. If you try to compute the local error, you will get the global error instead!'
129 )
131 # Initialize pointers and variables
132 ndim, freq, c, sigma, sol = self.ndim, self.freq, self.c, self.sigma, self.u_init
134 if ndim == 1:
135 x = self.grids
136 if freq[0] >= 0:
137 sol[:] = self.xp.sin(self.xp.pi * freq[0] * (x - c * t))
138 elif freq[0] == -1:
139 # Gaussian initial solution
140 sol[:] = self.xp.exp(-0.5 * (((x - (c * t)) % 1.0 - 0.5) / sigma) ** 2)
142 elif ndim == 2:
143 x, y = self.grids
144 sol[:] = self.xp.sin(self.xp.pi * freq[0] * (x - c * t)) * self.xp.sin(self.xp.pi * freq[1] * (y - c * t))
146 elif ndim == 3:
147 x, y, z = self.grids
148 sol[:] = (
149 self.xp.sin(self.xp.pi * freq[0] * (x - c * t))
150 * self.xp.sin(self.xp.pi * freq[1] * (y - c * t))
151 * self.xp.sin(self.xp.pi * freq[2] * (z - c * t))
152 )
154 return sol