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
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-27 07:06 +0000
1import subprocess
2import os
4import numpy as np
5from mpi4py import MPI
7from pySDC.helpers.stats_helper import get_sorted
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
17# http://www.personal.psu.edu/qud2/Res/Pre/dz09sisc.pdf
20def run_variant(variant=None):
21 """
22 Routine to run a particular variant
24 Args:
25 variant (str): string describing the variant
27 """
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
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'
41 # This comes as read-in for the problem class
42 problem_params = dict()
43 problem_params['nu'] = 2
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
52 # initialize step parameters
53 step_params = dict()
54 step_params['maxiter'] = 50
56 # initialize controller parameters
57 controller_params = dict()
58 controller_params['logger_level'] = 30
59 controller_params['hook_class'] = monitor
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
67 do_print = True
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)
110 if do_print:
111 out = 'Working on %s variant...' % variant
112 print(out)
114 # setup parameters "in time"
115 t0 = 0
116 Tend = 0.004
118 # instantiate controller
119 controller = controller_nonMPI(num_procs=1, controller_params=controller_params, description=description)
121 # get initial values on finest level
122 P = controller.MS[0].levels[0].prob
123 uinit = P.u_exact(t0)
125 # call main function to get things done...
126 uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)
128 # filter statistics by variant (number of iterations)
129 iter_counts = get_sorted(stats, type='niter', sortby='time')
131 # compute and print statistics
132 niters = np.array([item[1] for item in iter_counts])
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)
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 )
157 timing = get_sorted(stats, type='timing_run', sortby='time')
159 print('Time to solution: %6.4f sec.' % timing[0][1])
161 return None
164def main():
165 """
166 Main driver
168 """
170 run_variant(variant='sl_serial')
171 print()
172 run_variant(variant='ml_serial')
173 print()
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)
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)
203if __name__ == "__main__":
204 main()