Coverage for pySDC/core/BaseTransfer.py: 100%

103 statements  

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

1import logging 

2 

3import scipy.sparse as sp 

4 

5from pySDC.core.Errors import UnlockError 

6from pySDC.helpers.pysdc_helper import FrozenClass 

7from pySDC.core.Lagrange import LagrangeApproximation 

8 

9 

10# short helper class to add params as attributes 

11class _Pars(FrozenClass): 

12 def __init__(self, pars): 

13 self.finter = False 

14 for k, v in pars.items(): 

15 setattr(self, k, v) 

16 

17 self._freeze() 

18 

19 

20class base_transfer(object): 

21 """ 

22 Standard base_transfer class 

23 

24 Attributes: 

25 logger: custom logger for sweeper-related logging 

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

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

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

29 """ 

30 

31 def __init__(self, fine_level, coarse_level, base_transfer_params, space_transfer_class, space_transfer_params): 

32 """ 

33 Initialization routine 

34 

35 Args: 

36 fine_level (pySDC.Level.level): fine level connected with the base_transfer operations 

37 coarse_level (pySDC.Level.level): coarse level connected with the base_transfer operations 

38 base_transfer_params (dict): parameters for the base_transfer operations 

39 space_transfer_class: class to perform spatial transfer 

40 space_transfer_params (dict): parameters for the space_transfer operations 

41 """ 

42 

43 self.params = _Pars(base_transfer_params) 

44 

45 # set up logger 

46 self.logger = logging.getLogger('transfer') 

47 

48 # just copy by object 

49 self.fine = fine_level 

50 self.coarse = coarse_level 

51 

52 fine_grid = self.fine.sweep.coll.nodes 

53 coarse_grid = self.coarse.sweep.coll.nodes 

54 

55 if len(fine_grid) == len(coarse_grid): 

56 self.Pcoll = sp.eye(len(fine_grid)).toarray() 

57 self.Rcoll = sp.eye(len(fine_grid)).toarray() 

58 else: 

59 self.Pcoll = self.get_transfer_matrix_Q(fine_grid, coarse_grid) 

60 self.Rcoll = self.get_transfer_matrix_Q(coarse_grid, fine_grid) 

61 

62 # set up spatial transfer 

63 self.space_transfer = space_transfer_class( 

64 fine_prob=self.fine.prob, coarse_prob=self.coarse.prob, params=space_transfer_params 

65 ) 

66 

67 @staticmethod 

68 def get_transfer_matrix_Q(f_nodes, c_nodes): 

69 """ 

70 Helper routine to quickly define transfer matrices from a coarse set 

71 to a fine set of nodes (fully Lagrangian) 

72 Args: 

73 f_nodes: fine nodes (size nF) 

74 c_nodes: coarse nodes (size nC) 

75 

76 Returns: 

77 matrix containing the interpolation weights (shape (nF, nC)) 

78 """ 

79 approx = LagrangeApproximation(c_nodes) 

80 return approx.getInterpolationMatrix(f_nodes) 

81 

82 def restrict(self): 

83 """ 

84 Space-time restriction routine 

85 

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

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

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

89 fine level are restricted as well. 

90 """ 

91 

92 # get data for easier access 

93 F = self.fine 

94 G = self.coarse 

95 

96 PG = G.prob 

97 

98 SF = F.sweep 

99 SG = G.sweep 

100 

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

102 if not F.status.unlocked: 

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

104 

105 # restrict fine values in space 

106 tmp_u = [] 

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

108 tmp_u.append(self.space_transfer.restrict(F.u[m])) 

109 

110 # restrict collocation values 

111 G.u[0] = self.space_transfer.restrict(F.u[0]) 

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

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

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

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

116 

117 # re-evaluate f on coarse level 

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

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

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

121 

122 # build coarse level tau correction part 

123 tauG = G.sweep.integrate() 

124 

125 # build fine level tau correction part 

126 tauF = F.sweep.integrate() 

127 

128 # restrict fine level tau correction part in space 

129 tmp_tau = [] 

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

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

132 

133 # restrict fine level tau correction part in collocation 

134 tauFG = [] 

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

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

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

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

139 

140 # build tau correction 

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

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

143 

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

145 # restrict possible tau correction from fine in space 

146 tmp_tau = [] 

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

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

149 

150 # restrict possible tau correction from fine in collocation 

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

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

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

154 else: 

155 pass 

156 

157 # save u and rhs evaluations for interpolation 

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

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

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

161 

162 # works as a predictor 

163 G.status.unlocked = True 

164 

165 return None 

166 

167 def prolong(self): 

168 """ 

169 Space-time prolongation routine 

170 

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

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

173 """ 

174 

175 # get data for easier access 

176 F = self.fine 

177 G = self.coarse 

178 

179 PF = F.prob 

180 

181 SF = F.sweep 

182 SG = G.sweep 

183 

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

185 if not G.status.unlocked: 

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

187 

188 # build coarse correction 

189 

190 # interpolate values in space first 

191 tmp_u = [] 

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

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

194 

195 # interpolate values in collocation 

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

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

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

199 

200 # re-evaluate f on fine level 

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

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

203 

204 return None 

205 

206 def prolong_f(self): 

207 """ 

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

209 

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

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

212 """ 

213 

214 # get data for easier access 

215 F = self.fine 

216 G = self.coarse 

217 

218 SF = F.sweep 

219 SG = G.sweep 

220 

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

222 if not G.status.unlocked: 

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

224 

225 # build coarse correction 

226 

227 # interpolate values in space first 

228 tmp_u = [] 

229 tmp_f = [] 

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

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

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

233 

234 # interpolate values in collocation 

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

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

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

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

239 

240 return None