Coverage for pySDC/implementations/transfer_classes/BaseTransfer_mass.py: 0%

84 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-04-29 09:02 +0000

1from pySDC.core.BaseTransfer import base_transfer 

2from pySDC.core.Errors import UnlockError 

3 

4 

5class base_transfer_mass(base_transfer): 

6 """ 

7 Standard base_transfer class 

8 

9 Attributes: 

10 logger: custom logger for sweeper-related logging 

11 params(__Pars): parameter object containing the custom parameters passed by the user 

12 fine (pySDC.Level.level): reference to the fine level 

13 coarse (pySDC.Level.level): reference to the coarse level 

14 """ 

15 

16 def restrict(self): 

17 """ 

18 Space-time restriction routine 

19 

20 The routine applies the spatial restriction operator to teh fine values on the fine nodes, then reevaluates f 

21 on the coarse level. This is used for the first part of the FAS correction tau via integration. The second part 

22 is the integral over the fine values, restricted to the coarse level. Finally, possible tau corrections on the 

23 fine level are restricted as well. 

24 """ 

25 

26 # get data for easier access 

27 F = self.fine 

28 G = self.coarse 

29 

30 PG = G.prob 

31 PF = F.prob 

32 

33 SF = F.sweep 

34 SG = G.sweep 

35 

36 # only if the level is unlocked at least by prediction 

37 if not F.status.unlocked: 

38 raise UnlockError('fine level is still locked, cannot use data from there') 

39 

40 # restrict fine values in space 

41 tmp_u = [] 

42 for m in range(1, SF.coll.num_nodes + 1): 

43 tmp_u.append(self.space_transfer.project(F.u[m])) 

44 

45 # restrict collocation values 

46 G.u[0] = self.space_transfer.project(F.u[0]) 

47 for n in range(1, SG.coll.num_nodes + 1): 

48 G.u[n] = self.Rcoll[n - 1, 0] * tmp_u[0] 

49 for m in range(1, SF.coll.num_nodes): 

50 G.u[n] += self.Rcoll[n - 1, m] * tmp_u[m] 

51 

52 # re-evaluate f on coarse level 

53 G.f[0] = PG.eval_f(G.u[0], G.time) 

54 for m in range(1, SG.coll.num_nodes + 1): 

55 G.f[m] = PG.eval_f(G.u[m], G.time + G.dt * SG.coll.nodes[m - 1]) 

56 

57 # build coarse level tau correction part 

58 tauG = G.sweep.integrate() 

59 

60 for m in range(SG.coll.num_nodes): 

61 tauG[m] = PG.apply_mass_matrix(G.u[m + 1]) - tauG[m] 

62 

63 # build fine level tau correction part 

64 tauF = F.sweep.integrate() 

65 

66 for m in range(SF.coll.num_nodes): 

67 tauF[m] = PF.apply_mass_matrix(F.u[m + 1]) - tauF[m] 

68 

69 # restrict fine level tau correction part in space 

70 tmp_tau = [] 

71 for m in range(SF.coll.num_nodes): 

72 tmp_tau.append(self.space_transfer.restrict(tauF[m])) 

73 

74 # restrict fine level tau correction part in collocation 

75 tauFG = [] 

76 for n in range(1, SG.coll.num_nodes + 1): 

77 tauFG.append(self.Rcoll[n - 1, 0] * tmp_tau[0]) 

78 for m in range(1, SF.coll.num_nodes): 

79 tauFG[-1] += self.Rcoll[n - 1, m] * tmp_tau[m] 

80 

81 # build tau correction 

82 for m in range(SG.coll.num_nodes): 

83 G.tau[m] = tauG[m] - tauFG[m] 

84 

85 if F.tau[0] is not None: 

86 # restrict possible tau correction from fine in space 

87 tmp_tau = [] 

88 for m in range(SF.coll.num_nodes): 

