1
1
import numpy as np
2
2
import matplotlib .pyplot as plt
3
+ from devito import Grid , Eq , solve , TimeFunction , Operator
4
+
3
5
4
6
def solver_FECS (I , U0 , v , L , dt , C , T , user_action = None ):
5
7
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
7
9
dx = v * dt / C
8
10
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
+
10
13
# 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 ])
13
16
C = v * dt / dx
14
17
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
17
20
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 )
21
22
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
+
22
37
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 )
38
40
39
41
40
42
def solver (I , U0 , v , L , dt , C , T , user_action = None ,
41
43
scheme = 'FE' , periodic_bc = True ):
42
- Nt = int (round (T / float (dt )))
44
+ Nt = int (round (T / np . float64 (dt )))
43
45
t = np .linspace (0 , Nt * dt , Nt + 1 ) # Mesh points in time
44
46
dx = v * dt / C
45
47
Nx = int (round (L / dx ))
46
48
x = np .linspace (0 , L , Nx + 1 ) # Mesh points in space
49
+
47
50
# Make sure dx and dt are compatible with x and t
48
51
dx = x [1 ] - x [0 ]
49
52
dt = t [1 ] - t [0 ]
50
53
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 ) )
52
55
53
- u = np .zeros (Nx + 1 )
54
- u_n = np .zeros (Nx + 1 )
55
- u_nm1 = np .zeros (Nx + 1 )
56
56
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 )
57
105
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
+
58
111
# 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
+
65
114
# 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
+
68
117
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 ):
125
131
# 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 ]))
127
133
128
134
if user_action is not None :
129
- user_action (u , x , t , n + 1 )
135
+ user_action (u . data [ n ] , x , t , n )
130
136
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 ])
134
138
return integral
135
139
140
+
136
141
def run_FECS (case ):
137
142
"""Special function for the FECS case."""
138
143
if case == 'gaussian' :
@@ -159,14 +164,12 @@ def plot(u, x, t, n):
159
164
m = 40
160
165
if n % m != 0 :
161
166
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 ))
164
169
if np .abs (u ).max () > 3 : # Instability?
165
170
return
166
171
plt .plot (x , u )
167
172
legends .append ('t=%g' % t [n ])
168
- if n > 0 :
169
- plt .hold ('on' )
170
173
171
174
plt .ion ()
172
175
U0 = 0
@@ -180,6 +183,7 @@ def plot(u, x, t, n):
180
183
plt .axis ([0 , L , - 0.75 , 1.1 ])
181
184
plt .show ()
182
185
186
+
183
187
def run (scheme = 'UP' , case = 'gaussian' , C = 1 , dt = 0.01 ):
184
188
"""General admin routine for explicit and implicit solvers."""
185
189
@@ -203,7 +207,6 @@ def plot(u, x, t, n):
203
207
lines = plt .plot (x , u )
204
208
plt .axis ([x [0 ], x [- 1 ], - 0.5 , 1.5 ])
205
209
plt .xlabel ('x' ); plt .ylabel ('u' )
206
- plt .axes ().set_aspect (0.15 )
207
210
plt .savefig ('tmp_%04d.png' % n )
208
211
plt .savefig ('tmp_%04d.pdf' % n )
209
212
else :
@@ -219,12 +222,11 @@ def plot(u, x, t, n):
219
222
eps = 1E-14
220
223
if abs (t [n ] - 0.6 ) > eps and abs (t [n ] - 0 ) > eps :
221
224
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 ))
224
227
if np .abs (u ).max () > 3 : # Instability?
225
228
return
226
229
plt .plot (x , u )
227
- plt .hold ('on' )
228
230
plt .draw ()
229
231
if n > 0 :
230
232
y = [I (x_ - v * t [n ]) for x_ in x ]
@@ -264,16 +266,17 @@ def plot(u, x, t, n):
264
266
plt .figure (2 )
265
267
plt .axis ([0 , L , - 0.5 , 1.1 ])
266
268
plt .xlabel ('$x$' ); plt .ylabel ('$u$' )
267
- plt .axes ().set_aspect (0.5 ) # no effect
268
269
plt .savefig ('tmp1.png' ); plt .savefig ('tmp1.pdf' )
269
270
plt .show ()
270
271
# Make videos from figure(1) animation files
271
272
for codec in codecs :
272
273
cmd = 'ffmpeg -i tmp_%%04d.png -r 25 -vcodec %s movie.%s' % \
273
274
(codecs [codec ], codec )
274
275
os .system (cmd )
275
- print 'Integral of u:' , integral .max (), integral .min ()
276
+ print ('Integral of u:' , integral .max (), integral .min ())
277
+
276
278
279
+ # TODO: IMPLEMENT THIS IN DEVITO
277
280
def solver_theta (I , v , L , dt , C , T , theta = 0.5 , user_action = None , FE = False ):
278
281
"""
279
282
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):
282
285
Vectorized implementation and sparse (tridiagonal)
283
286
coefficient matrix.
284
287
"""
285
- import time ; t0 = time .clock () # for measuring the CPU time
288
+ import time ; t0 = time .process_time () # for measuring the CPU time
286
289
Nt = int (round (T / float (dt )))
287
290
t = np .linspace (0 , Nt * dt , Nt + 1 ) # Mesh points in time
288
291
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):
292
295
dx = x [1 ] - x [0 ]
293
296
dt = t [1 ] - t [0 ]
294
297
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 ) )
296
299
297
300
u = np .zeros (Nx + 1 )
298
301
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):
354
357
# Update u_n before next step
355
358
u_n , u = u , u_n
356
359
357
- t1 = time .clock ()
360
+ t1 = time .process_time ()
358
361
return integral
359
362
360
363
0 commit comments