Skip to content

Commit e72a7cd

Browse files
committed
Bayreuth 1D SDC code is up and running, very stable
1 parent 17cf364 commit e72a7cd

File tree

4 files changed

+255
-34
lines changed

4 files changed

+255
-34
lines changed

pySDC/implementations/problem_classes/AllenCahn_1D_FD.py

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@
55

66
from pySDC.core.Errors import ParameterError, ProblemError
77
from pySDC.core.Problem import ptype
8-
from pySDC.implementations.datatype_classes.mesh import mesh
8+
from pySDC.implementations.datatype_classes.mesh import mesh, rhs_imex_mesh
99

1010

11-
# noinspection PyUnusedLocal
12-
class allencahn_front(ptype):
11+
class allencahn_front_fullyimplicit(ptype):
1312
"""
1413
Example implementing the Allen-Cahn equation in 1D with finite differences and inhomogeneous Dirichlet-BC,
1514
with driving force, 0-1 formulation (Bayreuth example)
@@ -44,7 +43,7 @@ def __init__(self, problem_params, dtype_u=mesh, dtype_f=mesh):
4443
problem_params['stop_at_nan'] = True
4544

4645
# invoke super init, passing number of dofs, dtype_u and dtype_f
47-
super(allencahn_front, self).__init__(problem_params['nvars'], dtype_u, dtype_f, problem_params)
46+
super(allencahn_front_fullyimplicit, self).__init__(problem_params['nvars'], dtype_u, dtype_f, problem_params)
4847

4948
# compute dx and get discretization matrix A
5049
self.dx = (self.params.interval[1] - self.params.interval[0]) / (self.params.nvars + 1)
@@ -92,7 +91,6 @@ def solve_system(self, rhs, factor, u0, t):
9291
"""
9392

9493
u = self.dtype_u(u0).values
95-
z = self.dtype_u(self.init, val=0.0).values
9694
eps2 = self.params.eps ** 2
9795
dw = self.params.dw
9896

@@ -188,17 +186,96 @@ def u_exact(self, t):
188186
return me
189187

190188

191-
# noinspection PyUnusedLocal
192-
class allencahn_front_finel(allencahn_front):
189+
class allencahn_front_semiimplicit(allencahn_front_fullyimplicit):
193190
"""
194191
Example implementing the Allen-Cahn equation in 1D with finite differences and inhomogeneous Dirichlet-BC,
195-
with driving force, 0-1 formulation (Bayreuth example), Finel's trick/parametrization
192+
with driving force, 0-1 formulation (Bayreuth example), semi-implicit time-stepping
196193
197194
Attributes:
198195
A: second-order FD discretization of the 1D laplace operator
199196
dx: distance between two spatial nodes
200197
"""
201198

