クランクニコルソン法を使用して移流方程式を離散化する方法


8

移流方程式は、Crank-Nicolson法で使用するために離散化する必要があります。誰かがその方法を教えてもらえますか?


1
SciCompへようこそ!あなたの質問の範囲はこのサイトに非常に適合します。ただし、適切な回答を得るには、より具体的にする必要があります。特にわからないことを教えてください。あなたのコードはよく構造化され、文書化されているように見えますが、あなたの質問に答えるためには、おそらくより小さなコードスニペットで十分です。
2013年

たとえば、入力ベクトルに5つの要素があるテストケースを使用し、gdbやdddなどのデバッガーでコードをステップ実行すると、デバッグが簡単になる場合があります。そうすることで、エラーの原因を絞り込むことができます。ほとんどのコードデバッグの質問は、ここではあまりうまく機能しないと思います。これは、作業の大部分が、バグが最初にどこにあるのかを突き止めることに関係しているためです。それを見つけたら、説明は頻繁に(ただし、常にというわけではありません)簡単です。ユニットテストを実行して、Tridiagonalにこの動作を引き起こしている可能性のあるバグがあるかどうかを把握できますか?
Geoff Oxberry 2013年

WikipediaのCrank-Nicolsonメソッドのでこのをご覧ください。あなたが設定した場合し、Dは、xはゼロに、それはプレーンな移流問題に変わります。境界条件を組み込むために残っています...kDx
1

申し訳ありませんが、クランクニコルソン法は移流問題にはまったく不適切です。局所微分近似の安定性と精度は、残念ながら一貫性を保証しません。別の問題の解決策が得られます。いくつかの些細なケースでは幸運になるかもしれませんが、移流方程式は一般に許されません。数値解析の教科書を確認してください。Crank-Nicolsonスキームは使用されません。安定性のため、人々はまだいくつかのエンジニアリング上の問題でそれを採用する必要がありますが、そこで進化するにつれてソリューションを制御し、

回答:


19

移流方程式から始めて、保守的な形式です。

ut=(vu)x+s(x,t)

クランクニコルソン法は、時間平均の中心差で構成されます。

あなたj+1あなたjΔt=v[1β2Δバツあなたj+1あなたj1+β2Δバツあなたj+1+1あなたj1+1]+sバツt

表記に関して、付き文字は空間内のポイントを示し、上付き文字は時間内のポイントを示します。

のポイントは将来のものです:それらは未知数です。ここで、すべての既知がrhsにあり、未知数がlhsにあるように、上記の方程式を並べ替える必要があります。+1

置換を行い、

r=v2ΔtΔバツ

与える、

βrφj1+1+φj+1+βrφj+1+1=1βrφj1+φj1βrφj+1

これは、クランクニコルソン法を使用して離散化された移流方程式です。あなたはそれを行列方程式として書くことができ、

β=1/2

1βr0βr1βrβr1βr0βr1あなた1+1あなた2+1あなたJ1+1あなたJ+1=11βr01βr11βr1βr11βr01βr1あなた1あなた2あなたJ1あなた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()

3
実際、以前の質問も見ましたが、非常に一般的で答えられませんでした(コードのページを投稿したとき)。私の経験では、あなたがこのサイトで良い質問をすると、人々は非常に役に立ちます。道中ご無事に!
boyfarrell 2013年

ほんの冗談です。
パンドラガミ2013年

@boyfarrelこれのC ++ / Cバージョンがある可能性はありますか。ない場合は問題ありません。私はmatlabをあまり使用しておらず、習得したくありません。Fortranの方が良いでしょう。
パンドラガミ2013年

2
<不適切なコメントを削除>
ポール
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.