Skip to content

Commit da89af5

Browse files
authored
Merge pull request #76 from devitocodes/jakubbober-advec
Advec completed
2 parents 623ed68 + addc96a commit da89af5

File tree

104 files changed

+3829
-343
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+3829
-343
lines changed

.github/workflows/jupyter-notebooks.yml

+3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ jobs:
8282
- name: Diffusion notebooks (3.7)
8383
run: |
8484
$RUN_CMD python -m pytest -W ignore::DeprecationWarning --nbval --cov . --cov-config=.coveragerc --cov-report=xml:diffu_coverage.xml $SKIP fdm-devito-notebooks/03_diffu/diffu_rw.ipynb
85+
- name: Advection notebook (4)
86+
run: |
87+
$RUN_CMD python -m pytest -W ignore::DeprecationWarning --nbval --cov . --cov-config=.coveragerc --cov-report=xml:advec_coverage.xml $SKIP fdm-devito-notebooks/04_advec/advec.ipynb
8588
- name: Upload coverage to Codecov
8689
uses: codecov/[email protected]
8790
with:

fdm-devito-notebooks/04_advec/advec.ipynb

+301-221
Large diffs are not rendered by default.

fdm-devito-notebooks/04_advec/src-advec/advec1D.py

+114-111
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,143 @@
11
import numpy as np
22
import matplotlib.pyplot as plt
3+
from devito import Grid, Eq, solve, TimeFunction, Operator
4+
35

46
def 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

4042
def 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+
136141
def 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+
183187
def 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
277280
def 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

fdm-devito-notebooks/A_formulas/formulas.ipynb

+2-2
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@
522522
"cell_type": "markdown",
523523
"metadata": {},
524524
"source": [
525-
"### mathbb{R} exponentials\n",
525+
"### Real exponentials\n",
526526
"\n",
527527
"Let $u^n = \\exp{(\\omega n\\Delta t)} = e^{\\omega t_n}$."
528528
]
@@ -1041,7 +1041,7 @@
10411041
"name": "python",
10421042
"nbconvert_exporter": "python",
10431043
"pygments_lexer": "ipython3",
1044-
"version": "3.8.3"
1044+
"version": "3.8.2"
10451045
},
10461046
"latex_envs": {
10471047
"LaTeX_envs_menu_present": true,

fdm-jupyter-book/_toc.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818

1919
- chapter: Advection equations
2020
sections:
21-
- file: notebooks/advec/advec_placeholder.md
21+
- file: notebooks/advec/advec.ipynb
2222

2323
- chapter: Nonlinear problems
2424
sections:
25-
- file: notebooks/nonlin/nonlin_placeholder.md
25+
- file: notebooks/nonlin/nonlin_placeholder.md

0 commit comments

Comments
 (0)