Skip to content

Commit 6b883bf

Browse files
committed
Merge branch 'master' into parallel_mesh
# Conflicts: # pySDC/playgrounds/optimization/playground.py # pySDC/playgrounds/paralpha/playground_linear.py # pySDC/playgrounds/paralpha/playground_nonlinear.py
2 parents b7e35b2 + cbdfa4e commit 6b883bf

File tree

11 files changed

+789
-0
lines changed

11 files changed

+789
-0
lines changed

pySDC/core/Sweeper.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ def rho(x):
8686
QT = coll.Qmat[1:, 1:].T
8787
[_, _, U] = scipy.linalg.lu(QT, overwrite_a=True)
8888
QDmat[1:, 1:] = 2 * U.T
89+
elif qd_type == 'TRAP':
90+
for m in range(coll.num_nodes + 1):
91+
QDmat[m, 1:m + 1] = coll.delta_m[0:m]
92+
for m in range(coll.num_nodes + 1):
93+
QDmat[m, 0:m] += coll.delta_m[0:m]
94+
QDmat /= 2.0
8995
elif qd_type == 'IE':
9096
for m in range(coll.num_nodes + 1):
9197
QDmat[m, 1:m + 1] = coll.delta_m[0:m]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from pySDC.core.Hooks import hooks
2+
3+
4+
class error_output(hooks):
5+
"""
6+
Hook class to add output of error
7+
"""
8+
9+
def post_step(self, step, level_number):
10+
"""
11+
Default routine called after each step
12+
Args:
13+
step: the current step
14+
level_number: the current level number
15+
"""
16+
17+
super(error_output, self).post_step(step, level_number)
18+
19+
# some abbreviations
20+
L = step.levels[level_number]
21+
P = L.prob
22+
23+
L.sweep.compute_end_point()
24+
25+
# compute and save errors
26+
upde = P.u_exact(step.time + step.dt)
27+
pde_err = abs(upde - L.uend)
28+
29+
self.add_to_stats(process=step.status.slot, time=L.time + L.dt, level=L.level_index, iter=step.status.iter,
30+
sweep=L.status.sweep, type='error_after_step', value=pde_err)
31+
self.add_to_stats(process=step.status.slot, time=L.time + L.dt, level=L.level_index, iter=step.status.iter,
32+
sweep=L.status.sweep, type='residual_after_step', value=L.status.residual)

pySDC/playgrounds/Gander/__init__.py