199+
def __init__(self, problem_params, dtype_u=mesh, dtype_f=rhs_imex_mesh):
200+
"""
201+
Initialization routine
202+
203+
Args:
204+
problem_params (dict): custom parameters for the example
205+
dtype_u: mesh data type (will be passed parent class)
206+
dtype_f: mesh data type with implicit and explicit components (will be passed parent class)
207+
"""
208+
209+
# these parameters will be used later, so assert their existence
210+
essential_keys = ['nvars', 'dw', 'eps', 'newton_maxiter', 'newton_tol', 'interval']
211+
for key in essential_keys:
212+
if key not in problem_params:
213+
msg = 'need %s to instantiate problem, only got %s' % (key, str(problem_params.keys()))
214+
raise ParameterError(msg)
215+
216+
# we assert that nvars looks very particular here.. this will be necessary for coarsening in space later on
217+
if (problem_params['nvars'] + 1) % 2 != 0:
218+
raise ProblemError('setup requires nvars = 2^p - 1')
219+
220+
if 'stop_at_nan' not in problem_params:
221+
problem_params['stop_at_nan'] = True
222+
223+
# invoke super init, passing number of dofs, dtype_u and dtype_f
224+
super(allencahn_front_semiimplicit, self).__init__(problem_params, dtype_u, dtype_f)
225+
226+
def eval_f(self, u, t):
227+
"""
228+
Routine to evaluate the RHS
229+
230+
Args:
231+
u (dtype_u): current values
232+
t (float): current time
233+
234+
Returns:
235+
dtype_f: the RHS
236+
"""
237+
# set up boundary values to embed inner points
238+
v = 3.0 * np.sqrt(2) * self.params.eps * self.params.dw
239+
self.uext.values[0] = 0.5 * (1 + np.tanh((self.params.interval[0] - v * t) / (np.sqrt(2) * self.params.eps)))
240+
self.uext.values[-1] = 0.5 * (1 + np.tanh((self.params.interval[1] - v * t) / (np.sqrt(2) * self.params.eps)))
241+
242+
self.uext.values[1:-1] = u.values[:]
243+
244+
f = self.dtype_f(self.init)
245+
f.impl.values = self.A.dot(self.uext.values)[1:-1]
246+
f.expl.values = - 2.0 / self.params.eps ** 2 * u.values * (1.0 - u.values) * (1.0 - 2 * u.values) - \
247+
6.0 * self.params.dw * u.values * (1.0 - u.values)
248+
return f
249+
250+
def solve_system(self, rhs, factor, u0, t):
251+
"""
252+
Simple linear solver for (I-factor*A)u = rhs
253+
254+
Args:
255+
rhs (dtype_f): right-hand side for the linear system
256+
factor (float): abbrev. for the local stepsize (or any other factor required)
257+
u0 (dtype_u): initial guess for the iterative solver
258+
t (float): current time (e.g. for time-dependent BCs)
259+
260+
Returns:
261+
dtype_u: solution as mesh
262+
"""
263+
264+
me = self.dtype_u(self.init)
265+
self.uext.values[0] = 0.0
266+
self.uext.values[-1] = 0.0
267+
self.uext.values[1:-1] = rhs.values[:]
268+
me.values = spsolve(sp.eye(self.params.nvars + 2, format='csc') - factor * self.A, self.uext.values)[1:-1]
269+
# me.values = spsolve(sp.eye(self.params.nvars, format='csc') - factor * self.A[1:-1, 1:-1], rhs.values)
270+
return me
271+
272+
273+
class allencahn_front_finel(allencahn_front_fullyimplicit):
274+
"""
275+
Example implementing the Allen-Cahn equation in 1D with finite differences and inhomogeneous Dirichlet-BC,
276+
with driving force, 0-1 formulation (Bayreuth example), Finel's trick/parametrization
277+
"""
278+
202279
# noinspection PyTypeChecker
203280
def solve_system(self, rhs, factor, u0, t):
204281
"""

pySDC/playgrounds/Allen_Cahn/AllenCahn_Bayreuth_1D.py

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
from pySDC.helpers.stats_helper import filter_stats, sort_stats
99
from pySDC.implementations.collocation_classes.gauss_radau_right import CollGaussRadau_Right
1010
from pySDC.implementations.controller_classes.controller_nonMPI import controller_nonMPI
11-
from pySDC.implementations.problem_classes.AllenCahn_1D_FD import allencahn_front, allencahn_front_finel
11+
from pySDC.implementations.problem_classes.AllenCahn_1D_FD import allencahn_front_fullyimplicit, allencahn_front_semiimplicit
1212
from pySDC.implementations.sweeper_classes.generic_implicit import generic_implicit
13+
from pySDC.implementations.sweeper_classes.imex_1st_order import imex_1st_order
1314
from pySDC.playgrounds.Allen_Cahn.AllenCahn_monitor_Bayreuth import monitor
1415

1516

@@ -26,14 +27,14 @@ def setup_parameters():
2627

2728
# initialize level parameters
2829
level_params = dict()
29-
level_params['restol'] = 1E-08
30-
level_params['dt'] = 1.0 / 4
30+
level_params['restol'] = 1E-03
31+
level_params['dt'] = 16.0 / 1
3132
level_params['nsweeps'] = 1
3233

3334
# initialize sweeper parameters
3435
sweeper_params = dict()
3536
sweeper_params['collocation_class'] = CollGaussRadau_Right
36-
sweeper_params['num_nodes'] = [5]
37+
sweeper_params['num_nodes'] = [3]
3738
sweeper_params['Q1'] = ['LU']
3839
sweeper_params['Q2'] = ['LU']
3940
sweeper_params['QI'] = ['LU']
@@ -42,23 +43,23 @@ def setup_parameters():
4243

4344
# This comes as read-in for the problem class
4445
problem_params = dict()
45-
problem_params['nvars'] = 2047
46+
problem_params['nvars'] = 127
4647
problem_params['dw'] = -0.04
4748
problem_params['eps'] = 0.04
4849
problem_params['newton_maxiter'] = 100
49-
problem_params['newton_tol'] = 1E-08
50+
problem_params['newton_tol'] = 1E-04
5051
problem_params['lin_tol'] = 1E-08
5152
problem_params['lin_maxiter'] = 100
5253
problem_params['radius'] = 0.25
5354
problem_params['interval'] = (-0.5, 0.5)
5455

5556
# initialize step parameters
5657
step_params = dict()
57-
step_params['maxiter'] = 20
58+
step_params['maxiter'] = 50
5859

5960
# initialize controller parameters
6061
controller_params = dict()
61-
controller_params['logger_level'] = 30
62+
controller_params['logger_level'] = 20
6263
controller_params['hook_class'] = monitor
6364

6465
# fill description dictionary for easy step instantiation
@@ -70,6 +71,7 @@ def setup_parameters():
7071
description['level_params'] = level_params # pass level parameters
7172
description['step_params'] = step_params # pass step parameters
7273

74+
7375
return description, controller_params
7476

7577

@@ -90,21 +92,16 @@ def run_SDC_variant(variant=None, inexact=False):
9092

9193
# add stuff based on variant
9294
if variant == 'fully-implicit':
93-
# description['problem_class'] = allencahn_front
94-
description['problem_class'] = allencahn_front_finel
95+
description['problem_class'] = allencahn_front_fullyimplicit
96+
# description['problem_class'] = allencahn_front_finel
9597
description['sweeper_class'] = generic_implicit
9698
if inexact:
97-
description['problem_params']['newton_maxiter'] = 1
98-
# elif variant == 'semi-implicit':
99-
# description['problem_class'] = allencahn_semiimplicit
100-
# description['sweeper_class'] = imex_1st_order
101-
# if inexact:
102-
# description['problem_params']['lin_maxiter'] = 10
103-
# elif variant == 'semi-implicit_v2':
104-
# description['problem_class'] = allencahn_semiimplicit_v2
105-
# description['sweeper_class'] = imex_1st_order
106-
# if inexact:
107-
# description['problem_params']['newton_maxiter'] = 1
99+
description['problem_params']['newton_maxiter'] = 200
100+
elif variant == 'semi-implicit':
101+
description['problem_class'] = allencahn_front_semiimplicit
102+
description['sweeper_class'] = imex_1st_order
103+
if inexact:
104+
description['problem_params']['lin_maxiter'] = 10
108105
# elif variant == 'multi-implicit':
109106
# description['problem_class'] = allencahn_multiimplicit
110107
# description['sweeper_class'] = multi_implicit
@@ -127,7 +124,7 @@ def run_SDC_variant(variant=None, inexact=False):
127124

128125
# setup parameters "in time"
129126
t0 = 0
130-
Tend = 1.0
127+
Tend = 32.0
131128

132129
# instantiate controller
133130
controller = controller_nonMPI(num_procs=1, controller_params=controller_params, description=description)
@@ -147,8 +144,8 @@ def run_SDC_variant(variant=None, inexact=False):
147144
# call main function to get things done...
148145
uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)
149146

150-
plt_helper.plt.plot(uend.values)
151-
plt_helper.savefig('uend', save_pdf=False, save_pgf=False, save_png=True)
147+
# plt_helper.plt.plot(uend.values)
148+
# plt_helper.savefig('uend', save_pdf=False, save_pgf=False, save_png=True)
152149
# exit()
153150

154151
# filter statistics by variant (number of iterations)
@@ -320,9 +317,10 @@ def main(cwd=''):
320317
results = {}
321318
# for variant in ['multi-implicit', 'semi-implicit', 'fully-implicit', 'semi-implicit_v2', 'multi-implicit_v2']:
322319
for variant in ['fully-implicit']:
320+
# for variant in ['semi-implicit']:
323321

324-
results[(variant, 'exact')] = run_SDC_variant(variant=variant, inexact=False)
325-
# results[(variant, 'inexact')] = run_SDC_variant(variant=variant, inexact=True)
322+
# results[(variant, 'exact')] = run_SDC_variant(variant=variant, inexact=False)
323+
results[(variant, 'inexact')] = run_SDC_variant(variant=variant, inexact=True)
326324

327325
# dump result
328326
# fname = 'data/results_SDC_variants_AllenCahn_1E-03'
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import timeit
2+
import numpy as np
3+
4+
import pySDC.helpers.plot_helper as plt_helper
5+
from pySDC.helpers.stats_helper import filter_stats, sort_stats
6+
from pySDC.implementations.collocation_classes.gauss_radau_right import CollGaussRadau_Right
7+
from pySDC.implementations.controller_classes.controller_nonMPI import controller_nonMPI
8+
from pySDC.implementations.problem_classes.AllenCahn_1D_FD import allencahn_front_fullyimplicit
9+
from pySDC.implementations.sweeper_classes.generic_implicit import generic_implicit
10+
from pySDC.implementations.sweeper_classes.explicit import explicit
11+
from pySDC.playgrounds.Allen_Cahn.AllenCahn_monitor_Bayreuth import monitor
12+
13+
14+
def setup_parameters():
15+
"""
16+
Helper routine to fill in all relevant parameters
17+
18+
Note that this file will be used for all versions of SDC, containing more than necessary for each individual run
19+
20+
Returns:
21+
description (dict)
22+
controller_params (dict)
23+
"""
24+
25+
# initialize level parameters
26+
level_params = dict()
27+
level_params['restol'] = 1E-08
28+
level_params['dt'] = 1.0 / (16.0 * 128.0 ** 2)
29+
level_params['nsweeps'] = 1
30+
31+
# initialize sweeper parameters
32+
sweeper_params = dict()
33+
sweeper_params['collocation_class'] = CollGaussRadau_Right
34+
sweeper_params['num_nodes'] = [1]
35+
sweeper_params['Q1'] = ['LU']
36+
sweeper_params['Q2'] = ['LU']
37+
sweeper_params['QI'] = ['LU']
38+
sweeper_params['QE'] = ['EE']
39+
sweeper_params['spread'] = False
40+
41+
# This comes as read-in for the problem class
42+
problem_params = dict()
43+
problem_params['nvars'] = 127
44+
problem_params['dw'] = -0.04
45+
problem_params['eps'] = 0.04
46+
problem_params['newton_maxiter'] = 100
47+
problem_params['newton_tol'] = 1E-08
48+
problem_params['lin_tol'] = 1E-08
49+
problem_params['lin_maxiter'] = 100
50+
problem_params['radius'] = 0.25
51+
problem_params['interval'] = (-0.5, 0.5)
52+
53+
# initialize step parameters
54+
step_params = dict()
55+
step_params['maxiter'] = 20
56+
57+
# initialize controller parameters
58+
controller_params = dict()
59+
controller_params['logger_level'] = 30
60+
controller_params['hook_class'] = monitor
61+
62+
# fill description dictionary for easy step instantiation
63+
description = dict()
64+
description['problem_class'] = allencahn_front_fullyimplicit
65+
description['problem_params'] = problem_params # pass problem parameters
66+
description['sweeper_class'] = explicit
67+
description['sweeper_params'] = sweeper_params # pass sweeper parameters
68+
description['level_params'] = level_params # pass level parameters
69+
description['step_params'] = step_params # pass step parameters
70+
71+
return description, controller_params
72+
73+
74+
def run_SDC_variant(variant=None, inexact=False):
75+
"""
76+
Routine to run particular SDC variant
77+
78+
Args:
79+
variant (str): string describing the variant
80+
inexact (bool): flag to use inexact nonlinear solve (or nor)
81+
82+
Returns:
83+
results and statistics of the run
84+
"""
85+
86+
# load (incomplete) default parameters
87+
description, controller_params = setup_parameters()
88+
89+
# add stuff based on variant
90+
if variant == 'explicit':
91+
description['problem_class'] = allencahn_front_fullyimplicit
92+
description['sweeper_class'] = explicit
93+
else:
94+
raise NotImplemented('Wrong variant specified, got %s' % variant)
95+
96+
# setup parameters "in time"
97+
t0 = 0
98+
Tend = 1.0 / (16.0 * 128.0 ** 2)
99+
100+
# instantiate controller
101+
controller = controller_nonMPI(num_procs=1, controller_params=controller_params, description=description)
102+
103+
# get initial values on finest level
104+
P = controller.MS[0].levels[0].prob
105+
uinit = P.u_exact(t0)
106+
107+
# call main function to get things done...
108+
# uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)
109+
wrapped = wrapper(controller.run, u0=uinit, t0=t0, Tend=Tend)
110+
print(timeit.timeit(wrapped, number=10000) / 10000.0)
111+
112+
113+
def wrapper(func, *args, **kwargs):
114+
def wrapped():
115+
return func(*args, **kwargs)
116+
return wrapped
117+
118+
119+
def main(cwd=''):
120+
"""
121+
Main driver
122+
123+
Args:
124+
cwd (str): current working directory (need this for testing)
125+
"""
126+
127+
# Loop over variants, exact and inexact solves
128+
run_SDC_variant(variant='explicit')
129+
130+
131+
if __name__ == "__main__":
132+
main()

0 commit comments

Comments
 (0)