Coverage for pySDC/projects/parallelSDC/AllenCahn_parallel.py: 100%

92 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-09-25 20:28 +0000

1import numpy as np 

2from mpi4py import MPI 

3 

4from pySDC.helpers.stats_helper import get_sorted 

5 

6from pySDC.implementations.controller_classes.controller_nonMPI import controller_nonMPI 

7from pySDC.implementations.problem_classes.AllenCahn_2D_FD import allencahn_fullyimplicit 

8from pySDC.implementations.sweeper_classes.generic_implicit import generic_implicit 

9from pySDC.implementations.transfer_classes.TransferMesh_FFT2D import mesh_to_mesh_fft2d 

10from pySDC.implementations.hooks.AllenCahn_monitor import AllenCahnMonitor 

11from pySDC.implementations.transfer_classes.BaseTransferMPI import base_transfer_MPI 

12from pySDC.implementations.sweeper_classes.generic_implicit_MPI import generic_implicit_MPI 

13 

14# http://www.personal.psu.edu/qud2/Res/Pre/dz09sisc.pdf 

15 

16 

17def run_variant(variant=None): 

18 """ 

19 Routine to run a particular variant 

20 

21 Args: 

22 variant (str): string describing the variant 

23 

24 """ 

25 

26 # initialize level parameters 

27 level_params = dict() 

28 level_params['restol'] = 1e-07 

29 level_params['dt'] = 1e-03 / 2 

30 level_params['nsweeps'] = 1 

31 

32 # initialize sweeper parameters 

33 sweeper_params = dict() 

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

35 sweeper_params['num_nodes'] = 3 

36 sweeper_params['initial_guess'] = 'zero' 

37 

38 # This comes as read-in for the problem class 

39 problem_params = dict() 

40 

41 problem_params['eps'] = 0.04 

42 problem_params['newton_maxiter'] = 100 

43 problem_params['newton_tol'] = 1e-08 

44 problem_params['lin_tol'] = 1e-09 

45 problem_params['lin_maxiter'] = 100 

46 problem_params['radius'] = 0.25 

47 

48 # initialize step parameters 

49 step_params = dict() 

50 step_params['maxiter'] = 50 

51 

52 # initialize controller parameters 

53 controller_params = dict() 

54 controller_params['logger_level'] = 30 

55 controller_params['hook_class'] = AllenCahnMonitor 

56 

57 # fill description dictionary for easy step instantiation 

58 description = dict() 

59 description['problem_class'] = allencahn_fullyimplicit 

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

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

62 

63 do_print = True 

64 

65 # add stuff based on variant 

66 if variant == 'sl_serial': 

67 maxmeaniters = 5.0 

68 sweeper_params['QI'] = ['LU'] 

69 problem_params['nvars'] = [(128, 128)] 

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

71 description['sweeper_class'] = generic_implicit # pass sweeper 

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

73 elif variant == 'sl_parallel': 

74 maxmeaniters = 5.125 

75 assert MPI.COMM_WORLD.Get_size() == sweeper_params['num_nodes'] 

76 sweeper_params['QI'] = ['MIN3'] 

77 sweeper_params['comm'] = MPI.COMM_WORLD 

78 problem_params['nvars'] = [(128, 128)] 

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

80 description['sweeper_class'] = generic_implicit_MPI # pass sweeper 

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

82 do_print = MPI.COMM_WORLD.Get_rank() == 0 

83 elif variant == 'ml_serial': 

84 maxmeaniters = 3.125 

85 sweeper_params['QI'] = ['LU'] 

86 problem_params['nvars'] = [(128, 128), (64, 64)] 

87 description['space_transfer_class'] = mesh_to_mesh_fft2d 

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

89 description['sweeper_class'] = generic_implicit # pass sweeper 

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

91 elif variant == 'ml_parallel': 

92 assert MPI.COMM_WORLD.Get_size() == sweeper_params['num_nodes'] 

93 maxmeaniters = 4.25 

94 sweeper_params['QI'] = ['MIN3'] 

95 sweeper_params['comm'] = MPI.COMM_WORLD 

96 problem_params['nvars'] = [(128, 128), (64, 64)] 

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

98 description['sweeper_class'] = generic_implicit_MPI # pass sweeper 

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

100 description['space_transfer_class'] = mesh_to_mesh_fft2d 

101 description['base_transfer_class'] = base_transfer_MPI 

102 do_print = MPI.COMM_WORLD.Get_rank() == 0 

103 else: 

104 raise NotImplementedError('Wrong variant specified, got %s' % variant) 

105 

106 if do_print: 

107 out = 'Working on %s variant...' % variant 

108 print(out) 

109 

110 # setup parameters "in time" 

111 t0 = 0 

112 Tend = 0.004 

113 

114 # instantiate controller 

115 controller = controller_nonMPI(num_procs=1, controller_params=controller_params, description=description) 

116 

117 # get initial values on finest level 

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

119 uinit = P.u_exact(t0) 

120 

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

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

123 

124 # filter statistics by variant (number of iterations) 

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

126 

127 # compute and print statistics 

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

129 

130 if do_print: 

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

132 assert np.mean(niters) <= maxmeaniters, 'ERROR: number of iterations is too high, got %s instead of %s' % ( 

133 np.mean(niters), 

134 maxmeaniters, 

135 ) 

136 print(out) 

137 out = ' Range of values for number of iterations: %2i ' % np.ptp(niters) 

138 print(out) 

139 out = ' Position of max/min number of iterations: %2i -- %2i' % ( 

140 int(np.argmax(niters)), 

141 int(np.argmin(niters)), 

142 ) 

143 print(out) 

144 out = ' Std and var for number of iterations: %4.2f -- %4.2f' % (float(np.std(niters)), float(np.var(niters))) 

145 print(out) 

146 

147 newton_iters = P.work_counters['newton'].niter 

148 lin_iters = P.work_counters['linear'].niter 

149 print(' Iteration count (nonlinear/linear): %i / %i' % (newton_iters, lin_iters)) 

150 print( 

151 ' Mean Iteration count per call: %4.2f / %4.2f' 

152 % (newton_iters / max(P.newton_ncalls, 1), lin_iters / max(P.lin_ncalls, 1)) 

153 ) 

154 

155 timing = get_sorted(stats, type='timing_run', sortby='time') 

156 

157 print('Time to solution: %6.4f sec.' % timing[0][1]) 

158 

159 return None 

160 

161 

162def main(): 

163 """ 

164 Main driver: the serial variants. 

165 

166 The parallel variants need a 3-rank job, so they are not run from here. Use 

167 

168 mpirun -np 3 python -c "from pySDC.projects.parallelSDC.AllenCahn_parallel import run_variant as r; r('sl_parallel')" 

169 

170 or let the test do it -- `tests/test_AllenCahn_parallel.py` runs them through mpi-pytest. 

171 """ 

172 

173 run_variant(variant='sl_serial') 

174 print() 

175 run_variant(variant='ml_serial') 

176 print() 

177 

178 

179if __name__ == "__main__": 

180 main()