Skip to content

Commit 8085ed8

Browse files
committed
Merge branch 'feature/plot_stability' of https://github.com/danielru/pySDC into danielru-feature/plot_stability
2 parents aa639ad + 2ec9c6d commit 8085ed8

File tree

11 files changed

+335
-39
lines changed

11 files changed

+335
-39
lines changed

examples/acoustic_1d_imex/runconvergence.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
#description['transfer_class'] = mesh_to_mesh_1d
5555
#description['transfer_params'] = tparams
5656

57-
Nsteps = [20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80]
57+
Nsteps = [15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80]
5858

5959
for order in [2, 3, 4]:
6060

@@ -87,6 +87,10 @@
8787
# get initial values on finest level
8888
P = MS[0].levels[0].prob
8989
uinit = P.u_exact(t0)
90+
if ii==0:
91+
print "Time step: %4.2f" % dt
92+
print "Fast CFL number: %4.2f" % (pparams['cs']*dt/P.dx)
93+
print "Slow CFL number: %4.2f" % (pparams['cadv']*dt/P.dx)
9094

9195
# call main function to get things done...
9296
uend,stats = mp.run_pfasst(MS, u0=uinit, t0=t0, dt=dt, Tend=Tend)

examples/acoustic_1d_imex/runitererror.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@
8383
# get initial values on finest level
8484
P = MS[0].levels[0].prob
8585
uinit = P.u_exact(t0)
86+
87+
print "Fast CFL number: %4.2f" % (pparams['cs']*dt/P.dx)
88+
print "Slow CFL number: %4.2f" % (pparams['cadv']*dt/P.dx)
8689

8790
# call main function to get things done...
8891
uend,stats = mp.run_pfasst(MS, u0=uinit, t0=t0, dt=dt, Tend=Tend)
@@ -113,12 +116,12 @@
113116
for ii in range(0,np.size(cs_v)):
114117
x = np.arange(1,lastiter[ii,0])
115118
y = convrate[ii, 0, 0:lastiter[ii,0]-1]
116-
plt.plot(x, y, shape[ii], markersize=fs-2, color=color[ii], label=r'$c_{s}$=%4.2f' % cs_v[ii])
119+
plt.plot(x, y, shape[ii], markersize=fs-2, color=color[ii], label=r'$C_{\rm fast}$=%4.2f' % (cs_v[ii]*dt/P.dx))
117120
#plt.plot(x, 0.0*y+avg_convrate[ii,0], '--', color=color[ii])
118121

119122
plt.legend(loc='upper right', fontsize=fs, prop={'size':fs})
120123
plt.xlabel('Iteration', fontsize=fs)
121-
plt.ylabel('Convergence rate', fontsize=fs, labelpad=2)
124+
plt.ylabel(r'$|| r^{k+1} ||_{\infty}/|| r^k ||_{\infty}$', fontsize=fs, labelpad=2)
122125
plt.xlim([0, sparams['maxiter']])
123126
plt.ylim([0, 0.8])
124127
plt.yticks(fontsize=fs)

examples/boussinesq_2d_imex/ProblemClass.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def solve_system(self,rhs,factor,u0,t):
106106
sol, info = LA.gmres( self.Id - factor*self.M, b, x0=u0.values.flatten(), tol=self.gmres_tol, restart=self.gmres_restart, maxiter=self.gmres_maxiter, callback=cb)
107107
# If this is a dummy call with factor==0.0, do not log because it should not be counted as a solver call
108108
if factor!=0.0:
109-
print "SDC: Number of GMRES iterations: %3i --- Final residual: %6.3e" % ( cb.getcounter(), cb.getresidual() )
109+
#print "SDC: Number of GMRES iterations: %3i --- Final residual: %6.3e" % ( cb.getcounter(), cb.getresidual() )
110110
self.logger.add(cb.getcounter())
111111
me = mesh(self.nvars)
112112
me.values = unflatten(sol, 4, self.N[0], self.N[1])
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import numpy as np
2+
from matplotlib import pyplot as plt
3+
from mpl_toolkits.mplot3d import Axes3D
4+
from matplotlib import cm
5+
from matplotlib.ticker import LinearLocator, FormatStrFormatter
6+
from pylab import rcParams
7+
8+
from unflatten import unflatten
9+
10+
if __name__ == "__main__":
11+
xx = np.load('xaxis.npy')
12+
uend = np.load('sdc.npy')
13+
udirk2 = np.load('dirk2.npy')
14+
udirk4 = np.load('dirk4.npy')
15+
utrap = np.load('trap.npy')
16+
17+
fs = 8
18+
rcParams['figure.figsize'] = 5.0, 2.5
19+
fig = plt.figure()
20+
21+
plt.plot(xx[:,5], uend[2,:,5], '-', color='b', label='SDC')
22+
plt.plot(xx[:,5], udirk4[2,:,5], '--', color='g', markersize=fs-2, label='DIRK(4)', dashes=(3,3))
23+
plt.plot(xx[:,5], udirk2[2,:,5], '--', color='r', markersize=fs-2, label='DIRK(2)', dashes=(3,3))
24+
#plt.plot(xx[:,5], utrap[2,:,5], '--', color='k', markersize=fs-2, label='Trap', dashes=(3,3))
25+
plt.legend(loc='lower left', fontsize=fs, prop={'size':fs})
26+
plt.yticks(fontsize=fs)
27+
plt.xticks(fontsize=fs)
28+
plt.xlabel('x [km]', fontsize=fs, labelpad=0)
29+
plt.ylabel('Bouyancy', fontsize=fs, labelpad=1)
30+
#plt.show()
31+
plt.savefig('boussinesq.pdf', bbox_inches='tight')
32+

