Coverage for pySDC/implementations/problem_classes/polynomial_test_problem.py: 100%

36 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-11-02 12:30 +0000

1import numpy as np 

2 

3from pySDC.core.problem import Problem 

4from pySDC.implementations.datatype_classes.mesh import mesh, imex_mesh 

5 

6 

7class polynomial_testequation(Problem): 

8 """ 

9 Scalar ODE whose exact solution is a random polynomial in time, to test operations exact on polynomials. 

10 

11 Dummy problem for tests only! In particular, the `solve_system` function just returns the exact solution instead of 

12 solving an appropriate system. This class is indented to be used for tests of operations that are exact on polynomials. 

13 

14 Parameters 

15 ---------- 

16 degree : int, optional 

17 Number of coefficients of the polynomial, i.e., the polynomial has degree ``degree - 1``. 

18 seed : int, optional 

19 Seed for ``np.random.RandomState``, which draws the coefficients uniformly from :math:`[0, 1)`. 

20 useGPU : bool, optional 

21 Use ``CuPy`` for the solution. This switches the data types of the class, not only of this instance. 

22 """ 

23 

24 dtype_u = mesh 

25 dtype_f = mesh 

26 xp = np 

27 

28 def __init__(self, degree=1, seed=26266, useGPU=False): 

29 """Initialization routine""" 

30 

31 if useGPU: 

32 import cupy as cp 

33 from pySDC.implementations.datatype_classes.cupy_mesh import cupy_mesh, imex_cupy_mesh 

34 

35 # on the instance, since setting them on the class would switch every later instance to the GPU 

36 self.xp = cp 

37 self.dtype_u = cupy_mesh 

38 self.dtype_f = imex_cupy_mesh if self.dtype_f is imex_mesh else cupy_mesh 

39 

40 # invoke super init, passing number of dofs, dtype_u and dtype_f 

41 super().__init__(init=(1, None, np.dtype('float64'))) 

42 

43 self.rng = np.random.RandomState(seed=seed) 

44 self.poly = np.polynomial.Polynomial(self.rng.rand(degree)) 

45 self._makeAttributeAndRegister('degree', 'seed', localVars=locals(), readOnly=True) 

46 

47 def eval_f(self, u, t): 

48 """ 

49 Derivative of the polynomial. 

50 

51 Parameters 

52 ---------- 

53 u : dtype_u 

54 Current values of the numerical solution. 

55 t : float 

56 Current time of the numerical solution is computed. 

57 

58 Returns 

59 ------- 

60 f : dtype_f 

61 The right-hand side of the problem. 

62 """ 

63 

64 f = self.dtype_f(self.init) 

65 f[:] = self.xp.array(self.poly.deriv(m=1)(t)) 

66 return f 

67 

68 def solve_system(self, rhs, factor, u0, t): 

69 """ 

70 Just return the exact solution... 

71 

72 Parameters 

73 ---------- 

74 rhs : dtype_f 

75 Right-hand side for the linear system. 

76 factor : float 

77 Abbrev. for the local stepsize (or any other factor required). 

78 u0 : dtype_u 

79 Initial guess for the iterative solver. 

80 t : float 

81 Current time (e.g. for time-dependent BCs). 

82 

83 Returns 

84 ------- 

85 me : dtype_u 

86 The solution as mesh. 

87 """ 

88 

89 return self.u_exact(t) 

90 

91 def u_exact(self, t, **kwargs): 

92 """ 

93 Evaluate the polynomial. 

94 

95 Parameters 

96 ---------- 

97 t : float 

98 Time of the exact solution. 

99 **kwargs 

100 Takes ``u_init`` and ``t_init`` of the generic interface, which are ignored since the polynomial is known 

101 everywhere. 

102 

103 Returns 

104 ------- 

105 me : dtype_u 

106 The exact solution. 

107 """ 

108 me = self.dtype_u(self.init) 

109 me[:] = self.xp.array(self.poly(t)) 

110 return me 

111 

112 

113class polynomial_testequation_IMEX(polynomial_testequation): 

114 """ 

115 IMEX version of the polynomial test problem that assigns half the derivative to the implicit part and the other half to the explicit part. 

116 Keep in mind that you still cannot Really perform any solves. 

117 """ 

118 

119 dtype_f = imex_mesh 

120 

121 def eval_f(self, u, t): 

122 """ 

123 Derivative of the polynomial. 

124 

125 Parameters 

126 ---------- 

127 u : dtype_u 

128 Current values of the numerical solution. 

129 t : float 

130 Current time of the numerical solution is computed. 

131 

132 Returns 

133 ------- 

134 f : dtype_f 

135 The right-hand side of the problem. 

136 """ 

137 

138 f = self.dtype_f(self.init) 

139 derivative = self.xp.array(self.poly.deriv(m=1)(t)) 

140 f.impl[:] = derivative / 2 

141 f.expl[:] = derivative / 2 

142 return f