Coverage for pySDC/tutorial/step_6/pfasst_setup.py: 100%

100 statements  

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

1""" 

2The setup of tutorial step 6: the parameters of the single- and multi-level PFASST runs, and the loop that runs the 

3non-MPI controller for several numbers of processes. Parts A and B run that loop, part C the same parameters with the 

4MPI controller, and its test compares the results. 

5""" 

6 

7from pathlib import Path 

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.HeatEquation_ND_FD import heatNd_unforced 

13from pySDC.implementations.sweeper_classes.generic_implicit import generic_implicit 

14from pySDC.implementations.transfer_classes.TransferMesh import mesh_to_mesh 

15 

16 

17def run_pfasst(num_proc_list=None, fname=None, multi_level=True): 

18 """ 

19 Run PFASST with the non-MPI controller, for each number of processes in the list, and write what it prints to 

20 data/<fname> as well, for the comparison with the MPI controller in part C 

21 

22 Args: 

23 num_proc_list: list of number of processes to test with 

24 fname: filename/path for output 

25 multi_level (bool): do multi-level run or single-level 

26 

27 Returns: 

28 dict: the iteration counts of each time step, for each number of processes 

29 """ 

30 

31 if multi_level: 

32 description, controller_params, t0, Tend = set_parameters_ml() 

33 else: 

34 assert all(num_proc == 1 for num_proc in num_proc_list), ( 

35 'ERROR: single-level run can only use 1 processor, got %s' % num_proc_list 

36 ) 

37 description, controller_params, t0, Tend = set_parameters_sl() 

38 

39 Path("data").mkdir(parents=True, exist_ok=True) 

40 f = open('data/' + fname, 'w') 

41 iterations = {} 

42 # loop over different numbers of processes 

43 for num_proc in num_proc_list: 

44 out = 'Working with %2i processes...' % num_proc 

45 f.write(out + '\n') 

46 print(out) 

47 

48 # instantiate controllers 

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

50 

51 # get initial values on finest level 

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

53 uinit = P.u_exact(t0) 

54 

55 # call main functions to get things done... 

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

57 

58 # compute exact solution and compare with both results 

59 uex = P.u_exact(Tend) 

60 err = abs(uex - uend) 

61 

62 out = 'Error vs. exact solution: %12.8e' % err 

63 f.write(out + '\n') 

64 print(out) 

65 

66 # filter statistics by type (number of iterations) 

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

68 

69 # compute and print statistics 

70 for item in iter_counts: 

71 out = 'Number of iterations for time %4.2f: %1i ' % (item[0], item[1]) 

72 f.write(out + '\n') 

73 print(out) 

74 

75 f.write('\n') 

76 print() 

77 

78 assert all(item[1] <= 8 for item in iter_counts), "ERROR: weird iteration counts, got %s" % iter_counts 

79 iterations[num_proc] = [item[1] for item in iter_counts] 

80 

81 f.close() 

82 return iterations 

83 

84 

85def set_parameters_ml(): 

86 """ 

87 Helper routine to set parameters for the following multi-level runs 

88 

89 Returns: 

90 dict: dictionary containing the simulation parameters 

91 dict: dictionary containing the controller parameters 

92 float: starting time 

93 float: end time 

94 """ 

95 # initialize level parameters 

96 level_params = {} 

97 level_params['restol'] = 5e-10 

98 level_params['dt'] = 0.125 

99 

100 # initialize sweeper parameters 

101 sweeper_params = {} 

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

103 sweeper_params['num_nodes'] = [3] 

104 sweeper_params['QI'] = 'LU' 

105 

106 # initialize problem parameters 

107 problem_params = {} 

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

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

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

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

112 

113 # initialize step parameters 

114 step_params = {} 

115 step_params['maxiter'] = 50 

116 step_params['errtol'] = 1e-05 

117 

118 # initialize space transfer parameters 

119 space_transfer_params = {} 

120 space_transfer_params['rorder'] = 2 

121 space_transfer_params['iorder'] = 6 

122 

123 # initialize controller parameters 

124 controller_params = {} 

125 controller_params['logger_level'] = 30 

126 controller_params['all_to_done'] = True # can ask the controller to keep iterating all steps until the end 

127 controller_params['predict_type'] = 'pfasst_burnin' # PFASST's coarse-level predictor 

128 

129 # fill description dictionary for easy step instantiation 

130 description = {} 

131 description['problem_class'] = heatNd_unforced 

132 description['problem_params'] = problem_params 

133 description['sweeper_class'] = generic_implicit 

134 description['sweeper_params'] = sweeper_params 

135 description['level_params'] = level_params 

136 description['step_params'] = step_params 

137 description['space_transfer_class'] = mesh_to_mesh 

138 description['space_transfer_params'] = space_transfer_params 

139 

140 # set time parameters 

141 t0 = 0.0 

142 Tend = 1.0 

143 

144 return description, controller_params, t0, Tend 

145 

146 

147def set_parameters_sl(): 

148 """ 

149 Helper routine to set parameters for the following single-level runs 

150 

151 Returns: 

152 dict: dictionary containing the simulation parameters 

153 dict: dictionary containing the controller parameters 

154 float: starting time 

155 float: end time 

156 """ 

157 # initialize level parameters 

158 level_params = {} 

159 level_params['restol'] = 5e-10 

160 level_params['dt'] = 0.125 

161 

162 # initialize sweeper parameters 

163 sweeper_params = {} 

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

165 sweeper_params['num_nodes'] = 3 

166 sweeper_params['QI'] = 'LU' 

167 

168 # initialize problem parameters 

169 problem_params = {} 

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

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

172 problem_params['nvars'] = 63 # number of degrees of freedom for each level 

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

174 

175 # initialize step parameters 

176 step_params = {} 

177 step_params['maxiter'] = 50 

178 

179 # initialize controller parameters 

180 controller_params = {} 

181 controller_params['logger_level'] = 30 

182 

183 # fill description dictionary for easy step instantiation 

184 description = {} 

185 description['problem_class'] = heatNd_unforced 

186 description['problem_params'] = problem_params 

187 description['sweeper_class'] = generic_implicit 

188 description['sweeper_params'] = sweeper_params 

189 description['level_params'] = level_params 

190 description['step_params'] = step_params 

191 

192 # set time parameters 

193 t0 = 0.0 

194 Tend = 1.0 

195 

196 return description, controller_params, t0, Tend