examples/boussinesq_2d_imex/rungmrescounter.py

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
from unflatten import unflatten
2323

24-
from standard_integrators import dirk
24+
from standard_integrators import dirk, bdf2, trapezoidal
2525

2626
if __name__ == "__main__":
2727

@@ -40,16 +40,14 @@
4040
swparams['do_LU'] = False
4141

4242
sparams = {}
43-
sparams['maxiter'] = 3
43+
sparams['maxiter'] = 4
4444

45-
dirk_order = 2
45+
dirk_order = 4
4646

4747
# setup parameters "in time"
4848
t0 = 0
4949
Tend = 3000
50-
Nsteps = 500
51-
#Tend = 30
52-
#Nsteps = 5
50+
Nsteps = 100
5351
dt = Tend/float(Nsteps)
5452

5553
# This comes as read-in for the problem class
@@ -92,41 +90,63 @@
9290
cfl_advection = pparams['u_adv']*dt/P.h[0]
9391
cfl_acoustic_hor = pparams['c_s']*dt/P.h[0]
9492
cfl_acoustic_ver = pparams['c_s']*dt/P.h[1]
93+
print "Horizontal resolution: %4.2f" % P.h[0]
94+
print "Vertical resolution: %4.2f" % P.h[1]
9595
print ("CFL number of advection: %4.2f" % cfl_advection)
9696
print ("CFL number of acoustics (horizontal): %4.2f" % cfl_acoustic_hor)
9797
print ("CFL number of acoustics (vertical): %4.2f" % cfl_acoustic_ver)
9898

99-
dirk = dirk(P, dirk_order)
99+
dirk4 = dirk(P, 4)
100+
dirk2 = dirk(P, 2)
101+
trap = trapezoidal(P)
102+
bdf = bdf2(P)
100103
u0 = uinit.values.flatten()
101-
104+
udirk4 = u0
105+
udirk2 = u0
106+
ubdf = u0
107+
utrap = u0
102108
for i in range(0,Nsteps):
103-
u0 = dirk.timestep(u0, dt)
104-
109+
udirk4 = dirk4.timestep(udirk4, dt)
110+
udirk2 = dirk2.timestep(udirk2, dt)
111+
utrap = trap.timestep(utrap, dt)
112+
#if i==0:
113+
# ubdf_new = bdf.firsttimestep(ubdf, dt)
114+
# ubdf_m1 = ubdf
115+
#else:
116+
# ubdf_new = bdf.timestep(ubdf, ubdf_m1, dt)
117+
#ubdf_m1 = ubdf
118+
#ubdf = ubdf_new
119+
105120
# call main function to get things done...
106121
uend,stats = mp.run_pfasst(MS,u0=uinit,t0=t0,dt=dt,Tend=Tend)
107-
108-
u0 = unflatten(u0, 4, P.N[0], P.N[1])
109-
110-
fs = 8
111-
rcParams['figure.figsize'] = 5.0, 2.5
112-
fig = plt.figure()
113-
114-
plt.plot(P.xx[:,5], uend.values[2,:,5], '-', color='b', label='SDC')
115-
plt.plot(P.xx[:,5], u0[2,:,5], '+', color='g', markevery=5, markersize=fs-2, label='DIRK')
116-
plt.legend(loc='lower left', fontsize=fs, prop={'size':fs})
117-
plt.yticks(fontsize=fs)
118-
plt.xticks(fontsize=fs)
119-
plt.xlabel('x', fontsize=fs, labelpad=0)
120-
plt.ylabel('Bouyancy', fontsize=fs, labelpad=1)
121-
#plt.show()
122-
plt.savefig('boussinesq.pdf', bbox_inches='tight')
123-
124-
print " #### Logging report for DIRK #### "
125-
print "Number of calls to implicit solver: %5i" % dirk.logger.solver_calls
126-
print "Total number of GMRES iterations: %5i" % dirk.logger.iterations
127-
print "Average number of iterations per call: %6.3f" % (float(dirk.logger.iterations)/float(dirk.logger.solver_calls))
122+
udirk4 = unflatten(udirk4, 4, P.N[0], P.N[1])
123+
udirk2 = unflatten(udirk2, 4, P.N[0], P.N[1])
124+
print "Norm of final solution by trapezoidal rule: %5.3f" % np.linalg.norm( utrap, np.inf )
125+
utrap = unflatten(utrap, 4, P.N[0], P.N[1])
126+
127+
np.save('xaxis', P.xx)
128+
np.save('sdc', uend.values)
129+
np.save('dirk2', udirk2)
130+
np.save('dirk4', udirk4)
131+
np.save('trap', utrap)
128132