89 tmp_tau.append(self.space_transfer.restrict(F.tau[m])) 

90 

91 # restrict possible tau correction from fine in collocation 

92 for n in range(SG.coll.num_nodes): 

93 for m in range(SF.coll.num_nodes): 

94 G.tau[n] += self.Rcoll[n, m] * tmp_tau[m] 

95 else: 

96 pass 

97 

98 # save u and rhs evaluations for interpolation 

99 for m in range(1, SG.coll.num_nodes + 1): 

100 G.uold[m] = PG.dtype_u(G.u[m]) 

101 G.fold[m] = PG.dtype_f(G.f[m]) 

102 

103 # This is somewhat ugly, but we have to apply the mass matrix on u0 only on the finest level 

104 if F.level_index == 0: 

105 G.u[0] = self.space_transfer.restrict(PF.apply_mass_matrix(F.u[0])) 

106 

107 # works as a predictor 

108 G.status.unlocked = True 

109 

110 return None 

111 

112 def prolong(self): 

113 """ 

114 Space-time prolongation routine 

115 

116 This routine applies the spatial prolongation routine to the difference between the computed and the restricted 

117 values on the coarse level and then adds this difference to the fine values as coarse correction. 

118 """ 

119 

120 # get data for easier access 

121 F = self.fine 

122 G = self.coarse 

123 

124 PF = F.prob 

125 

126 SF = F.sweep 

127 SG = G.sweep 

128 

129 # only of the level is unlocked at least by prediction or restriction 

130 if not G.status.unlocked: 

131 raise UnlockError('coarse level is still locked, cannot use data from there') 

132 

133 # build coarse correction 

134 

135 # interpolate values in space first 

136 tmp_u = [] 

137 for m in range(1, SG.coll.num_nodes + 1): 

138 tmp_u.append(self.space_transfer.prolong(G.u[m] - G.uold[m])) 

139 

140 # interpolate values in collocation 

141 # F.u[0] += tmp_u[0] 

142 for n in range(1, SF.coll.num_nodes + 1): 

143 for m in range(SG.coll.num_nodes): 

144 F.u[n] += self.Pcoll[n - 1, m] * tmp_u[m] 

145 

146 # re-evaluate f on fine level 

147 # F.f[0] = PF.eval_f(F.u[0], F.time) 

148 for m in range(1, SF.coll.num_nodes + 1): 

149 F.f[m] = PF.eval_f(F.u[m], F.time + F.dt * SF.coll.nodes[m - 1]) 

150 

151 return None 

152 

153 def prolong_f(self): 

154 """ 

155 Space-time prolongation routine w.r.t. the rhs f 

156 

157 This routine applies the spatial prolongation routine to the difference between the computed and the restricted 

158 values on the coarse level and then adds this difference to the fine values as coarse correction. 

159 """ 

160 

161 # get data for easier access 

162 F = self.fine 

163 G = self.coarse 

164 

165 SF = F.sweep 

166 SG = G.sweep 

167 

168 # only of the level is unlocked at least by prediction or restriction 

169 if not G.status.unlocked: 

170 raise UnlockError('coarse level is still locked, cannot use data from there') 

171 

172 # build coarse correction 

173 

174 # interpolate values in space first 

175 tmp_u = [] 

176 tmp_f = [] 

177 for m in range(1, SG.coll.num_nodes + 1): 

178 tmp_u.append(self.space_transfer.prolong(G.u[m] - G.uold[m])) 

179 tmp_f.append(self.space_transfer.prolong(G.f[m] - G.fold[m])) 

180 

181 # interpolate values in collocation 

182 for n in range(1, SF.coll.num_nodes + 1): 

183 for m in range(SG.coll.num_nodes): 

184 F.u[n] += self.Pcoll[n - 1, m] * tmp_u[m] 

185 F.f[n] += self.Pcoll[n - 1, m] * tmp_f[m] 

186 

187 return None