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

112 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-27 07:06 +0000

1import subprocess 

2import os 

3 

4import numpy as np 

5from mpi4py import MPI 

6 

7from pySDC.helpers.stats_helper import get_sorted 

8 

9from pySDC.implementations.controller_classes.controller_nonMPI import controller_nonMPI 

10from pySDC.implementations.problem_classes.AllenCahn_2D_FD import allencahn_fullyimplicit 

11from pySDC.implementations.sweeper_classes.generic_implicit import generic_implicit 

12from pySDC.implementations.transfer_classes.TransferMesh_FFT2D import mesh_to_mesh_fft2d 

13from pySDC.playgrounds.Allen_Cahn.AllenCahn_monitor import monitor 

14from pySDC.implementations.transfer_classes.BaseTransferMPI import base_transfer_MPI 

15from pySDC.implementations.sweeper_classes.generic_implicit_MPI import generic_implicit_MPI 

16 

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

18 

19 

20def run_variant(variant=None): 

21 """ 

22 Routine to run a particular variant 

23 

24 Args: 

25 variant (str): string describing the variant 

26 

27 """ 

28 

29 # initialize level parameters 

30 level_params = dict() 

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

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

33 level_params['nsweeps'] = 1 

34 

35 # initialize sweeper parameters 

36 sweeper_params = dict() 

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

38 sweeper_params['num_nodes'] = 3 

39 sweeper_params['initial_guess'] = 'zero' 

40 

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

42 problem_params = dict() 

43 problem_params['nu'] = 2 

44 

45 problem_params['eps'] = 0.04 

46 problem_params['newton_maxiter'] = 100 

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

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

49 problem_params['lin_maxiter'] = 100 

50 problem_params['radius'] = 0.25 

51 

52 # initialize step parameters 

53 step_params = dict() 

54 step_params['maxiter'] = 50 

55 

56 # initialize controller parameters 

57 controller_params = dict() 

58 controller_params['logger_level'] = 30 

59 controller_params['hook_class'] = monitor 

60 

61 # fill description dictionary for easy step instantiation 

62 description = dict() 

63 description['problem_class'] = allencahn_fullyimplicit 

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

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

66 

67 do_print = True 

68 

69 # add stuff based on variant 

70 if variant == 'sl_serial': 

71 maxmeaniters = 5.0 

72 sweeper_params['QI'] = ['LU'] 

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

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

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

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

77 elif variant == 'sl_parallel': 

78 maxmeaniters = 5.125 

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

80 sweeper_params['QI'] = ['MIN3'] 

81 sweeper_params['comm'] = MPI.COMM_WORLD 

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

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

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

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

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

87 elif variant == 'ml_serial': 

88 maxmeaniters = 3.125 

89 sweeper_params['QI'] = ['LU'] 

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

91 description['space_transfer_class'] = mesh_to_mesh_fft2d 

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

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

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

95 elif variant == 'ml_parallel': 

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

97 maxmeaniters = 4.25 

98 sweeper_params['QI'] = ['MIN3'] 

99 sweeper_params['comm'] = MPI.COMM_WORLD 

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

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

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

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

104 description['space_transfer_class'] = mesh_to_mesh_fft2d 

105 description['base_transfer_class'] = base_transfer_MPI 

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

107 else: 

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

109 

110 if do_print: 

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

112 print(out) 

113 

114 # setup parameters "in time" 

115 t0 = 0 

116 Tend = 0.004 

117 

118 # instantiate controller 

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

120 

121 # get initial values on finest level 

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

123 uinit = P.u_exact(t0) 

124 

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

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

127 

128 # filter statistics by variant (number of iterations) 

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

130 

131 # compute and print statistics 

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

133 

134 if do_print: 

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

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

137 np.mean(niters), 

138 maxmeaniters, 

139 ) 

140 print(out) 

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

142 print(out) 

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

144 int(np.argmax(niters)), 

145 int(np.argmin(niters)), 

146 ) 

147 print(out) 

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

149 print(out) 

150 

151 print(' Iteration count (nonlinear/linear): %i / %i' % (P.newton_itercount, P.lin_itercount)) 

152 print( 

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

154 % (P.newton_itercount / max(P.newton_ncalls, 1), P.lin_itercount / max(P.lin_ncalls, 1)) 

155 ) 

156 

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

158 

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

160 

161 return None 

162 

163 

164def main(): 

165 """ 

166 Main driver 

167 

168 """ 

169 

170 run_variant(variant='sl_serial') 

171 print() 

172 run_variant(variant='ml_serial') 

173 print() 

174 

175 my_env = os.environ.copy() 

176 my_env['PYTHONPATH'] = '../../..:.' 

177 my_env['COVERAGE_PROCESS_START'] = 'pyproject.toml' 

178 cmd = ( 

179 "mpirun -np 3 python -c \"from pySDC.projects.parallelSDC.AllenCahn_parallel import *; " 

180 "run_variant(\'sl_parallel\');\"" 

181 ) 

182 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 

183 p.wait() 

184 for line in p.stdout: 

185 print(line) 

186 for line in p.stderr: 

187 print(line) 

188 assert p.returncode == 0, 'ERROR: did not get return code 0, got %s' % (p.returncode) 

189 

190 cmd = ( 

191 "mpirun -np 3 python -c \"from pySDC.projects.parallelSDC.AllenCahn_parallel import *; " 

192 "run_variant(\'ml_parallel\');\"" 

193 ) 

194 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 

195 p.wait() 

196 for line in p.stdout: 

197 print(line) 

198 for line in p.stderr: 

199 print(line) 

200 assert p.returncode == 0, 'ERROR: did not get return code 0, got %s' % (p.returncode) 

201 

202 

203if __name__ == "__main__": 

204 main()