129-
print " #### Logging report for SDC #### "
133+
print " #### Logging report for DIRK-4 #### "
134+
print "Number of calls to implicit solver: %5i" % dirk4.logger.solver_calls
135+
print "Total number of GMRES iterations: %5i" % dirk4.logger.iterations
136+
print "Average number of iterations per call: %6.3f" % (float(dirk4.logger.iterations)/float(dirk4.logger.solver_calls))
137+
138+
print " #### Logging report for DIRK-2 #### "
139+
print "Number of calls to implicit solver: %5i" % dirk2.logger.solver_calls
140+
print "Total number of GMRES iterations: %5i" % dirk2.logger.iterations
141+
print "Average number of iterations per call: %6.3f" % (float(dirk2.logger.iterations)/float(dirk2.logger.solver_calls))
142+
143+
#print " #### Logging report for BDF2 #### "
144+
#print "Number of calls to implicit solver: %5i" % bdf.logger.solver_calls
145+
#print "Total number of GMRES iterations: %5i" % bdf.logger.iterations
146+
#print "Average number of iterations per call: %6.3f" % (float(bdf.logger.iterations)/float(bdf.logger.solver_calls))
147+
148+
print " #### Logging report for SDC-(%1i,%1i) #### " % (swparams['num_nodes'], sparams['maxiter'])
130149
print "Number of calls to implicit solver: %5i" % P.logger.solver_calls
131150
print "Total number of GMRES iterations: %5i" % P.logger.iterations
132-
print "Average number of iterations per call: %6.3f" % (float(P.logger.iterations)/float(P.logger.solver_calls))
151+
print "Average number of iterations per call: %6.3f" % (float(P.logger.iterations)/float(P.logger.solver_calls))
152+

examples/boussinesq_2d_imex/standard_integrators.py

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,79 @@
44
import scipy.sparse as sp
55
from ProblemClass import Callback, logging, boussinesq_2d_imex
66

