11from __future__ import division
22import numpy as np
33import scipy .sparse as sp
4- import scipy .sparse .linalg as sLA
5- import scipy .linalg as LA
4+ from scipy .sparse .linalg import splu
65
76from pySDC .core .Problem import ptype
7+ from pySDC .core .Errors import ParameterError , ProblemError
88
99
10+ # noinspection PyUnusedLocal
1011class advection1d (ptype ):
1112 """
12- Example implementing the unforced 1D advection equation with periodic BC in [0,1], discretized using upwinding finite differences
13+ Example implementing the unforced 1D advection equation with periodic BC in [0,1],
14+ discretized using upwinding finite differences
1315
1416 Attributes:
1517 A: FD discretization of the gradient operator using upwinding
@@ -21,29 +23,33 @@ def __init__(self, problem_params, dtype_u, dtype_f):
2123 Initialization routine
2224
2325 Args:
24- problem_params: custom parameters for the example
26+ problem_params (dict) : custom parameters for the example
2527 dtype_u: mesh data type (will be passed parent class)
2628 dtype_f: mesh data type (will be passed parent class)
2729 """
2830
2931 # these parameters will be used later, so assert their existence
30- assert 'nvars' in problem_params , 'ERROR: need number of nvars for the problem class'
31- assert 'c' in problem_params , 'ERROR: need advection parameter for the problem class'
32- assert 'freq' in problem_params , 'ERROR: need frequency parameter for the problem class'
32+ essential_keys = ['nvars' , 'c' , 'freq' ]
33+ for key in essential_keys :
34+ if key not in problem_params :
35+ msg = 'need %s to instantiate problem, only got %s' % (key , str (problem_params .keys ()))
36+ raise ParameterError (msg )
3337
3438 # we assert that nvars looks very particular here.. this will be necessary for coarsening in space later on
35- assert (problem_params ['nvars' ])% 2 == 0 , 'ERROR: the setup requires nvars = 2^p'
39+ if (problem_params ['nvars' ]) % 2 != 0 :
40+ raise ProblemError ('setup requires nvars = 2^p' )
3641
37- if not 'order' in problem_params :
42+ if 'order' not in problem_params :
3843 problem_params ['order' ] = 1
39- if not 'type' in problem_params :
44+ if 'type' not in problem_params :
4045 problem_params ['type' ] = 'upwind'
4146
4247 # invoke super init, passing number of dofs, dtype_u and dtype_f
43- super (advection1d ,self ).__init__ (init = problem_params ['nvars' ], dtype_u = dtype_u , dtype_f = dtype_f , params = problem_params )
48+ super (advection1d , self ).__init__ (init = problem_params ['nvars' ], dtype_u = dtype_u , dtype_f = dtype_f ,
49+ params = problem_params )
4450
4551 # compute dx and get discretization matrix A
46- self .dx = 1.0 / self .params .nvars
52+ self .dx = 1.0 / self .params .nvars
4753 self .A = self .__get_A (self .params .nvars , self .params .c , self .dx , self .params .order , self .params .type )
4854
4955 @staticmethod
@@ -52,14 +58,14 @@ def __get_A(N, c, dx, order, type):
5258 Helper function to assemble FD matrix A in sparse format
5359
5460 Args:
55- N: number of dofs
56- c: diffusion coefficient
57- dx: distance between two spatial nodes
58- order: specifies order of discretization
59- type: upwind or centered differences
61+ N (int) : number of dofs
62+ c (float) : diffusion coefficient
63+ dx (float) : distance between two spatial nodes
64+ order (int) : specifies order of discretization
65+ type (string) : upwind or centered differences
6066
6167 Returns:
62- matrix A in CSC format
68+ scipy.sparse.csc_matrix: matrix A in CSC format
6369 """
6470
6571 coeff = None
@@ -81,8 +87,7 @@ def __get_A(N, c, dx, order, type):
8187 zero_pos = 4
8288 coeff = 1.0 / 60.0
8389 else :
84- print ("Order " + order + " not implemented." )
85- exit ()
90+ raise ProblemError ("Order " + str (order ) + " not implemented." )
8691
8792 else :
8893
@@ -111,66 +116,65 @@ def __get_A(N, c, dx, order, type):
111116 coeff = 1.0 / 60.0
112117 zero_pos = 5
113118 else :
114- print ("Order " + order + " not implemented." )
115- exit ()
119+ raise ProblemError ("Order " + str (order ) + " not implemented." )
116120
117- dstencil = np .concatenate ((stencil , np .delete (stencil ,zero_pos - 1 )))
118- offsets = np .concatenate (([N - i - 1 for i in reversed (range (zero_pos - 1 ))],[i - zero_pos + 1 for i in range (zero_pos - 1 ,len (stencil ))]))
119- doffsets = np .concatenate ((offsets , np .delete (offsets ,zero_pos - 1 )- N ))
121+ dstencil = np .concatenate ((stencil , np .delete (stencil , zero_pos - 1 )))
122+ offsets = np .concatenate (([N - i - 1 for i in reversed (range (zero_pos - 1 ))],
123+ [i - zero_pos + 1 for i in range (zero_pos - 1 , len (stencil ))]))
124+ doffsets = np .concatenate ((offsets , np .delete (offsets , zero_pos - 1 ) - N ))
120125
121- A = c * coeff * (1.0 / dx ) * sp .diags (dstencil ,doffsets ,shape = (N ,N ),format = 'csc' )
126+ A = sp .diags (dstencil , doffsets , shape = (N , N ), format = 'csc' )
127+ A *= c * coeff * (1.0 / dx )
122128
123129 return A
124130
125-
126- def eval_f (self ,u ,t ):
131+ def eval_f (self , u , t ):
127132 """
128133 Routine to evaluate the RHS
129134
130135 Args:
131- u: current values
132- t: current time
136+ u (dtype_u) : current values
137+ t (float) : current time
133138
134139 Returns:
135- the RHS
140+ dtype_f: the RHS
136141 """
137142
138143 f = self .dtype_f (self .init )
139- f .values = - self .A .dot (u .values )
144+ f .values = - 1.0 * self .A .dot (u .values )
140145 return f
141146
142- def solve_system (self ,rhs ,factor ,u0 ,t ):
147+ def solve_system (self , rhs , factor , u0 , t ):
143148 """
144- Simple linear solver for (I- factor*A)u = rhs
149+ Simple linear solver for (I+ factor*A)u = rhs
145150
146151 Args:
147- rhs: right-hand side for the linear system
148- factor: abbrev. for the node-to-node stepsize (or any other factor required)
149- u0: initial guess for the iterative solver (not used here so far)
150- t: current time (e.g. for time-dependent BCs)
152+ rhs (dtype_f) : right-hand side for the linear system
153+ factor (float) : abbrev. for the node-to-node stepsize (or any other factor required)
154+ u0 (dtype_u) : initial guess for the iterative solver (not used here so far)
155+ t (float) : current time (e.g. for time-dependent BCs)
151156
152157 Returns:
153- solution as mesh
158+ dtype_u: solution as mesh
154159 """
155160
156161 me = self .dtype_u (self .init )
157- me .values = sLA .spsolve (sp .eye (self .params .nvars )+ factor * self .A ,rhs .values )
162+ L = splu (sp .eye (self .params .nvars , format = 'csc' ) + factor * self .A )
163+ me .values = L .solve (rhs .values )
158164 return me
159165
160- def u_exact (self ,t ):
166+ def u_exact (self , t ):
161167 """
162168 Routine to compute the exact solution at time t
163169
164170 Args:
165- t: current time
171+ t (float) : current time
166172
167173 Returns:
168- exact solution
174+ dtype_u: exact solution
169175 """
170176
171177 me = self .dtype_u (self .init )
172- xvalues = np .array ([i * self .dx for i in range (self .params .nvars )])
173- me .values = np .sin (np .pi * self .params .freq * (xvalues - self .params .c * t ))
178+ xvalues = np .array ([i * self .dx for i in range (self .params .nvars )])
179+ me .values = np .sin (np .pi * self .params .freq * (xvalues - self .params .c * t ))
174180 return me
175-
176-
0 commit comments