Coverage for pySDC/implementations/sweeper_classes/explicit.py: 0%

46 statements  

« prev     ^ index     » next       coverage.py v7.6.7, created at 2024-11-16 14:51 +0000

1from pySDC.core.sweeper import Sweeper 

2 

3 

4class explicit(Sweeper): 

5 """ 

6 Custom sweeper class, implements Sweeper.py 

7 

8 Attributes: 

9 QE: explicit Euler integration matrix 

10 """ 

11 

12 def __init__(self, params): 

13 """ 

14 Initialization routine for the custom sweeper 

15 

16 Args: 

17 params: parameters for the sweeper 

18 """ 

19 

20 if 'QE' not in params: 

21 params['QE'] = 'EE' 

22 

23 # call parent's initialization routine 

24 super(explicit, self).__init__(params) 

25 

26 # integration matrix 

27 self.QE = self.get_Qdelta_explicit(qd_type=self.params.QE) 

28 

29 def integrate(self): 

30 """ 

31 Integrates the right-hand side 

32 

33 Returns: 

34 list of dtype_u: containing the integral as values 

35 """ 

36 

37 # get current level and problem description 

38 L = self.level 

39 P = L.prob 

40 

41 me = [] 

42 

43 # integrate RHS over all collocation nodes 

44 for m in range(1, self.coll.num_nodes + 1): 

45 # new instance of dtype_u, initialize values with 0 

46 me.append(P.dtype_u(P.init, val=0.0)) 

47 for j in range(1, self.coll.num_nodes + 1): 

48 me[-1] += L.dt * self.coll.Qmat[m, j] * L.f[j] 

49 

50 return me 

51 

52 def update_nodes(self): 

53 """ 

54 Update the u- and f-values at the collocation nodes -> corresponds to a single sweep over all nodes 

55 

56 Returns: 

57 None 

58 """ 

59 

60 # get current level and problem description 

61 L = self.level 

62 P = L.prob 

63 

64 # only if the level has been touched before 

65 assert L.status.unlocked 

66 

67 # get number of collocation nodes for easier access 

68 M = self.coll.num_nodes 

69 

70 # gather all terms which are known already (e.g. from the previous iteration) 

71 # this corresponds to u0 + QF(u^k) - QEFE(u^k) + tau 

72 

73 # get QF(u^k) 

74 integral = self.integrate() 

75 for m in range(M): 

76 # subtract QEFE(u^k)_m 

77 for j in range(1, M + 1): 

78 integral[m] -= L.dt * self.QE[m + 1, j] * L.f[j] 

79 # add initial value 

80 integral[m] += L.u[0] 

81 # add tau if associated 

82 if L.tau[m] is not None: 

83 integral[m] += L.tau[m] 

84 

85 # do the sweep 

86 for m in range(0, M): 

87 # build new u, consisting of the known values from above and new values from previous nodes (at k+1) 

88 L.u[m + 1] = P.dtype_u(integral[m]) 

89 for j in range(1, m + 1): 

90 L.u[m + 1] += L.dt * self.QE[m + 1, j] * L.f[j] 

91 

92 # update function values 

93 L.f[m + 1] = P.eval_f(L.u[m + 1], L.time + L.dt * self.coll.nodes[m]) 

94 

95 # indicate presence of new values at this level 

96 L.status.updated = True 

97 

98 return None 

99 

100 def compute_end_point(self): 

101 """ 

102 Compute u at the right point of the interval 

103 

104 The value uend computed here is a full evaluation of the Picard formulation unless do_full_update==False 

105 

106 Returns: 

107 None 

108 """ 

109 

110 # get current level and problem description 

111 L = self.level 

112 P = L.prob 

113 

114 # check if Mth node is equal to right point and do_coll_update is false, perform a simple copy 

115 if self.coll.right_is_node and not self.params.do_coll_update: 

116 # a copy is sufficient 

117 L.uend = P.dtype_u(L.u[-1]) 

118 else: 

119 # start with u0 and add integral over the full interval (using coll.weights) 

120 L.uend = P.dtype_u(L.u[0]) 

121 for m in range(self.coll.num_nodes): 

122 L.uend += L.dt * self.coll.weights[m] * L.f[m + 1] 

123 # add up tau correction of the full interval (last entry) 

124 if L.tau[-1] is not None: 

125 L.uend += L.tau[-1] 

126 

127 return None