7+
#
8+
# Trapezoidal rule
9+
#
10+
class trapezoidal:
11+
12+
def __init__(self, problem, alpha=0.5):
13+
assert isinstance(problem, boussinesq_2d_imex), "problem is wrong type of object"
14+
self.Ndof = np.shape(problem.M)[0]
15+
self.order = 2
16+
self.logger = logging()
17+
self.problem = problem
18+
self.alpha = alpha
19+
20+
def timestep(self, u0, dt):
21+
B_trap = sp.eye(self.Ndof) + self.alpha*dt*(self.problem.D_upwind + self.problem.M)
22+
b = B_trap.dot(u0)
23+
return self.f_solve(b, alpha=(1.0-self.alpha)*dt, u0 = u0)
24+
25+
#
26+
# Returns f(u) = c*u
27+
#
28+
def f(self,u):
29+
return self.problem.D_upwind.dot(u)+self.problem.M.dot(u)
30+
31+
32+
#
33+
# Solves (Id - alpha*c)*u = b for u
34+
#
35+
def f_solve(self, b, alpha, u0):
36+
cb = Callback()
37+
sol, info = LA.gmres( self.problem.Id - alpha*(self.problem.D_upwind + self.problem.M), b, x0=u0, tol=self.problem.gmres_tol, restart=self.problem.gmres_restart, maxiter=self.problem.gmres_maxiter, callback=cb)
38+
if alpha!=0.0:
39+
#print "BDF-2: Number of GMRES iterations: %3i --- Final residual: %6.3e" % ( cb.getcounter(), cb.getresidual() )
40+
self.logger.add(cb.getcounter())
41+
return sol
42+
43+
#
44+
# A BDF-2 implicit two-step method
45+
#
46+
class bdf2:
47+
48+
def __init__(self, problem):
49+
assert isinstance(problem, boussinesq_2d_imex), "problem is wrong type of object"
50+
self.Ndof = np.shape(problem.M)[0]
51+
self.order = 2
52+
self.logger = logging()
53+
self.problem = problem
54+
55+
def firsttimestep(self, u0, dt):
56+
return self.f_solve(b = u0, alpha = dt, u0 = u0)
57+
58+
def timestep(self, u0, um1, dt):
59+
b = (4.0/3.0)*u0 - (1.0/3.0)*um1
60+
return self.f_solve(b = b, alpha = (2.0/3.0)*dt, u0 = u0)
61+
62+
#
63+
# Returns f(u) = c*u
64+
#
65+
def f(self,u):
66+
return self.problem.D_upwind.dot(u)+self.problem.M.dot(u)
67+
68+
69+
#
70+
# Solves (Id - alpha*c)*u = b for u
71+
#
72+
def f_solve(self, b, alpha, u0):
73+
cb = Callback()
74+
sol, info = LA.gmres( self.problem.Id - alpha*(self.problem.D_upwind + self.problem.M), b, x0=u0, tol=self.problem.gmres_tol, restart=self.problem.gmres_restart, maxiter=self.problem.gmres_maxiter, callback=cb)
75+
if alpha!=0.0:
76+
#print "BDF-2: Number of GMRES iterations: %3i --- Final residual: %6.3e" % ( cb.getcounter(), cb.getresidual() )
77+
self.logger.add(cb.getcounter())
78+
return sol
79+
780
#
881
# A diagonally implicit Runge-Kutta method of order 2, 3 or 4
982
#
@@ -117,6 +190,6 @@ def f_solve(self, b, alpha, u0):
117190
cb = Callback()
118191
sol, info = LA.gmres( self.problem.Id - alpha*(self.problem.D_upwind + self.problem.M), b, x0=u0, tol=self.problem.gmres_tol, restart=self.problem.gmres_restart, maxiter=self.problem.gmres_maxiter, callback=cb)
119192
if alpha!=0.0:
120-
print "DIRK: Number of GMRES iterations: %3i --- Final residual: %6.3e" % ( cb.getcounter(), cb.getresidual() )
193+
#print "DIRK-%1i: Number of GMRES iterations: %3i --- Final residual: %6.3e" % ( self.order, cb.getcounter(), cb.getresidual() )
121194
self.logger.add(cb.getcounter())
122195
return sol
File renamed without changes.
File renamed without changes.

examples/SWFW/playground.py renamed to examples/fwsw/playground.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import numpy as np
66
import matplotlib.pyplot as plt
77

8-
from examples.SWFW.ProblemClass import swfw_scalar
8+
from examples.fwsw.ProblemClass import swfw_scalar
99
from pySDC.datatype_classes.complex_mesh import mesh, rhs_imex_mesh
1010
from pySDC.sweeper_classes.imex_1st_order import imex_1st_order
1111
import pySDC.PFASST_stepwise as mp

