Coverage for pySDC/projects/AsympConv/PFASST_conv_Linf.py: 96%

157 statements  

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

1import csv 

2import os 

3 

4# import matplotlib 

5# matplotlib.use('Agg') 

6import matplotlib.pyplot as plt 

7import numpy as np 

8 

9from pySDC.helpers.stats_helper import get_sorted 

10 

11from pySDC.implementations.controller_classes.controller_nonMPI import controller_nonMPI 

12from pySDC.implementations.problem_classes.AdvectionEquation_ND_FD import advectionNd 

13from pySDC.implementations.problem_classes.HeatEquation_ND_FD import heatNd_unforced 

14from pySDC.implementations.sweeper_classes.generic_implicit import generic_implicit 

15from pySDC.implementations.transfer_classes.TransferMesh import mesh_to_mesh 

16 

17 

18def main(): 

19 """ 

20 Main driver running diffusion and advection tests 

21 """ 

22 QI = 'LU' 

23 run_diffusion(QI=QI) 

24 run_advection(QI=QI) 

25 

26 QI = 'LU2' 

27 run_diffusion(QI=QI) 

28 run_advection(QI=QI) 

29 

30 plot_results() 

31 

32 

33def run_diffusion(QI, max_proc_exp=13): 

34 """ 

35 A simple test program to test PFASST convergence for the heat equation with random initial data 

36 

37 Args: 

38 QI: preconditioner 

39 max_proc_exp: max number of processors will be 2^max_proc_exp 

40 """ 

41 

42 # initialize level parameters 

43 level_params = dict() 

44 level_params['restol'] = 1e-08 

45 level_params['nsweeps'] = [3, 1] 

46 

47 # initialize sweeper parameters 

48 sweeper_params = dict() 

49 sweeper_params['quad_type'] = 'RADAU-RIGHT' 

50 sweeper_params['num_nodes'] = [3] 

51 sweeper_params['QI'] = [QI, 'LU'] 

52 sweeper_params['initial_guess'] = 'zero' 

53 

54 # initialize problem parameters 

55 problem_params = dict() 

56 problem_params['nu'] = 0.1 # diffusion coefficient 

57 problem_params['freq'] = 2 # frequency for the test value 

58 problem_params['nvars'] = [127, 63] # number of degrees of freedom for each level 

59 problem_params['bc'] = 'dirichlet-zero' # boundary conditions 

60 

61 # initialize step parameters 

62 step_params = dict() 

63 step_params['maxiter'] = 200 

64 

65 # initialize space transfer parameters 

66 space_transfer_params = dict() 

67 space_transfer_params['rorder'] = 2 

68 space_transfer_params['iorder'] = 2 

69 space_transfer_params['periodic'] = False 

70 

71 # initialize controller parameters 

72 controller_params = dict() 

73 controller_params['logger_level'] = 30 

74 

75 # fill description dictionary for easy step instantiation 

76 description = dict() 

77 description['problem_class'] = heatNd_unforced # pass problem class 

78 description['problem_params'] = problem_params # pass problem parameters 

79 description['sweeper_class'] = generic_implicit # pass sweeper (see part B) 

80 description['sweeper_params'] = sweeper_params # pass sweeper parameters 

81 description['step_params'] = step_params # pass step parameters 

82 description['space_transfer_class'] = mesh_to_mesh # pass spatial transfer class 

83 description['space_transfer_params'] = space_transfer_params # pass paramters for spatial transfer 

84 

85 # set time parameters 

86 t0 = 0.0 

87 Tend = 1.0 

88 

89 # set up number of parallel time-steps to run PFASST with 

90 

91 fname = 'data/results_conv_diffusion_Linf_QI' + str(QI) + '.txt' 

92 file = open(fname, 'w') 

93 writer = csv.writer(file) 

94 writer.writerow(('num_proc', 'niter')) 

95 file.close() 

96 

97 for i in range(0, max_proc_exp): 

98 num_proc = 2**i 

99 level_params['dt'] = (Tend - t0) / num_proc 

100 description['level_params'] = level_params # pass level parameters 

