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
« 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"""
7from pathlib import Path
9from pySDC.helpers.stats_helper import get_sorted
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
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
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
27 Returns:
28 dict: the iteration counts of each time step, for each number of processes
29 """
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()
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)
48 # instantiate controllers
49 controller = controller_nonMPI(num_procs=num_proc, controller_params=controller_params, description=description)
51 # get initial values on finest level
52 P = controller.MS[0].levels[0].prob
53 uinit = P.u_exact(t0)
55 # call main functions to get things done...
56 uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)
58 # compute exact solution and compare with both results
59 uex = P.u_exact(Tend)
60 err = abs(uex - uend)
62 out = 'Error vs. exact solution: %12.8e' % err
63 f.write(out + '\n')
64 print(out)
66 # filter statistics by type (number of iterations)
67 iter_counts = get_sorted(stats, type='niter', sortby='time')
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)
75 f.write('\n')
76 print()
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]
81 f.close()
82 return iterations
85def set_parameters_ml():
86 """
87 Helper routine to set parameters for the following multi-level runs
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
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'
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
113 # initialize step parameters
114 step_params = {}
115 step_params['maxiter'] = 50
116 step_params['errtol'] = 1e-05
118 # initialize space transfer parameters
119 space_transfer_params = {}
120 space_transfer_params['rorder'] = 2
121 space_transfer_params['iorder'] = 6
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
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
140 # set time parameters
141 t0 = 0.0
142 Tend = 1.0
144 return description, controller_params, t0, Tend
147def set_parameters_sl():
148 """
149 Helper routine to set parameters for the following single-level runs
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
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'
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
175 # initialize step parameters
176 step_params = {}
177 step_params['maxiter'] = 50
179 # initialize controller parameters
180 controller_params = {}
181 controller_params['logger_level'] = 30
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
192 # set time parameters
193 t0 = 0.0
194 Tend = 1.0
196 return description, controller_params, t0, Tend