examples/fwsw/plot_stability.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from pySDC import Level as lvl
2+
from pySDC import Hooks as hookclass
3+
from pySDC import CollocationClasses as collclass
4+
from pySDC import Step as stepclass
5+
6+
from pySDC.datatype_classes.complex_mesh import mesh, rhs_imex_mesh
7+
from pySDC.sweeper_classes.imex_1st_order import imex_1st_order as imex
8+
from examples.fwsw.ProblemClass import swfw_scalar
9+
import numpy as np
10+
11+
from pylab import rcParams
12+
import matplotlib.pyplot as plt
13+
from subprocess import call
14+
15+
if __name__ == "__main__":
16+
17+
N_s = 100
18+
N_f = 400
19+
20+
lambda_s = 1j*np.linspace(0.0, 2.0, N_s)
21+
lambda_f = 1j*np.linspace(2.0, 8.0, N_f)
22+
23+
pparams = {}
24+
# the following are not used in the computation
25+
pparams['lambda_s'] = np.array([0.0])
26+
pparams['lambda_f'] = np.array([0.0])
27+
pparams['u0'] = 1.0
28+
swparams = {}
29+
swparams['collocation_class'] = collclass.CollGaussLobatto
30+
swparams['num_nodes'] = 4
31+
K = 5
32+
33+
#
34+
# ...this is functionality copied from test_imexsweeper. Ideally, it should be available in one place.
35+
#
36+
step = stepclass.step(params={})
37+
L = lvl.level(problem_class=swfw_scalar, problem_params=pparams, dtype_u=mesh, dtype_f=rhs_imex_mesh, sweeper_class=imex, sweeper_params=swparams, level_params={}, hook_class=hookclass.hooks, id="stability")
38+
step.register_level(L)
39+
step.status.dt = 1.0
40+
step.status.time = 0.0
41+
u0 = step.levels[0].prob.u_exact(step.status.time)
42+
step.init_step(u0)
43+
nnodes = step.levels[0].sweep.coll.num_nodes
44+
level = step.levels[0]
45+
problem = level.prob
46+
47+
QE = level.sweep.QE[1:,1:]
48+
QI = level.sweep.QI[1:,1:]
49+
Q = level.sweep.coll.Qmat[1:,1:]
50+
51+
stab = np.zeros((N_f, N_s), dtype='complex')
52+
53+
for i in range(0,N_s):
54+
for j in range(0,N_f):
55+
lambda_fast = lambda_f[j]
56+
lambda_slow = lambda_s[i]
57+
LHS = np.eye(nnodes) - step.status.dt*( lambda_fast*QI + lambda_slow*QE )
58+
RHS = step.status.dt*( (lambda_fast+lambda_slow)*Q - (lambda_fast*QI + lambda_slow*QE) )
59+
60+
Pinv = np.linalg.inv(LHS)
61+
Mat_sweep = np.linalg.matrix_power(Pinv.dot(RHS), K)
62+
for k in range(0,K):
63+
Mat_sweep = Mat_sweep + np.linalg.matrix_power(Pinv.dot(RHS),k).dot(Pinv)
64+
stab_fh = 1.0 + (lambda_fast + lambda_slow)*level.sweep.coll.weights.dot(Mat_sweep.dot(np.ones(nnodes)))
65+
stab[j,i] = stab_fh
66+
67+
###
68+
rcParams['figure.figsize'] = 2.5, 2.5
69+
fs = 8
70+
fig = plt.figure()
71+
#pcol = plt.pcolor(lambda_s.imag, lambda_f.imag, np.absolute(stab), vmin=0.99, vmax=2.01)
72+
#pcol.set_edgecolor('face')
73+
levels = np.array([0.95, 0.99, 1.01, 1.05])
74+
# levels = np.array([1.0])
75+
CS1 = plt.contour(lambda_s.imag, lambda_f.imag, np.absolute(stab), levels, colors='k',linestyles='dashed')
76+
CS2 = plt.contour(lambda_s.imag, lambda_f.imag, np.absolute(stab), [1.0], colors='k')
77+
plt.clabel(CS1, fontsize=fs-2)
78+
plt.clabel(CS2, fontsize=fs-2)
79+
#plt.plot([0, 2], [0, 2], color='k', linewidth=1)
80+
plt.gca().set_xticks([0.0, 1.0, 2.0, 3.0])
81+
plt.gca().tick_params(axis='both', which='both', labelsize=fs)
82+
plt.xlim([np.min(lambda_s.imag), np.max(lambda_s.imag)])
83+
plt.xlabel('$\Delta t \lambda_{slow}$', fontsize=fs, labelpad=2.0)
84+
plt.ylabel('$\Delta t \lambda_{fast}$', fontsize=fs)
85+
plt.title(r'$M=%1i$, $K=%1i$' % (swparams['num_nodes'],K), fontsize=fs)
86+
filename = 'sdc-fwsw-stability-K'+str(K)+'-M'+str(swparams['num_nodes'])+'.pdf'
87+
fig.savefig(filename, bbox_inches='tight')
88+
call(["pdfcrop", filename, filename])
89+

0 commit comments

Comments
 (0)