101 

102 out = 'Working on num_proc = %5i' % num_proc 

103 print(out) 

104 cfl = problem_params['nu'] * level_params['dt'] / (1.0 / (problem_params['nvars'][0] + 1)) ** 2 

105 out = ' CFL number: %4.2e' % cfl 

106 print(out) 

107 

108 # instantiate controller 

109 controller = controller_nonMPI(num_procs=num_proc, controller_params=controller_params, description=description) 

110 

111 # get initial values on finest level 

112 P = controller.MS[0].levels[0].prob 

113 uinit = P.u_exact(t0) 

114 

115 # call main function to get things done... 

116 uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend) 

117 

118 # filter statistics by type (number of iterations) 

119 iter_counts = get_sorted(stats, type='niter', sortby='time') 

120 

121 niters = np.array([item[1] for item in iter_counts]) 

122 

123 out = ' Mean number of iterations: %4.2f' % np.mean(niters) 

124 print(out) 

125 

126 file = open(fname, 'a') 

127 writer = csv.writer(file) 

128 writer.writerow((num_proc, np.mean(niters))) 

129 file.close() 

130 

131 assert os.path.isfile(fname), 'ERROR: pickle did not create file' 

132 

133 

134def run_advection(QI, max_proc_exp=7): 

135 """ 

136 A simple test program to test PFASST convergence for the periodic advection equation 

137 

138 Args: 

139 QI: preconditioner 

140 max_proc_exp: max number of processors will be 2^max_proc_exp 

141 """ 

142 

143 # initialize level parameters 

144 level_params = dict() 

145 level_params['restol'] = 1e-08 

146 level_params['nsweeps'] = [3, 1] 

147 

148 # initialize sweeper parameters 

149 sweeper_params = dict() 

150 sweeper_params['quad_type'] = 'RADAU-RIGHT' 

151 sweeper_params['num_nodes'] = [3] 

152 sweeper_params['QI'] = [QI, 'LU'] # For the IMEX sweeper, the LU-trick can be activated for the implicit part 

153 sweeper_params['initial_guess'] = 'zero' 

154 

155 # initialize problem parameters 

156 problem_params = dict() 

157 problem_params['freq'] = 64 # frequency for the test value 

158 problem_params['nvars'] = [128, 64] # number of degrees of freedom for each level 

159 problem_params['order'] = 2 

160 problem_params['stencil_type'] = 'center' 

161 problem_params['c'] = 0.1 

162 problem_params['bc'] = 'periodic' # boundary conditions 

163 

164 # initialize step parameters 

165 step_params = dict() 

166 step_params['maxiter'] = 200 

167 

168 # initialize space transfer parameters 

169 space_transfer_params = dict() 

170 space_transfer_params['rorder'] = 2 

171 space_transfer_params['iorder'] = 2 

172 space_transfer_params['periodic'] = True 

173 

174 # initialize controller parameters 

175 controller_params = dict() 

176 controller_params['logger_level'] = 30 

177 

178 # fill description dictionary for easy step instantiation 

179 description = dict() 

180 description['problem_class'] = advectionNd # pass problem class 

181 description['problem_params'] = problem_params # pass problem parameters 

182 description['sweeper_class'] = generic_implicit # pass sweeper (see part B) 

183 description['sweeper_params'] = sweeper_params # pass sweeper parameters 

184 description['step_params'] = step_params # pass step parameters 

185 description['space_transfer_class'] = mesh_to_mesh # pass spatial transfer class 

186 description['space_transfer_params'] = space_transfer_params # pass paramters for spatial transfer 

187 

188 # set time parameters 

189 t0 = 0.0 

190 Tend = 1.0 

191 

192 # set up number of parallel time-steps to run PFASST with 

193 

194 fname = 'data/results_conv_advection_Linf_QI' + str(QI) + '.txt' 

195 file = open(fname, 'w') 

196 writer = csv.writer(file) 

197 writer.writerow(('num_proc', 'niter')) 

198 file.close() 

199 

200 for i in range(0, max_proc_exp): 

