download
raw
4.25 kB
#!/usr/bin/env python
# As wave1D_dn0.py, but using ghost cells and index sets.
"""
1D wave equation with homogeneous Neumann conditions::
u, x, t, cpu = solver(I, V, f, c, L, dt, C, T, user_action)
Function solver solves the wave equation
u_tt = c**2*u_xx + f(x,t) on
(0,L) with du/dn=0 on x=0 and x = L.
dt is the time step.
T is the stop time for the simulation.
C is the Courant number (=c*dt/dx).
dx is computed from dt and C.
I and f are functions: I(x), f(x,t).
user_action is a function of (u, x, t, n) where the calling code
can add visualization, error computations, data analysis,
store solutions, etc.
Function viz::
viz(I, V, f, c, L, dt, C, T, umin, umax, animate=True)
calls solver with a user_action function that can plot the
solution on the screen (as an animation).
"""
import numpy as np
def solver(I, V, f, c, L, dt, C, T, user_action=None):
"""
Solve u_tt=c^2*u_xx + f on (0,L)x(0,T].
u(0,t)=U_0(t) or du/dn=0 (U_0=None),
u(L,t)=U_L(t) or du/dn=0 (u_L=None).
"""
Nt = int(round(T/dt))
t = np.linspace(0, Nt*dt, Nt+1) # Mesh points in time
dx = dt*c/float(C)
Nx = int(round(L/dx))
x = np.linspace(0, L, Nx+1) # Mesh points in space
C2 = C**2; dt2 = dt*dt # Help variables in the scheme
# Wrap user-given f, V
if f is None or f == 0:
f = (lambda x, t: 0)
if V is None or V == 0:
V = (lambda x: 0)
u = np.zeros(Nx+3) # Solution array at new time level
u_1 = np.zeros(Nx+3) # Solution at 1 time level back
u_2 = np.zeros(Nx+3) # Solution at 2 time levels back
Ix = range(1, u.shape[0]-1)
It = range(0, t.shape[0])
import time; t0 = time.clock() # for measuring CPU time
# Load initial condition into u_1
for i in Ix:
u_1[i] = I(x[i-Ix[0]]) # Note the index transformation in x
# Ghost values set according to du/dx=0
i = Ix[0]
u_1[i-1] = u_1[i+1]
i = Ix[-1]
u_1[i+1] = u_1[i-1]
if user_action is not None:
# Make sure to send the part of u that corresponds to x
user_action(u_1[Ix[0]:Ix[-1]+1], x, t, 0)
# Special formula for the first step
for i in Ix:
u[i] = u_1[i] + dt*V(x[i-Ix[0]]) + \
0.5*C2*(u_1[i-1] - 2*u_1[i] + u_1[i+1]) + \
0.5*dt2*f(x[i-Ix[0]], t[0])
# Ghost values set according to du/dx=0
i = Ix[0]
u[i-1] = u[i+1]
i = Ix[-1]
u[i+1] = u[i-1]
if user_action is not None:
# Make sure to send the part of u that corresponds to x
user_action(u[Ix[0]:Ix[-1]+1], x, t, 1)
# Update data structures for next step
#u_2[:] = u_1; u_1[:] = u # safe, but slower
u_2, u_1, u = u_1, u, u_2
for n in range(1, Nt):
for i in Ix:
u[i] = - u_2[i] + 2*u_1[i] + \
C2*(u_1[i-1] - 2*u_1[i] + u_1[i+1]) + \
dt2*f(x[i-Ix[0]], t[n])
# Ghost values set according to du/dx=0
i = Ix[0]
u[i-1] = u[i+1]
i = Ix[-1]
u[i+1] = u[i-1]
if user_action is not None:
# Make sure to send the part of u that corresponds to x
if user_action(u[Ix[0]:Ix[-1]+1], x, t, n+1):
break
# Update data structures for next step
#u_2[:] = u_1; u_1[:] = u # safe, but slower
u_2, u_1, u = u_1, u, u_2
# Important to correct the mathematically wrong u=u_2 above
# before returning u
u = u_1
cpu_time = t0 - time.clock()
return u[1:-1], x, t, cpu_time
from wave1D_u0 import viz
from wave1D_n0 import plug
# Cannot just import test_plug because wave1D_n0.test_plug will
# then call wave1D.solver, not the solver above
def test_plug():
"""
Check that an initial plug is correct back after one period,
if C=1.
"""
L = 1.0
I = lambda x: 0 if abs(x-L/2.0) > 0.1 else 1
Nx = 10
c = 0.5
C = 1
dt = C*(L/Nx)/c
nperiods = 4
T = L/c*nperiods # One period: c*T = L
u, x, t, cpu = solver(
I=I, V=None, f=None, c=c, L=L,
dt=dt, C=C, T=T, user_action=None)
u_0 = np.array([I(x_) for x_ in x])
diff = np.abs(u - u_0).max()
tol = 1E-13
assert diff < tol
if __name__ == '__main__':
test_plug()

Xet Storage Details

Size:
4.25 kB
·
Xet hash:
31b74a074480c189cfa5a353b8615c82e7a99160d57a652abee5c15b50c03c72

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.