Skip to content

Commit 562a508

Browse files
committed
PFASST for L->infty, tests, more output
1 parent 67e8b79 commit 562a508

File tree

9 files changed

+400
-31
lines changed

9 files changed

+400
-31
lines changed

playgrounds/HeatEquation/periodic_playground.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,24 @@ def main():
1818
A simple test program to do PFASST runs for the heat equation
1919
"""
2020

21+
# set up number of parallel time-steps to run PFASST with
22+
num_proc = 16
23+
2124
# initialize level parameters
2225
level_params = dict()
2326
level_params['restol'] = 1E-08
24-
level_params['dt'] = 0.25
25-
level_params['nsweeps'] = [2, 1]
27+
level_params['dt'] = 1.0 / num_proc
28+
level_params['nsweeps'] = [3, 1]
2629

2730
# initialize sweeper parameters
2831
sweeper_params = dict()
2932
sweeper_params['collocation_class'] = CollGaussRadau_Right
3033
sweeper_params['num_nodes'] = [3]
31-
sweeper_params['QI'] = ['LU'] # For the IMEX sweeper, the LU-trick can be activated for the implicit part
34+
sweeper_params['QI'] = ['LU2', 'LU'] # For the IMEX sweeper, the LU-trick can be activated for the implicit part
3235

3336
# initialize problem parameters
3437
problem_params = dict()
35-
problem_params['nu'] = 1E-06 # diffusion coefficient
38+
problem_params['nu'] = 0.1 # diffusion coefficient
3639
problem_params['freq'] = -1 # frequency for the test value
3740
problem_params['nvars'] = [128, 64] # number of degrees of freedom for each level
3841

@@ -66,10 +69,7 @@ def main():
6669

6770
# set time parameters
6871
t0 = 0.0
69-
Tend = 4 * level_params['dt']
70-
71-
# set up number of parallel time-steps to run PFASST with
72-
num_proc = 4
72+
Tend = 1.0
7373

7474
# instantiate controller
7575
controller = allinclusive_multigrid_nonMPI(num_procs=num_proc, controller_params=controller_params,
Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
import numpy as np
2+
import csv
3+
import os
4+
import matplotlib
5+
matplotlib.use('Agg')
6+
import matplotlib.pyplot as plt
7+
8+
from pySDC.implementations.problem_classes.HeatEquation_1D_FD import heat1d
9+
from pySDC.implementations.problem_classes.AdvectionEquation_1D_FD import advection1d
10+
from pySDC.implementations.datatype_classes.mesh import mesh
11+
from pySDC.implementations.collocation_classes.gauss_radau_right import CollGaussRadau_Right
12+
from pySDC.implementations.sweeper_classes.generic_implicit import generic_implicit
13+
from pySDC.implementations.transfer_classes.TransferMesh import mesh_to_mesh
14+
from pySDC.implementations.controller_classes.allinclusive_multigrid_nonMPI import allinclusive_multigrid_nonMPI
15+
16+
from pySDC.helpers.stats_helper import filter_stats, sort_stats
17+
18+
19+
def main():
20+
"""
21+
Main driver running diffusion and advection tests
22+
"""
23+
QI = 'LU'
24+
# run_diffusion(QI=QI)
25+
run_advection(QI=QI)
26+
27+
QI = 'LU2'
28+
# run_diffusion(QI=QI)
29+
run_advection(QI=QI)
30+
31+
plot_results()
32+
33+
34+
def run_diffusion(QI):
35+
"""
36+
A simple test program to test PFASST convergence for the heat equation with random initial data
37+
38+
Args:
39+
QI: preconditioner
40+
"""
41+
42+
# initialize level parameters
43+
level_params = dict()
44+
level_params['restol'] = 1E-08
45+
level_params['nsweeps'] = [3, 1]
46+
47+
# initialize sweeper parameters
48+
sweeper_params = dict()
49+
sweeper_params['collocation_class'] = CollGaussRadau_Right
50+
sweeper_params['num_nodes'] = [3]
51+
sweeper_params['QI'] = [QI, 'LU']
52+
sweeper_params['spread'] = False
53+
54+
# initialize problem parameters
55+
problem_params = dict()
56+
problem_params['nu'] = 0.1 # diffusion coefficient
57+
problem_params['freq'] = -1 # frequency for the test value
58+
problem_params['nvars'] = [127, 63] # number of degrees of freedom for each level
59+
60+
# initialize step parameters
61+
step_params = dict()
62+
step_params['maxiter'] = 200
63+
64+
# initialize space transfer parameters
65+
space_transfer_params = dict()
66+
space_transfer_params['rorder'] = 2
67+
space_transfer_params['iorder'] = 2
68+
space_transfer_params['periodic'] = False
69+
70+
# initialize controller parameters
71+
controller_params = dict()
72+
controller_params['logger_level'] = 30
73+
controller_params['predict'] = False
74+
75+
# fill description dictionary for easy step instantiation
76+
description = dict()
77+
description['problem_class'] = heat1d # pass problem class
78+
description['problem_params'] = problem_params # pass problem parameters
79+
description['dtype_u'] = mesh # pass data type for u
80+
description['dtype_f'] = mesh # pass data type for f
81+
description['sweeper_class'] = generic_implicit # pass sweeper (see part B)
82+
description['sweeper_params'] = sweeper_params # pass sweeper parameters
83+
description['step_params'] = step_params # pass step parameters
84+
description['space_transfer_class'] = mesh_to_mesh # pass spatial transfer class
85+
description['space_transfer_params'] = space_transfer_params # pass paramters for spatial transfer
86+
87+
# set time parameters
88+
t0 = 0.0
89+
Tend = 1.0
90+
91+
# set up number of parallel time-steps to run PFASST with
92+
93+
fname = 'data/results_conv_diffusion_Linf_QI' + str(QI) + '.txt'
94+
file = open(fname, 'w')
95+
writer = csv.writer(file)
96+
writer.writerow(('num_proc', 'niter'))
97+
file.close()
98+
99+
for i in range(0, 13):
100+
101+
num_proc = 2 ** i
102+
level_params['dt'] = (Tend - t0) / num_proc
103+
description['level_params'] = level_params # pass level parameters
104+
105+
out = 'Working on num_proc = %5i' % num_proc
106+
print(out)
107+
cfl = problem_params['nu'] * level_params['dt'] / (1.0 / (problem_params['nvars'][0] + 1)) ** 2
108+
out = ' CFL number: %4.2e' % cfl
109+
print(out)
110+
111+
# instantiate controller
112+
controller = allinclusive_multigrid_nonMPI(num_procs=num_proc, controller_params=controller_params,
113+
description=description)
114+
115+
# get initial values on finest level
116+
P = controller.MS[0].levels[0].prob
117+
uinit = P.u_exact(t0)
118+
119+
# call main function to get things done...
120+
uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)
121+
122+
# filter statistics by type (number of iterations)
123+
filtered_stats = filter_stats(stats, type='niter')
124+
125+
# convert filtered statistics to list of iterations count, sorted by process
126+
iter_counts = sort_stats(filtered_stats, sortby='time')
127+
128+
niters = np.array([item[1] for item in iter_counts])
129+
130+
out = ' Mean number of iterations: %4.2f' % np.mean(niters)
131+
print(out)
132+
133+
file = open(fname, 'a')
134+
writer = csv.writer(file)
135+
writer.writerow((num_proc, np.mean(niters)))
136+
file.close()
137+
138+
assert os.path.isfile(fname), 'ERROR: pickle did not create file'
139+
140+
141+
def run_advection(QI):
142+
"""
143+
A simple test program to test PFASST convergence for the periodic advection equation
144+
145+
Args:
146+
QI: preconditioner
147+
"""
148+
149+
# initialize level parameters
150+
level_params = dict()
151+
level_params['restol'] = 1E-08
152+
level_params['nsweeps'] = [3, 1]
153+
154+
# initialize sweeper parameters
155+
sweeper_params = dict()
156+
sweeper_params['collocation_class'] = CollGaussRadau_Right
157+
sweeper_params['num_nodes'] = [3]
158+
sweeper_params['QI'] = [QI, 'LU'] # For the IMEX sweeper, the LU-trick can be activated for the implicit part
159+
sweeper_params['spread'] = False
160+
161+
# initialize problem parameters
162+
problem_params = dict()
163+
problem_params['freq'] = 64 # frequency for the test value
164+
problem_params['nvars'] = [128, 64] # number of degrees of freedom for each level
165+
problem_params['order'] = 2
166+
problem_params['type'] = 'center'
167+
problem_params['c'] = 0.1
168+
169+
# initialize step parameters
170+
step_params = dict()
171+
step_params['maxiter'] = 200
172+
173+
# initialize space transfer parameters
174+
space_transfer_params = dict()
175+
space_transfer_params['rorder'] = 2
176+
space_transfer_params['iorder'] = 2
177+
space_transfer_params['periodic'] = True
178+
179+
# initialize controller parameters
180+
controller_params = dict()
181+
controller_params['logger_level'] = 30
182+
controller_params['predict'] = False
183+
184+
# fill description dictionary for easy step instantiation
185+
description = dict()
186+
description['problem_class'] = advection1d # pass problem class
187+
description['problem_params'] = problem_params # pass problem parameters
188+
description['dtype_u'] = mesh # pass data type for u
189+
description['dtype_f'] = mesh # pass data type for f
190+
description['sweeper_class'] = generic_implicit # pass sweeper (see part B)
191+
description['sweeper_params'] = sweeper_params # pass sweeper parameters
192+
description['step_params'] = step_params # pass step parameters
193+
description['space_transfer_class'] = mesh_to_mesh # pass spatial transfer class
194+
description['space_transfer_params'] = space_transfer_params # pass paramters for spatial transfer
195+
196+
# set time parameters
197+
t0 = 0.0
198+
Tend = 1.0
199+
200+
# set up number of parallel time-steps to run PFASST with
201+
202+
fname = 'data/results_conv_advection_Linf_QI' + str(QI) + '.txt'
203+
file = open(fname, 'w')
204+
writer = csv.writer(file)
205+
writer.writerow(('num_proc', 'niter'))
206+
file.close()
207+
208+
for i in range(0, 7):
209+
210+
num_proc = 2 ** i
211+
level_params['dt'] = (Tend - t0) / num_proc
212+
description['level_params'] = level_params # pass level parameters
213+
214+
out = 'Working on num_proc = %5i' % num_proc
215+
print(out)
216+
cfl = problem_params['c'] * level_params['dt'] / (1.0 / problem_params['nvars'][0])
217+
out = ' CFL number: %4.2e' % cfl
218+
print(out)
219+
220+
# instantiate controller
221+
controller = allinclusive_multigrid_nonMPI(num_procs=num_proc, controller_params=controller_params,
222+
description=description)
223+
224+
# get initial values on finest level
225+
P = controller.MS[0].levels[0].prob
226+
uinit = P.u_exact(t0)
227+
228+
# call main function to get things done...
229+
uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)
230+
231+
# filter statistics by type (number of iterations)
232+
filtered_stats = filter_stats(stats, type='niter')
233+
234+
# convert filtered statistics to list of iterations count, sorted by process
235+
iter_counts = sort_stats(filtered_stats, sortby='time')
236+
237+
niters = np.array([item[1] for item in iter_counts])
238+
239+
out = ' Mean number of iterations: %4.2f' % np.mean(niters)
240+
print(out)
241+
242+
file = open(fname, 'a')
243+
writer = csv.writer(file)
244+
writer.writerow((num_proc, np.mean(niters)))
245+
file.close()
246+
247+
assert os.path.isfile(fname), 'ERROR: pickle did not create file'
248+
249+
250+
def plot_results(cwd=''):
251+
"""
252+
Plotting routine for iteration counts
253+
254+
Args:
255+
cwd: current working directory
256+
"""
257+
258+
setups = [('diffusion', 'LU', 'LU2'), ('advection', 'LU', 'LU2')]
259+
260+
for type, QI1, QI2 in setups:
261+
262+
fname = cwd + 'data/results_conv_' + type + '_Linf_QI' + QI1 + '.txt'
263+
file = open(fname, 'r')
264+
reader = csv.DictReader(file, delimiter=',')
265+
xvalues_1 = []
266+
niter_1 = []
267+
for row in reader:
268+
xvalues_1.append(int(row['num_proc']))
269+
niter_1.append(float(row['niter']))
270+
file.close()
271+
272+
fname = cwd + 'data/results_conv_' + type + '_Linf_QI' + QI2 + '.txt'
273+
file = open(fname, 'r')
274+
reader = csv.DictReader(file, delimiter=',')
275+
xvalues_2 = []
276+
niter_2 = []
277+
for row in reader:
278+
xvalues_2.append(int(row['num_proc']))
279+
niter_2.append(float(row['niter']))
280+
file.close()
281+
282+
# set up plotting parameters
283+
params = {'legend.fontsize': 20,
284+
'figure.figsize': (12, 8),
285+
'axes.labelsize': 20,
286+
'axes.titlesize': 20,
287+
'xtick.labelsize': 16,
288+
'ytick.labelsize': 16,
289+
'lines.linewidth': 3
290+
}
291+
plt.rcParams.update(params)
292+
293+
# set up figure
294+
plt.figure()
295+
plt.xlabel('number of time-steps (L)')
296+
plt.ylabel('#iterations')
297+
plt.xlim(min(xvalues_1 + xvalues_2) / 2, max(xvalues_1 + xvalues_2) * 2)
298+
plt.ylim(min(niter_1 + niter_2) - 1, max(niter_1 + niter_2) + 1)
299+
plt.grid()
300+
301+
# plot
302+
plt.semilogx(xvalues_1, niter_1, 'r-', marker='s', markersize=10, label=QI1)
303+
plt.semilogx(xvalues_2, niter_2, 'b-', marker='o', markersize=10, label=QI2)
304+
305+
plt.legend(loc=2, ncol=1, numpoints=1)
306+
307+
# save plot, beautify
308+
fname = 'data/conv_test_niter_Linf_' + type + '.png'
309+
plt.savefig(fname, rasterized=True, bbox_inches='tight')
310+
311+
assert os.path.isfile(fname), 'ERROR: plotting did not create file'
312+
313+
314+
if __name__ == "__main__":
315+
main()

0 commit comments

Comments
 (0)