201 num_proc = 2**i 

202 level_params['dt'] = (Tend - t0) / num_proc 

203 description['level_params'] = level_params # pass level parameters 

204 

205 out = 'Working on num_proc = %5i' % num_proc 

206 print(out) 

207 cfl = problem_params['c'] * level_params['dt'] / (1.0 / problem_params['nvars'][0]) 

208 out = ' CFL number: %4.2e' % cfl 

209 print(out) 

210 

211 # instantiate controller 

212 controller = controller_nonMPI(num_procs=num_proc, controller_params=controller_params, description=description) 

213 

214 # get initial values on finest level 

215 P = controller.MS[0].levels[0].prob 

216 uinit = P.u_exact(t0) 

217 

218 # call main function to get things done... 

219 uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend) 

220 

221 # filter statistics by type (number of iterations) 

222 iter_counts = get_sorted(stats, type='niter', sortby='time') 

223 

224 niters = np.array([item[1] for item in iter_counts]) 

225 

226 out = ' Mean number of iterations: %4.2f' % np.mean(niters) 

227 print(out) 

228 

229 file = open(fname, 'a') 

230 writer = csv.writer(file) 

231 writer.writerow((num_proc, np.mean(niters))) 

232 file.close() 

233 

234 assert os.path.isfile(fname), 'ERROR: pickle did not create file' 

235 

236 

237def plot_results(cwd=''): 

238 """ 

239 Plotting routine for iteration counts 

240 

241 Args: 

242 cwd: current working directory 

243 """ 

244 

245 setups = [('diffusion', 'LU', 'LU2'), ('advection', 'LU', 'LU2')] 

246 

247 for type, QI1, QI2 in setups: 

248 fname = cwd + 'data/results_conv_' + type + '_Linf_QI' + QI1 + '.txt' 

249 file = open(fname, 'r') 

250 reader = csv.DictReader(file, delimiter=',') 

251 xvalues_1 = [] 

252 niter_1 = [] 

253 for row in reader: 

254 xvalues_1.append(int(row['num_proc'])) 

255 niter_1.append(float(row['niter'])) 

256 file.close() 

257 

258 fname = cwd + 'data/results_conv_' + type + '_Linf_QI' + QI2 + '.txt' 

259 file = open(fname, 'r') 

260 reader = csv.DictReader(file, delimiter=',') 

261 xvalues_2 = [] 

262 niter_2 = [] 

263 for row in reader: 

264 xvalues_2.append(int(row['num_proc'])) 

265 niter_2.append(float(row['niter'])) 

266 file.close() 

267 

268 # set up plotting parameters 

269 params = { 

270 'legend.fontsize': 20, 

271 'figure.figsize': (12, 8), 

272 'axes.labelsize': 20, 

273 'axes.titlesize': 20, 

274 'xtick.labelsize': 16, 

275 'ytick.labelsize': 16, 

276 'lines.linewidth': 3, 

277 } 

278 plt.rcParams.update(params) 

279 

280 # set up figure 

281 plt.figure() 

282 plt.xlabel('number of time-steps (L)') 

283 plt.ylabel('no. of iterations') 

284 plt.xlim(min(xvalues_1 + xvalues_2) / 2.0, max(xvalues_1 + xvalues_2) * 2.0) 

285 plt.ylim(min(niter_1 + niter_2) - 1, max(niter_1 + niter_2) + 1) 

286 plt.grid() 

287 

288 # plot 

289 plt.semilogx(xvalues_1, niter_1, 'r-', marker='s', markersize=10, label=QI1) 

290 plt.semilogx(xvalues_2, niter_2, 'b-', marker='o', markersize=10, label=QI2) 

291 

292 plt.legend(loc=2, ncol=1, numpoints=1) 

293 

294 # save plot, beautify 

295 fname = 'data/conv_test_niter_Linf_' + type + '.png' 

296 plt.savefig(fname, bbox_inches='tight') 

297 

298 assert os.path.isfile(fname), 'ERROR: plotting did not create file' 

299 

300 

301if __name__ == "__main__": 

302 main()