Whitespace-only changes.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import numpy as np
2+
3+
from pySDC.helpers.stats_helper import filter_stats, sort_stats
4+
from pySDC.implementations.collocation_classes.gauss_radau_right import CollGaussRadau_Right
5+
from pySDC.implementations.controller_classes.controller_nonMPI import controller_nonMPI
6+
from pySDC.implementations.problem_classes.TestEquation_0D import testequation0d
7+
from pySDC.implementations.sweeper_classes.generic_implicit import generic_implicit
8+
from pySDC.playgrounds.Gander.HookClass_error_output import error_output
9+
10+
11+
def testequation_setup(prec_type=None, maxiter=None):
12+
"""
13+
Setup routine for the test equation
14+
15+
Args:
16+
par (float): parameter for controlling stiffness
17+
"""
18+
# initialize level parameters
19+
level_params = dict()
20+
level_params['restol'] = 0.0
21+
level_params['dt'] = 0.25
22+
level_params['nsweeps'] = [1]
23+
24+
# initialize sweeper parameters
25+
sweeper_params = dict()
26+
sweeper_params['collocation_class'] = CollGaussRadau_Right
27+
sweeper_params['num_nodes'] = [3]
28+
sweeper_params['QI'] = prec_type
29+
sweeper_params['initial_guess'] = 'spread'
30+
31+
# initialize problem parameters
32+
problem_params = dict()
33+
problem_params['u0'] = 1.0 # initial value (for all instances)
34+
# use single values like this...
35+
# problem_params['lambdas'] = [[-1.0]]
36+
# .. or a list of values like this ...
37+
# problem_params['lambdas'] = [[-1.0, -2.0, 1j, -1j]]
38+
problem_params['lambdas'] = [[-1000]]
39+
# note: PFASST will do all of those at once, but without interaction (realized via diagonal matrix).
40+
# The propagation matrix will be diagonal too, corresponding to the respective lambda value.
41+
42+
# initialize step parameters
43+
step_params = dict()
44+
step_params['maxiter'] = maxiter
45+
46+
# initialize controller parameters
47+
controller_params = dict()
48+
controller_params['logger_level'] = 30
49+
controller_params['hook_class'] = error_output
50+
51+
# fill description dictionary for easy step instantiation
52+
description = dict()
53+
description['problem_class'] = testequation0d # pass problem class
54+
description['problem_params'] = problem_params # pass problem parameters
55+
description['sweeper_class'] = generic_implicit # pass sweeper
56+
description['sweeper_params'] = sweeper_params # pass sweeper parameters
57+
description['level_params'] = level_params # pass level parameters
58+
description['step_params'] = step_params # pass step parameters
59+
60+
return description, controller_params
61+
62+
63+
def compare_preconditioners(f=None, list_of_k=None):
64+
65+
# set time parameters
66+
t0 = 0.0
67+
Tend = 1.0
68+
69+
for k in list_of_k:
70+
71+
description_IE, controller_params_IE = testequation_setup(prec_type='IE', maxiter=k)
72+
description_LU, controller_params_LU = testequation_setup(prec_type='LU', maxiter=k)
73+
74+
out = f'\nWorking with maxiter = {k}'
75+
f.write(out + '\n')
76+
print(out)
77+
78+
# instantiate controller
79+
controller_IE = controller_nonMPI(num_procs=1, controller_params=controller_params_IE, description=description_IE)
80+
controller_LU = controller_nonMPI(num_procs=1, controller_params=controller_params_LU, description=description_LU)
81+
82+
# get initial values on finest level
83+
P = controller_IE.MS[0].levels[0].prob
84+
uinit = P.u_exact(t0)
85+
uex = P.u_exact(Tend)
86+
87+
# this is where the iteration is happening
88+
uend_IE, stats_IE = controller_IE.run(u0=uinit, t0=t0, Tend=Tend)
89+
uend_LU, stats_LU = controller_LU.run(u0=uinit, t0=t0, Tend=Tend)
90+
91+
diff = abs(uend_IE - uend_LU)
92+
93+
err_IE = abs(uend_IE - uex)
94+
err_LU = abs(uend_LU - uex)
95+
96+
out = ' Error (IE/LU) vs. exact solution: %6.4e -- %6.4e' % (err_IE, err_LU)
97+
f.write(out + '\n')
98+
print(out)
99+
out = ' Difference between both results: %6.4e' % diff
100+
f.write(out + '\n')
101+
print(out)
102+
103+
# filter statistics by type
104+
filtered_stats_IE = filter_stats(stats_IE, type='error_after_step')
105+
filtered_stats_LU = filter_stats(stats_LU, type='error_after_step')
106+
107+
# convert filtered statistics to list
108+
errors_IE = sort_stats(filtered_stats_IE, sortby='time')
109+
errors_LU = sort_stats(filtered_stats_LU, sortby='time')
110+
print(errors_IE)
111+
print(errors_LU)
112+
113+
114+
def main():
115+
116+
f = open('comparison_IE_vs_LU.txt', 'w')
117+
compare_preconditioners(f=f, list_of_k=[1, 2, 3, 4])
118+
f.close()
119+
120+
121+
if __name__ == "__main__":
122+
main()
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import numpy as np
2+
import matplotlib.pyplot as plt
3+
4+
from pySDC.implementations.collocation_classes.gauss_lobatto import \
5+
CollGaussLobatto
6+
from pySDC.implementations.collocation_classes.gauss_radau_left import \
7+
CollGaussRadau_Left
8+
from pySDC.implementations.collocation_classes.gauss_radau_right import \
9+
CollGaussRadau_Right
10+
from pySDC.implementations.collocation_classes.equidistant import \
11+
Equidistant
12+
13+
collDict = {'LOBATTO': CollGaussLobatto,
14+
'RADAU_LEFT': CollGaussRadau_Left,
15+
'RADAU_RIGHT': CollGaussRadau_Right,
16+
'EQUID': Equidistant}
17+
18+
# Problem parameters
19+
tBeg = 0
20+
tEnd = 1
21+
lam = -1.0+1j # \lambda coefficient from the space operator
22+
numType = np.array(lam).dtype
23+
u0 = 1 # initial solution
24+
25+
# Discretization parameters
26+
L = 8 # number of time steps
27+
M = 5 # number of nodes
28+
sweepType = 'BE'
29+
nodesType = 'EQUID'
30+
31+
# Time interval decomposition
32+
times = np.linspace(tBeg, tEnd, num=L)
33+
dt = times[1]-times[0]
34+
35+
# Generate nodes, deltas and Q using pySDC
36+
coll = collDict[nodesType](M, 0, 1)
37+
nodes = coll._getNodes
38+
deltas = coll._gen_deltas
39+
Q = coll._gen_Qmatrix[1:, 1:]
40+
Q = Q*lam*dt
41+
42+
# Generate Q_\Delta
43+
QDelta = np.zeros((M, M))
44+
if sweepType in ['BE', 'FE']:
45+
offset = 1 if sweepType == 'FE' else 0
46+
for i in range(offset, M):
47+
QDelta[i:, :M-i] += np.diag(deltas[:M-i])
48+
else:
49+
raise ValueError(f'sweepType={sweepType}')
50+
QDelta = QDelta*lam*dt
51+
52+
print(QDelta.real)
53+
exit()
54+
55+
# Generate other matrices
56+
H = np.zeros((M, M), dtype=numType)
57+
H[:, -1] = 1
58+
I = np.identity(M)
59+
60+
# Generate operators
61+
ImQDelta = I - QDelta
62+
ImQ = I - Q
63+
64+
65+
def fineSweep(u, uStar, f):
66+
u += np.linalg.solve(ImQDelta, H.dot(uStar) + f - ImQ.dot(u))
67+
68+
69+
def coarseSweep(u, uStar, f):
70+
u += np.linalg.solve(ImQDelta, H.dot(uStar) + f)
71+
72+
73+
# Variables
74+
f = np.zeros((L, M), dtype=numType)
75+
f[0] = u0
76+
u = np.zeros((L, M), dtype=numType)
77+
t = np.array([t + dt*nodes for t in times])
78+
79+
# Exact solution
80+
uExact = np.exp(t*lam)
81+
82+
83+
nSweep = 3 # also number of iteration for Parareal-SDC and PFASST
84+
85+
# SDC solution
86+
uSDC = u.copy()
87+
# uSDC[:] = u0
88+
uStar = u[0]*0
89+
for l in range(L):
90+
for n in range(nSweep):
91+
fineSweep(uSDC[l], uStar, f[l])
92+
uStar = uSDC[l]
93+
94+
# Parareal-SDC solution <=> pipelined SDC <=> RIDC ?
95+
uPar = u.copy()
96+
# uPar[:] = u0
97+
for n in range(nSweep):
98+
uStar = u[0]*0
99+
for l in range(L):
100+
fineSweep(uPar[l], uStar, f[l])
101+
uStar = uPar[l]
102+
103+
# PFASST solution
104+
uPFA = u.copy()
105+
if True:
106+
# -- initialization with coarse sweep
107+
# (equivalent to fine sweep, since uPFA[l] = 0)
108+
uStar = u[0]*0
109+
for l in range(L):
110+
coarseSweep(uPFA[l], uStar, f[l])
111+
uStar = uPFA[l]
112+
# -- PFASST iteration
113+
for n in range(nSweep):
114+
uStar = u[0]*0
115+
for l in range(L):
116+
uStarPrev = uPFA[l].copy()
117+
fineSweep(uPFA[l], uStar, f[l])
118+
uStar = uStarPrev
119+
120+
# Plot solution and error
121+
if True:
122+
plt.figure('Solution (amplitude)')
123+
for sol, lbl, sym in [[uExact, 'Exact', 'o-'],
124+
[uSDC, 'SDC', 's-'],
125+
[uPar, 'Parareal', '>-'],
126+
[uPFA, 'PFASST', 'p-']]:
127+
plt.plot(t.ravel(), sol.ravel().real, sym, label=lbl)
128+
plt.legend()
129+
plt.grid(True)
130+
plt.xlabel('Time')
131+
132+
plt.figure('Solution (phase)')
133+
for sol, lbl, sym in [[uExact, 'Exact', 'o-'],
134+
[uSDC, 'SDC', 's-'],
135+
[uPar, 'Parareal', '>-'],
136+
[uPFA, 'PFASST', 'p-']]:
137+
plt.plot(t.ravel(), sol.ravel().imag, sym, label=lbl)
138+
plt.legend()
139+
plt.grid(True)
140+
plt.xlabel('Time')
141+
142+
eSDC = np.abs(uExact.ravel()-uSDC.ravel())
143+
ePar = np.abs(uExact.ravel()-uPar.ravel())
144+
ePFA = np.abs(uExact.ravel()-uPFA.ravel())
145+
146+
plt.figure('Error')
147+
plt.semilogy(t.ravel(), eSDC, 's-', label=f'SDC {nSweep} sweep')
148+
plt.semilogy(t.ravel(), ePar, '>-', label=f'Parareal {nSweep} iter')
149+
plt.semilogy(t.ravel(), ePFA, 'p-', label=f'PFASST {nSweep} iter')
150+
plt.legend()
151+
plt.grid(True)
152+
plt.xlabel('Time')
153+
154+
plt.show()

0 commit comments

Comments
 (0)