移流方程式から始めて、保守的な形式です。
∂あなた∂t= - ∂(v u )∂バツ+ s (x 、t )
クランクニコルソン法は、時間平均の中心差で構成されます。
あなたn + 1j- UんjΔ トン= - V [ 1 - β2 Δ X(uんj + 1- Uんj − 1) + β2 Δ X(un + 1j + 1- Un + 1j − 1) ] +s(x、t)
表記に関して、下付き文字は空間内のポイントを示し、上付き文字は時間内のポイントを示します。
のポイントは将来のものです:それらは未知数です。ここで、すべての既知がrhsにあり、未知数がlhsにあるように、上記の方程式を並べ替える必要があります。n + 1
置換を行い、
r = v2Δ トンΔのX
与える、
- βr ϕn + 1j − 1+ ϕn + 1j+ βr ϕn + 1j + 1= (1 - β)r ϕんj − 1+ ϕんj− (1 - β)r ϕんj + 1
これは、クランクニコルソン法を使用して離散化された移流方程式です。あなたはそれを行列方程式として書くことができ、
β=1/2
⎛⎝⎜⎜⎜⎜⎜⎜⎜1−βr0βr1⋱βr⋱−βr⋱1−βr0βr1⎞⎠⎟⎟⎟⎟⎟⎟⎟⎛⎝⎜⎜⎜⎜⎜⎜⎜⎜あなたn + 11あなたn + 12⋮あなたn + 1J− 1あなたn + 1J⎞⎠⎟⎟⎟⎟⎟⎟⎟⎟= ⎛⎝⎜⎜⎜⎜⎜⎜⎜1(1 − β)r0− (1 −β)r1⋱− (1 −β)r⋱(1 − β)r⋱1(1 − β)r0− (1 −β)r1⎞⎠⎟⎟⎟⎟⎟⎟⎟⎛⎝⎜⎜⎜⎜⎜⎜⎜⎜あなたん1あなたん2⋮あなたんJ− 1あなたんJ⎞⎠⎟⎟⎟⎟⎟⎟⎟⎟
1/2を設定すると、時間内に台形積分が行われるため、Crank-Nicolsonの場合はこれが必要です。
β= 1 / 2
警告のいくつかの単語。これはあなたが欲しかった基本的な解決策ですが、適切な問題のためにある種の境界条件を含める必要があります。また、Crank-Nicolsonは必ずしも移流方程式の最良の方法ではありません。これは2次精度であり、無条件に安定しています。これは素晴らしいことです。ただし、非常に鋭いピークのあるソリューションまたは初期条件がある場合は、(すべての中央の差分ステンシルと同様に)偽の発振が発生します。
私はPythonで次のコードを記述しました。これで開始できます。このコードは、一定の速度で右に移動する初期ガウス曲線の移流方程式を解きます。
from __future__ import division
from scipy.sparse import spdiags
from scipy.sparse.linalg import spsolve
import numpy as np
import pylab
def make_advection_matrices(z, r):
"""Return matrices A and M for advection equations"""
ones = np.ones(len(z))
A = spdiags( [-beta*r, ones, beta*r], (-1,0,1), len(z), len(z) )
M = spdiags( [(1-beta) * r, ones, -(1-beta) * r], (-1,0,1), len(z), len(z) )
return A.tocsr(), M.tocsr()
def plot_iteration(z, u, iteration):
"""Plot the solver progress"""
pylab.plot(z, u, label="Iteration %d" % iteration)
# Set up basic constants
beta = 0.5
J = 200 # total number of mesh points
z = np.linspace(-10,10,J) # vertices
dz = abs(z[1]-z[0]) # space step
dt = 0.2 # time step
v = 2 * np.ones(len(z)) # velocity field (constant)
r = v / 2 * dt / dz
# Initial conditions (peak function)
gaussian = lambda z, height, position, hwhm: height * np.exp(-np.log(2) * ((z - position)/hwhm)**2)
u_init = gaussian(z, 1, -3, 2)
A, M = make_advection_matrices(z, r)
u = u_init
for i in range(10):
u = spsolve(A, M * u)
plot_iteration(z, u, i)
pylab.legend()
pylab.show()