11import numpy as np
22import matplotlib .pyplot as plt
3+ from devito import Grid , Eq , solve , TimeFunction , Operator
4+
35
46def solver_FECS (I , U0 , v , L , dt , C , T , user_action = None ):
57 Nt = int (round (T / float (dt )))
6- t = np .linspace (0 , Nt * dt , Nt + 1 ) # Mesh points in time
8+ t = np .linspace (0 , Nt * dt , Nt + 1 ) # Mesh points in time
79 dx = v * dt / C
810 Nx = int (round (L / dx ))
9- x = np .linspace (0 , L , Nx + 1 ) # Mesh points in space
11+ x = np .linspace (0 , L , Nx + 1 ) # Mesh points in space
12+
1013 # Make sure dx and dt are compatible with x and t
11- dx = x [1 ] - x [0 ]
12- dt = t [1 ] - t [0 ]
14+ dx = float ( x [1 ] - x [0 ])
15+ dt = float ( t [1 ] - t [0 ])
1316 C = v * dt / dx
1417
15- u = np . zeros ( Nx + 1 )
16- u_n = np . zeros ( Nx + 1 )
18+ grid = Grid ( shape = ( Nx + 1 ,), extent = ( L ,) )
19+ t_s = grid . time_dim
1720
18- # Set initial condition u(x,0) = I(x)
19- for i in range (0 , Nx + 1 ):
20- u_n [i ] = I (x [i ])
21+ u = TimeFunction (name = 'u' , grid = grid , space_order = 2 , save = Nt + 1 )
2122
23+ pde = u .dtr + v * u .dxc
24+
25+ stencil = solve (pde , u .forward )
26+ eq = Eq (u .forward , stencil )
27+
28+ # Set initial condition u(x,0) = I(x)
29+ u .data [1 , :] = [I (xi ) for xi in x ]
30+
31+ # Insert boundary condition
32+ bc = [Eq (u [t_s + 1 , 0 ], U0 )]
33+
34+ op = Operator ([eq ] + bc )
35+ op .apply (dt = dt , x_m = 1 , x_M = Nx - 1 )
36+
2237 if user_action is not None :
23- user_action (u_n , x , t , 0 )
24-
25- for n in range (0 , Nt ):
26- # Compute u at inner mesh points
27- for i in range (1 , Nx ):
28- u [i ] = u_n [i ] - 0.5 * C * (u_n [i + 1 ] - u_n [i - 1 ])
29-
30- # Insert boundary condition
31- u [0 ] = U0
32-
33- if user_action is not None :
34- user_action (u , x , t , n + 1 )
35-
36- # Switch variables before next step
37- u_n , u = u , u_n
38+ for n in range (0 , Nt + 1 ):
39+ user_action (u .data [n ], x , t , n )
3840
3941
4042def solver (I , U0 , v , L , dt , C , T , user_action = None ,
4143 scheme = 'FE' , periodic_bc = True ):
42- Nt = int (round (T / float (dt )))
44+ Nt = int (round (T / np . float64 (dt )))
4345 t = np .linspace (0 , Nt * dt , Nt + 1 ) # Mesh points in time
4446 dx = v * dt / C
4547 Nx = int (round (L / dx ))
4648 x = np .linspace (0 , L , Nx + 1 ) # Mesh points in space
49+
4750 # Make sure dx and dt are compatible with x and t
4851 dx = x [1 ] - x [0 ]
4952 dt = t [1 ] - t [0 ]
5053 C = v * dt / dx
51- print 'dt=%g, dx=%g, Nx=%d, C=%g' % (dt , dx , Nx , C )
54+ print ( 'dt=%g, dx=%g, Nx=%d, C=%g' % (dt , dx , Nx , C ) )
5255
53- u = np .zeros (Nx + 1 )
54- u_n = np .zeros (Nx + 1 )
55- u_nm1 = np .zeros (Nx + 1 )
5656 integral = np .zeros (Nt + 1 )
57+
58+ grid = Grid (shape = (Nx + 1 ,), extent = (L ,), dtype = np .float64 )
59+
60+ t_s = grid .time_dim
61+
62+ def u (to = 1 , so = 1 ):
63+ u = TimeFunction (name = 'u' , grid = grid , time_order = to , space_order = so , save = Nt + 1 )
64+ return u
65+
66+ if scheme == 'FE' :
67+ u = u (so = 2 )
68+ pde = u .dtr + v * u .dxc
69+
70+ pbc = [Eq (u [t_s + 1 , 0 ], u [t_s , 0 ] - 0.5 * C * (u [t_s , 1 ] - u [t_s , Nx ]))]
71+ pbc += [Eq (u [t_s + 1 , Nx ], u [t_s + 1 , 0 ])]
72+
73+ elif scheme == 'LF' :
74+ # Use UP scheme for the first timestep
75+ u = u (to = 2 , so = 2 )
76+ pde0 = u .dtr (fd_order = 1 ) + v * u .dxl (fd_order = 1 )
77+
78+ stencil0 = solve (pde0 , u .forward )
79+ eq0 = Eq (u .forward , stencil0 ).subs (t_s , 0 )
80+
81+ pbc0 = [Eq (u [t_s , 0 ], u [t_s , Nx ]).subs (t_s , 0 )]
82+
83+ # Now continue with LF scheme
84+ pde = u .dtc + v * u .dxc
85+
86+ pbc = [Eq (u [t_s + 1 , 0 ], u [t_s - 1 , 0 ] - C * (u [t_s , 1 ] - u [t_s , Nx - 1 ]))]
87+ pbc += [Eq (u [t_s + 1 , Nx ], u [t_s + 1 , 0 ])]
88+
89+ elif scheme == 'UP' :
90+ u = u ()
91+ pde = u .dtr + v * u .dxl
92+
93+ pbc = [Eq (u [t_s , 0 ], u [t_s , Nx ])]
94+
95+ elif scheme == 'LW' :
96+ u = u (so = 2 )
97+ pde = u .dtr + v * u .dxc - 0.5 * dt * v ** 2 * u .dx2
98+
99+ pbc = [Eq (u [t_s + 1 , 0 ], u [t_s , 0 ] - 0.5 * C * (u [t_s , 1 ] - u [t_s , Nx - 1 ]) + \
100+ 0.5 * C ** 2 * (u [t_s , 1 ] - 2 * u [t_s , 0 ] + u [t_s , Nx - 1 ]))]
101+ pbc += [Eq (u [t_s + 1 , Nx ], u [t_s + 1 , 0 ])]
102+
103+ else :
104+ raise ValueError ('scheme="%s" not implemented' % scheme )
57105
106+ stencil = solve (pde , u .forward )
107+ eq = Eq (u .forward , stencil )
108+
109+ bc_init = [Eq (u [t_s + 1 , 0 ], U0 ).subs (t_s , 0 )]
110+
58111 # Set initial condition u(x,0) = I(x)
59- for i in range (0 , Nx + 1 ):
60- u_n [i ] = I (x [i ])
61-
62- # Insert boundary condition
63- u [0 ] = U0
64-
112+ u .data [0 , :] = [I (xi ) for xi in x ]
113+
65114 # Compute the integral under the curve
66- integral [0 ] = dx * (0.5 * u_n [0 ] + 0.5 * u_n [ Nx ] + np .sum (u_n [ 1 : - 1 ]))
67-
115+ integral [0 ] = dx * (0.5 * u . data [0 ][ 0 ] + 0.5 * u . data [ 0 ][ Nx ] + np .sum (u . data [ 0 ][ 1 : Nx ]))
116+
68117 if user_action is not None :
69- user_action (u_n , x , t , 0 )
70-
71- for n in range (0 , Nt ):
72- if scheme == 'FE' :
73- if periodic_bc :
74- i = 0
75- u [i ] = u_n [i ] - 0.5 * C * (u_n [i + 1 ] - u_n [Nx ])
76- u [Nx ] = u [0 ]
77- #u[i] = u_n[i] - 0.5*C*(u_n[1] - u_n[Nx])
78- for i in range (1 , Nx ):
79- u [i ] = u_n [i ] - 0.5 * C * (u_n [i + 1 ] - u_n [i - 1 ])
80- elif scheme == 'LF' :
81- if n == 0 :
82- # Use upwind for first step
83- if periodic_bc :
84- i = 0
85- #u[i] = u_n[i] - C*(u_n[i] - u_n[Nx-1])
86- u_n [i ] = u_n [Nx ]
87- for i in range (1 , Nx + 1 ):
88- u [i ] = u_n [i ] - C * (u_n [i ] - u_n [i - 1 ])
89- else :
90- if periodic_bc :
91- i = 0
92- # Must have this,
93- u [i ] = u_nm1 [i ] - C * (u_n [i + 1 ] - u_n [Nx - 1 ])
94- # not this:
95- #u_n[i] = u_n[Nx]
96- for i in range (1 , Nx ):
97- u [i ] = u_nm1 [i ] - C * (u_n [i + 1 ] - u_n [i - 1 ])
98- if periodic_bc :
99- u [Nx ] = u [0 ]
100- elif scheme == 'UP' :
101- if periodic_bc :
102- u_n [0 ] = u_n [Nx ]
103- for i in range (1 , Nx + 1 ):
104- u [i ] = u_n [i ] - C * (u_n [i ] - u_n [i - 1 ])
105- elif scheme == 'LW' :
106- if periodic_bc :
107- i = 0
108- # Must have this,
109- u [i ] = u_n [i ] - 0.5 * C * (u_n [i + 1 ] - u_n [Nx - 1 ]) + \
110- 0.5 * C * (u_n [i + 1 ] - 2 * u_n [i ] + u_n [Nx - 1 ])
111- # not this:
112- #u_n[i] = u_n[Nx]
113- for i in range (1 , Nx ):
114- u [i ] = u_n [i ] - 0.5 * C * (u_n [i + 1 ] - u_n [i - 1 ]) + \
115- 0.5 * C * (u_n [i + 1 ] - 2 * u_n [i ] + u_n [i - 1 ])
116- if periodic_bc :
117- u [Nx ] = u [0 ]
118- else :
119- raise ValueError ('scheme="%s" not implemented' % scheme )
120-
121- if not periodic_bc :
122- # Insert boundary condition
123- u [0 ] = U0
124-
118+ user_action (u .data [0 ], x , t , 0 )
119+
120+ bc = [Eq (u [t_s + 1 , 0 ], U0 )]
121+
122+ if scheme == 'LF' :
123+ op = Operator ((pbc0 if periodic_bc else []) + [eq0 ] + (bc_init if not periodic_bc else []) \
124+ + (pbc if periodic_bc else []) + [eq ] + (bc if not periodic_bc else []))
125+ else :
126+ op = Operator (bc_init + (pbc if periodic_bc else []) + [eq ] + (bc if not periodic_bc else []))
127+
128+ op .apply (dt = dt , x_m = 1 , x_M = Nx if scheme == 'UP' else Nx - 1 )
129+
130+ for n in range (1 , Nt + 1 ):
125131 # Compute the integral under the curve
126- integral [n + 1 ] = dx * (0.5 * u [ 0 ] + 0.5 * u [ Nx ] + np .sum (u [ 1 : - 1 ]))
132+ integral [n ] = dx * (0.5 * u . data [ n ][ 0 ] + 0.5 * u . data [ n ][ Nx ] + np .sum (u . data [ n ][ 1 : Nx ]))
127133
128134 if user_action is not None :
129- user_action (u , x , t , n + 1 )
135+ user_action (u . data [ n ] , x , t , n )
130136
131- # Switch variables before next step
132- u_nm1 , u_n , u = u_n , u , u_nm1
133- print 'I:' , integral [n + 1 ]
137+ print ('I:' , integral [n ])
134138 return integral
135139
140+
136141def run_FECS (case ):
137142 """Special function for the FECS case."""
138143 if case == 'gaussian' :
@@ -159,14 +164,12 @@ def plot(u, x, t, n):
159164 m = 40
160165 if n % m != 0 :
161166 return
162- print 't=%g, n=%d, u in [%g, %g] w/%d points' % \
163- (t [n ], n , u .min (), u .max (), x .size )
167+ print ( 't=%g, n=%d, u in [%g, %g] w/%d points' % \
168+ (t [n ], n , u .min (), u .max (), x .size ))
164169 if np .abs (u ).max () > 3 : # Instability?
165170 return
166171 plt .plot (x , u )
167172 legends .append ('t=%g' % t [n ])
168- if n > 0 :
169- plt .hold ('on' )
170173
171174 plt .ion ()
172175 U0 = 0
@@ -180,6 +183,7 @@ def plot(u, x, t, n):
180183 plt .axis ([0 , L , - 0.75 , 1.1 ])
181184 plt .show ()
182185
186+
183187def run (scheme = 'UP' , case = 'gaussian' , C = 1 , dt = 0.01 ):
184188 """General admin routine for explicit and implicit solvers."""
185189
@@ -203,7 +207,6 @@ def plot(u, x, t, n):
203207 lines = plt .plot (x , u )
204208 plt .axis ([x [0 ], x [- 1 ], - 0.5 , 1.5 ])
205209 plt .xlabel ('x' ); plt .ylabel ('u' )
206- plt .axes ().set_aspect (0.15 )
207210 plt .savefig ('tmp_%04d.png' % n )
208211 plt .savefig ('tmp_%04d.pdf' % n )
209212 else :
@@ -219,12 +222,11 @@ def plot(u, x, t, n):
219222 eps = 1E-14
220223 if abs (t [n ] - 0.6 ) > eps and abs (t [n ] - 0 ) > eps :
221224 return
222- print 't=%g, n=%d, u in [%g, %g] w/%d points' % \
223- (t [n ], n , u .min (), u .max (), x .size )
225+ print ( 't=%g, n=%d, u in [%g, %g] w/%d points' % \
226+ (t [n ], n , u .min (), u .max (), x .size ))
224227 if np .abs (u ).max () > 3 : # Instability?
225228 return
226229 plt .plot (x , u )
227- plt .hold ('on' )
228230 plt .draw ()
229231 if n > 0 :
230232 y = [I (x_ - v * t [n ]) for x_ in x ]
@@ -264,16 +266,17 @@ def plot(u, x, t, n):
264266 plt .figure (2 )
265267 plt .axis ([0 , L , - 0.5 , 1.1 ])
266268 plt .xlabel ('$x$' ); plt .ylabel ('$u$' )
267- plt .axes ().set_aspect (0.5 ) # no effect
268269 plt .savefig ('tmp1.png' ); plt .savefig ('tmp1.pdf' )
269270 plt .show ()
270271 # Make videos from figure(1) animation files
271272 for codec in codecs :
272273 cmd = 'ffmpeg -i tmp_%%04d.png -r 25 -vcodec %s movie.%s' % \
273274 (codecs [codec ], codec )
274275 os .system (cmd )
275- print 'Integral of u:' , integral .max (), integral .min ()
276+ print ('Integral of u:' , integral .max (), integral .min ())
277+
276278
279+ # TODO: IMPLEMENT THIS IN DEVITO
277280def solver_theta (I , v , L , dt , C , T , theta = 0.5 , user_action = None , FE = False ):
278281 """
279282 Full solver for the model problem using the theta-rule
@@ -282,7 +285,7 @@ def solver_theta(I, v, L, dt, C, T, theta=0.5, user_action=None, FE=False):
282285 Vectorized implementation and sparse (tridiagonal)
283286 coefficient matrix.
284287 """
285- import time ; t0 = time .clock () # for measuring the CPU time
288+ import time ; t0 = time .process_time () # for measuring the CPU time
286289 Nt = int (round (T / float (dt )))
287290 t = np .linspace (0 , Nt * dt , Nt + 1 ) # Mesh points in time
288291 dx = v * dt / C
@@ -292,7 +295,7 @@ def solver_theta(I, v, L, dt, C, T, theta=0.5, user_action=None, FE=False):
292295 dx = x [1 ] - x [0 ]
293296 dt = t [1 ] - t [0 ]
294297 C = v * dt / dx
295- print 'dt=%g, dx=%g, Nx=%d, C=%g' % (dt , dx , Nx , C )
298+ print ( 'dt=%g, dx=%g, Nx=%d, C=%g' % (dt , dx , Nx , C ) )
296299
297300 u = np .zeros (Nx + 1 )
298301 u_n = np .zeros (Nx + 1 )
@@ -354,7 +357,7 @@ def solver_theta(I, v, L, dt, C, T, theta=0.5, user_action=None, FE=False):
354357 # Update u_n before next step
355358 u_n , u = u , u_n
356359
357- t1 = time .clock ()
360+ t1 = time .process_time ()
358361 return integral
359362
360363
0 commit comments