This demo example shows ...
In [25]:
%pylab inline
In [26]:
import numpy as np
import time
import matplotlib.pyplot as plt
from IPython.display import clear_output
from mpl_toolkits.mplot3d.axes3d import Axes3D
First, define some constants we need
In [27]:
# Number of grid cells in each direction of the grid
m = 21
n = 21
# Grid spacing
dx = 10/float(m)
dy = 10/float(n)
# The grid itself
Q = np.zeros((3, n, m))
Q[0, :, :] = 1.0
Q[0, n/2, m/2] = 3.0
# Gravitational constant
g = 9.80665
Vi ønsker å løse grundtvannslikningen eksplisitt
Grundtvannslikningene kan skrives
\begin{aligned} \left[ \begin{array}{c} h\\\ hu\\\ hv \end{array} \right]_t + \left[ \begin{array}{c} hu\\\ hu^2 + \tfrac{1}{2}gh^2\\\ huv \end{array} \right]_x + \left[ \begin{array}{c} hv\\\ huv\\\ hv^2 + \tfrac{1}{2}gh^2 \end{array} \right]_y = \left[ \begin{array}{c} 0\\\ 0\\\ 0 \end{array} \right]. \end{aligned}Her er $h$ vannhøyden, $hu$ fluxen langs x-aksen, og $hv$ fluxen langs y-aksen. Vi kan skrive det mer kompakt på vektor form som
$Q_t + F(Q)_x + G(Q)_y = 0$
Og diskretisere ved å beregne fluxen inn og ut av hver celle:
$$ Q_t = - \frac{ F\_{i+1/2}(Q) - F\_{i-1/2}(Q) }{ \Delta x } - \frac{ G\_{j+1/2}(Q) - G\_{j-1/2}(Q) }{ \Delta y } $$Vi kan approksimere $F(Q)$ ved integrasjonspunktet mellom to celler med hjelp av central-upwind fluks funksjonen
\begin{aligned} F_{j+1/2}(Q^k) = \frac{ a^+\_{j+1/2} F(Q^{k-}\_{j+1/2}) - a^-\_{j+1/2} F(Q^{k+}\_{j+1/2}) }{ a^+\_{j+1/2} - a^-\_{j+1/2} } + \frac{ a^+\_{j+1/2} a^-\_{j+1/2} }{ a^+\_{j+1/2} - a^-\_{j+1/2} } \left( Q^{k+}\_{j+1/2}-Q^{k-}\_{j+1/2} \right) \end{aligned}Her er + brukt for å vise at verdien tas fra høyre side av interfacet, og - for å vise at den tas fra venstre side av interfacet, og $a$ er største/minste egenverdi for integrasjonspunktet (tilsvarer største bølgehastighet)
In [28]:
#Central upwind flux function
def CU(Fl, Ql , Fr, Qr, ap, am):
return (ap*Fr - am*Fl) / (ap-am) + (ap*am)/(ap-am)*(Qr-Ql)
#Find the discrete F-flux at an integration point
def F(Ql, Qr):
#Find the maximum / minimum local wave speeds
cl = sqrt(g*Ql[0])
cr = sqrt(g*Qr[0])
ul = Ql[1]/Ql[0]
ur = Qr[1]/Qr[0]
am = min(min(ul-cl, ur-cr), 0.0)
ap = max(max(ul+cl, ur+cr), 0.0)
#Define the local helper function Fh
def Fh(Q):
return np.array([
Q[1],
Q[1]*Q[1]/Q[0] + 0.5*g*Q[0]*Q[0],
Q[1]*Q[2]/Q[0]
])
Fl = Fh(Ql)
Fr = Fh(Qr)
return CU(Fl, Ql, Fr, Qr, ap, am)
#Find the discrete G-flux at an integration point
def G(Ql, Qr):
#Find the maximum / minimum local wave speeds
cl = sqrt(g*Ql[0])
cr = sqrt(g*Qr[0])
vl = Ql[2]/Ql[0]
vr = Qr[2]/Qr[0]
am = min(min(vl-cl, vr-cr), 0.0)
ap = max(max(vl+cl, vr+cr), 0.0)
#Define the local helper function Gh
def Gh(Q):
return np.array([
Q[2],
Q[1]*Q[2]/Q[0],
Q[2]*Q[2]/Q[0] + 0.5*g*Q[0]*Q[0]
])
Gl = Gh(Ql)
Gr = Gh(Qr)
return CU(Gl, Ql, Gr, Qr, ap, am)
Vi beregner fluxen inn og ut av hver celle som følger
$$ Q^{k+1} = Q^k + \Delta t \left(\frac{F_{j-1/2}(Q^k) - F_{j+1/2}(Q^k)}{\Delta x} + \frac{G_{j-1/2}(Q^k) - G_{j+1/2}(Q^k)}{\Delta y} \right) = Q^k + \Delta t \cdot R(Q^k) $$
In [29]:
fig, ax = plt.subplots()
dt = 0.05
#Perform timestepping
for i in range(0, 100):
f_flux = np.zeros((3, n, m-1))
g_flux = np.zeros((3, n-1, m))
# Loop over all intefaces and create the flux
for k in range(n):
for l in range(m-1):
f_flux[:, k, l] = F(Q[:, k, l], Q[:, k, l+1])
for k in range(n-1):
for l in range(m):
g_flux[:, k, l] = G(Q[:, k, l], Q[:, k+1, l])
# Loop over all internal cells and sum fluxes
for k in range(1, n-1):
for l in range(1, m-1):
Q[:, k, l] = Q[:, k, l] + dt * ( (f_flux[:, k, l-1] - f_flux[:, k, l])/dx + (g_flux[:, k-1, l] - g_flux[:, k, l])/dy )
#Boundary conditions (wall)
Q[:, :, 0] = Q[:, :, 1]
Q[:, :, -1] = Q[:, :, -2]
Q[1, :, 0] = -Q[1, :, 0]
Q[1, :, -1] = -Q[1, :, -1]
Q[:, 0, :] = Q[:, 1, :]
Q[:, -1, :] = Q[:, -2, :]
Q[2, 0, :] = -Q[2, 0, :]
Q[2, -1, :] = -Q[2, -1, :]
if (i % 10 == 0):
#clear_output()
ax.cla()
x = np.arange(0, m)
y = np.arange(0, n)
x, y = np.meshgrid(x, y)
ax = fig.gca(projection='3d')
ax.plot_surface(x, y, Q[0, :, :], rstride=1, cstride=1, antialiased=True, cmap=cm.coolwarm);
#time.sleep(0.2)
display(fig)
plt.close()
$\Delta t$ er begrenset med følgende CFL-betingelse
$$ \Delta t \lt \frac{1}{4} \text{min}\left\\{\Delta x / |a_x|, \Delta y / |a_y| \right\\} $$hvor $a_{x}$ og $a_y$ er største / minste egenverdi i domenet for $F$ og $G$ respektivt.
Vi trenger i tillegg randkrav. I vårt tilfelle benytter vi vegg randkrav, hvor vi benytter skygge-celler:
$Q_{-1,-1} = Q_{0,0}, \quad Q_{m+1, n+1} = Q_{m, n}$
In [29]: