Skip to content

Commit e93845d

Browse files
author
Daniel Ruprecht
committed
added functions for standard integrators
1 parent 277491b commit e93845d

File tree

2 files changed

+281
-0
lines changed

2 files changed

+281
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
2+
from pySDC import CollocationClasses as collclass
3+
4+
import numpy as np
5+
6+
from ProblemClass import boussinesq_2d_imex
7+
from examples.boussinesq_2d_imex.TransferClass import mesh_to_mesh_2d
8+
from examples.boussinesq_2d_imex.HookClass import plot_solution
9+
10+
from pySDC.datatype_classes.mesh import mesh, rhs_imex_mesh
11+
from pySDC.sweeper_classes.imex_1st_order import imex_1st_order
12+
import pySDC.PFASST_stepwise as mp
13+
from pySDC import Log
14+
from pySDC.Stats import grep_stats, sort_stats
15+
16+
from matplotlib import pyplot as plt
17+
from mpl_toolkits.mplot3d import Axes3D
18+
from matplotlib import cm
19+
from matplotlib.ticker import LinearLocator, FormatStrFormatter
20+
from unflatten import unflatten
21+
22+
from standard_integrators import dirk
23+
24+
if __name__ == "__main__":
25+
26+
# set global logger (remove this if you do not want the output at all)
27+
logger = Log.setup_custom_logger('root')
28+
29+
num_procs = 1
30+
31+
# This comes as read-in for the level class
32+
lparams = {}
33+
lparams['restol'] = 1E-8
34+
35+
swparams = {}
36+
swparams['collocation_class'] = collclass.CollGaussLobatto
37+
swparams['num_nodes'] = 3
38+
swparams['do_LU'] = True
39+
40+
sparams = {}
41+
sparams['maxiter'] = 4
42+
43+
dirk_order = 4
44+
45+
# setup parameters "in time"
46+
t0 = 0
47+
Tend = 3000
48+
Nsteps = 500
49+
#Tend = 30
50+
#Nsteps = 5
51+
dt = Tend/float(Nsteps)
52+
53+
# This comes as read-in for the problem class
54+
pparams = {}
55+
pparams['nvars'] = [(4,450,30)]
56+
#pparams['nvars'] = [(4,150,10)]
57+
pparams['u_adv'] = 0.02
58+
pparams['c_s'] = 0.3
59+
pparams['Nfreq'] = 0.01
60+
pparams['x_bounds'] = [(-150.0, 150.0)]
61+
pparams['z_bounds'] = [( 0.0, 10.0)]
62+
pparams['order'] = [4] # [fine_level, coarse_level]
63+
pparams['order_upw'] = [5]
64+
pparams['gmres_maxiter'] = [50]
65+
pparams['gmres_restart'] = [20]
66+
pparams['gmres_tol'] = [1e-6]
67+
68+
# This comes as read-in for the transfer operations
69+
tparams = {}
70+
tparams['finter'] = False
71+
72+
# Fill description dictionary for easy hierarchy creation
73+
description = {}
74+
description['problem_class'] = boussinesq_2d_imex
75+
description['problem_params'] = pparams
76+
description['dtype_u'] = mesh
77+
description['dtype_f'] = rhs_imex_mesh
78+
description['sweeper_params'] = swparams
79+
description['sweeper_class'] = imex_1st_order
80+
description['level_params'] = lparams
81+
description['hook_class'] = plot_solution
82+
83+
# quickly generate block of steps
84+
MS = mp.generate_steps(num_procs,sparams,description)
85+
86+
# get initial values on finest level
87+
P = MS[0].levels[0].prob
88+
uinit = P.u_exact(t0)
89+
90+
dirk = dirk(P.D_upwind + P.M, dirk_order, pparams['gmres_maxiter'], pparams['gmres_restart'], pparams['gmres_tol'])
91+
u0 = uinit.values.flatten()
92+
93+
for i in range(0,Nsteps):
94+
u0 = dirk.timestep(u0, dt)
95+
96+
cfl_advection = pparams['u_adv']*dt/P.h[0]
97+
cfl_acoustic_hor = pparams['c_s']*dt/P.h[0]
98+
cfl_acoustic_ver = pparams['c_s']*dt/P.h[1]
99+
print ("CFL number of advection: %4.2f" % cfl_advection)
100+
print ("CFL number of acoustics (horizontal): %4.2f" % cfl_acoustic_hor)
101+
print ("CFL number of acoustics (vertical): %4.2f" % cfl_acoustic_ver)
102+
103+
# call main function to get things done...
104+
uend,stats = mp.run_pfasst(MS,u0=uinit,t0=t0,dt=dt,Tend=Tend)
105+
106+
u0 = unflatten(u0, 4, P.N[0], P.N[1])
107+
fig = plt.figure()
108+
109+
plt.plot(P.xx[:,5], uend.values[2,:,5], color='r', marker='+', markevery=3)
110+
plt.plot(P.xx[:,5], u0[2,:,5], color='b', markevery=5)
111+
plt.show()
112+
113+
print " #### Logging report for DIRK #### "
114+
print "Number of calls to implicit solver: %5i" % dirk.logger.solver_calls
115+
print "Total number of GMRES iterations: %5i" % dirk.logger.iterations
116+
print "Average number of iterations per call: %6.3f" % (float(dirk.logger.iterations)/float(dirk.logger.solver_calls))
117+
118+
print " #### Logging report for SDC #### "
119+
print "Number of calls to implicit solver: %5i" % P.logger.solver_calls
120+
print "Total number of GMRES iterations: %5i" % P.logger.iterations
121+
print "Average number of iterations per call: %6.3f" % (float(P.logger.iterations)/float(P.logger.solver_calls))
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import numpy as np
2+
import math
3+
import scipy.sparse.linalg as LA
4+
import scipy.sparse as sp
5+
from ProblemClass import Callback, logging
6+
#
7+
# Trapezoidal rule
8+
#
9+
class trapezoidal:
10+
11+
def __init__(self, M, alpha=0.5):
12+
assert np.shape(M)[0]==np.shape(M)[1], "Matrix M must be quadratic"
13+
self.Ndof = np.shape(M)[0]
14+
self.M = M
15+
self.alpha = alpha
16+
17+
def timestep(self, u0, dt):
18+
M_trap = sp.eye(self.Ndof) - self.alpha*dt*self.M
19+
B_trap = sp.eye(self.Ndof) + (1.0-self.alpha)*dt*self.M
20+
b = B_trap.dot(u0)
21+
return LA.spsolve(M_trap, b)
22+
#
23+
# A BDF-2 implicit two-step method
24+
#
25+
class bdf2:
26+
27+
def __init__(self, M):
28+
assert np.shape(M)[0]==np.shape(M)[1], "Matrix M must be quadratic"
29+
self.Ndof = np.shape(M)[0]
30+
self.M = M
31+
32+
def firsttimestep(self, u0, dt):
33+
b = u0
34+
L = sp.eye(self.Ndof) - dt*self.M
35+
return LA.spsolve(L, b)
36+
37+
def timestep(self, u0, um1, dt):
38+
b = (4.0/3.0)*u0 - (1.0/3.0)*um1
39+
L = sp.eye(self.Ndof) - (2.0/3.0)*dt*self.M
40+
return LA.spsolve(L, b)
41+
#
42+
# A diagonally implicit Runge-Kutta method of order 2, 3 or 4
43+
#
44+
class dirk:
45+
46+
def __init__(self, M, order, gmres_maxiter, gmres_restart, gmres_tol):
47+
48+
assert np.shape(M)[0]==np.shape(M)[1], "Matrix M must be quadratic"
49+
self.Ndof = np.shape(M)[0]
50+
self.M = M
51+
self.order = order
52+
self.logger = logging()
53+
self.gmres_maxiter = gmres_maxiter
54+
self.gmres_restart = gmres_restart
55+
self.gmres_tol = gmres_tol
56+
57+
assert self.order in [2,22,3,4], 'Order must be 2,22,3,4'
58+
59+
if (self.order==2):
60+
self.nstages = 1
61+
self.A = np.zeros((1,1))
62+
self.A[0,0] = 0.5
63+
self.tau = [0.5]
64+
self.b = [1.0]
65+
66+
if (self.order==22):
67+
self.nstages = 2
68+
self.A = np.zeros((2,2))
69+
self.A[0,0] = 1.0/3.0
70+
self.A[1,0] = 1.0/2.0
71+
self.A[1,1] = 1.0/2.0
72+
73+
self.tau = np.zeros(2)
74+
self.tau[0] = 1.0/3.0
75+
self.tau[1] = 1.0
76+
77+
self.b = np.zeros(2)
78+
self.b[0] = 3.0/4.0
79+
self.b[1] = 1.0/4.0
80+
81+
82+
if (self.order==3):
83+
self.nstages = 2
84+
self.A = np.zeros((2,2))
85+
self.A[0,0] = 0.5 + 1.0/( 2.0*math.sqrt(3.0) )
86+
self.A[1,0] = -1.0/math.sqrt(3.0)
87+
self.A[1,1] = self.A[0,0]
88+
89+
self.tau = np.zeros(2)
90+
self.tau[0] = 0.5 + 1.0/( 2.0*math.sqrt(3.0) )
91+
self.tau[1] = 0.5 - 1.0/( 2.0*math.sqrt(3.0) )
92+
93+
self.b = np.zeros(2)
94+
self.b[0] = 0.5
95+
self.b[1] = 0.5
96+
97+
if (self.order==4):
98+
self.nstages = 3
99+
alpha = 2.0*math.cos(math.pi/18.0)/math.sqrt(3.0)
100+
101+
self.A = np.zeros((3,3))
102+
self.A[0,0] = (1.0 + alpha)/2.0
103+
self.A[1,0] = -alpha/2.0
104+
self.A[1,1] = self.A[0,0]
105+
self.A[2,0] = (1.0 + alpha)
106+
self.A[2,1] = -(1.0 + 2.0*alpha)
107+
self.A[2,2] = self.A[0,0]
108+
109+
self.tau = np.zeros(3)
110+
self.tau[0] = (1.0 + alpha)/2.0
111+
self.tau[1] = 1.0/2.0
112+
self.tau[2] = (1.0 - alpha)/2.0
113+
114+
self.b = np.zeros(3)
115+
self.b[0] = 1.0/(6.0*alpha*alpha)
116+
self.b[1] = 1.0 - 1.0/(3.0*alpha*alpha)
117+
self.b[2] = 1.0/(6.0*alpha*alpha)
118+
119+
self.stages = np.zeros((self.nstages,self.Ndof))
120+
121+
def timestep(self, u0, dt):
122+
123+
uend = u0
124+
for i in range(0,self.nstages):
125+
126+
b = u0
127+
128+
# Compute right hand side for this stage's implicit step
129+
for j in range(0,i):
130+
b = b + self.A[i,j]*dt*self.f(self.stages[j,:])
131+
132+
# Implicit solve for current stage
133+
#if i==0:
134+
self.stages[i,:] = self.f_solve( b, dt*self.A[i,i] , u0 )
135+
#else:
136+
# self.stages[i,:] = self.f_solve( b, dt*self.A[i,i] , self.stages[i-1,:] )
137+
138+
# Add contribution of current stage to final value
139+
uend = uend + self.b[i]*dt*self.f(self.stages[i,:])
140+
141+
return uend
142+
143+
#
144+
# Returns f(u) = c*u
145+
#
146+
def f(self,u):
147+
return self.M.dot(u)
148+
149+
150+
#
151+
# Solves (Id - alpha*c)*u = b for u
152+
#
153+
def f_solve(self, b, alpha, u0):
154+
cb = Callback()
155+
L = sp.eye(self.Ndof) - alpha*self.M
156+
sol, info = LA.gmres( L, b, x0=u0, tol=self.gmres_tol, restart=self.gmres_restart, maxiter=self.gmres_maxiter, callback=cb)
157+
if alpha!=0.0:
158+
print "DIRK: Number of GMRES iterations: %3i --- Final residual: %6.3e" % ( cb.getcounter(), cb.getresidual() )
159+
self.logger.add(cb.getcounter())
160+
return sol

0 commit comments

Comments
 (0)