細川・林・石田・長谷部 2019...

29
プログラミング演習II 細川・林・石田・長谷部 2019 2Q

Transcript of 細川・林・石田・長谷部 2019...

Page 1: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

プログラミング演習II細川・林・石田・長谷部 2019 2Q

Page 2: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

拡散方程式

Page 3: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

液体を混ぜる

C v濃度 速度

Page 4: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

濃度Cの時間変化を支配する方程式

濃度は位置と時間の関数

Cの移流と拡散を表現する方程式(advection-diffusion equation)

@C

@t+ v ·rC = ↵r2C

拡散係数(diffusion coefficient)

1次元

2次元

C(x, t)

@C

@t+ u

@C

@x= ↵

@2C

@x2

@C

@t+ u

@C

@x+ v

@C

@y= ↵

✓@2C

@x2+

@2C

@y2

Page 5: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

1次元拡散方程式

まずは単純な問題から

時間だけでなく位置の関数     をどう扱うか?C(x, t)

計算対象とする領域(computational domain)

x

x = 0 x = 1

C(x, t)

分布は隣接領域に周期的とする (periodic boundary condition)

@C

@t= ↵

@2C

@x2

Page 6: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

離散化連続関数のすべての位置における値を取り扱う(保存し、計算する)のは不可能

xx = 0 x = 1

C(x, t)

i = 0 1 2 3 4 5 6 7 8 9x9x8x7x6x5x4x3x2x1x0

限られた場所のCの値のみを保存・計算する

(Cを離散的な値として取り扱う)Cn(xi) Cn

i

C0C1 C2 C3

C4

C5C6 C7

C8C9

位置に通し番号をつける

�x �x �x

const int NX=10; double* C = new double [NX]; delete [] C;

(C++の配列確保・削除)

double C[NX];

でも可。この場合delete無し

(newしたら必ずdelete)

Page 7: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

中心差分

5 6 7

C5

C6C7

�x �x

x

@C

@x

����n

i+1/2

!Cn

i+1 � Cni

�x

@C

@x

����n

i�1/2

!Cn

i � Cni�1

�x

@2C

@x2

����n

i

! 1

�x

"@C

@x

����n

i+1/2

� @C

@x

����n

i�1/2

#

Page 8: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

中心差分

5 6 7

C5

C6C7

�x �x

x

@C

@x

����n

i+1/2

!Cn

i+1 � Cni

�x

@C

@x

����n

i�1/2

!Cn

i � Cni�1

�x

@2C

@x2

����n

i

!Cn

i+1 � 2Cni + Cn

i�1

�x2

Page 9: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

一次精度陽解法 + 中心差分

Cn+1i � Cn

i

�t= ↵

Cni+1 � 2Cn

i + Cni�1

�x2

Cn+1i = Cn

i +↵�t

�x2

�Cn

i+1 � 2Cni + Cn

i�1

Cn+1i = Cn

i + d�Cn

i+1 � 2Cni + Cn

i�1

d =↵�t

�x2拡散数(diffusion number)

@C

@t= ↵

@2C

@x2

Page 10: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

拡散数と数値安定性(概説)

拡散数を変形すると、 d =↵�t

�x2=

↵/�x

�x/�t

数値計算の1ステップである点から隣の点にCの情報が伝達される、と捉えると、     はCの離散情報の伝播速度であり、流束は

�x/�t(�x/�t)C

一方、     から分かるように、     が物理的な流束であり、そのオーダは

r · ↵rC(↵/�x)C

これらの比が拡散数、とみても良い。 物理的な変化よりも離散情報の伝播の方が速くなければ正しく計算できないことは容易に想像できる。つまり、拡散数は1より十分小さくとるべき。 実際、理論的に       が安定条件となる。

d <1

2

�↵@C/@x

Page 11: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

計算条件の設定

計算領域と分割数の設定

格子点幅が決まる

拡散数を安定条件の範囲で指定

時間刻み幅が決まる dt =d�x2

const int NX=10; const double dx = 1.0/(double)(NX); const double alpha = 1.0; const double dnx = 0.10; const double dt = dnx/(alpha*(1.0/dx/dx));

x 2 [0, 1] Nx = 10

�x = 1/Nx

< 1/2

【新規プロジェクト:03DiffusionEquation】

Page 12: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

配列の確保・初期条件設定

double* x = new double [NX]; for(int i=0; i<NX; i++) x[i]=((double)i+0.5)*dx; double* C = new double [NX]; double* Cn = new double [NX]; double* tmp; for(int i=0; i<NX; i++){ C[i]=(cos(2.0*M_PI*x[i])+1.0)*0.5; }

Cは濃度の値保存用の配列。

Cnは差分式でアップデートした値を一旦保存しておく用の配列。

tmpはCnの値をCに付け替えるために利用するポインタ。

C(x, 0) = (cos(2⇡x) + 1)/2

Page 13: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

差分式の計算

while(step<stepEnd){ for(int i=0; i<NX; i++){ double cCenter = C[i]; int iw = i - 1; int ie = i + 1; double diffX = dnx*(C[ie] - 2.0*cCenter + C[iw]); Cn[i] = cCenter + diffX; } tmp=C; C=Cn; Cn=tmp;

step++; }

Cn+1i = Cn

i + d�Cn

i+1 � 2Cni + Cn

i�1

Page 14: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

境界条件の設定:考え方

今回は周期的条件を適用するので、    は       。

Cn+1i = Cn

i + d�Cn

i+1 � 2Cni + Cn

i�1

において、    のとき        は計算領域外で、プログラムでC[-1]を参照するとエラーが出るか、検討ハズレの値を拾ってくる。

i = 0 Ci�1 = C�1

i = �1 i = Nx � 1

はi = Nx i = 0

x

1 2 3 4 5 6 7 8 9

C0C1 C2 C3

C4

C5C6 C7

C8C9

0

(= Nx)(= �1)

(= Nx � 1)

Page 15: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

境界条件の設定:実装

while(step<stepEnd){ for(int i=0; i<NX; i++){ double cCenter = C[i]; int iw = i - 1; int ie = i + 1; if(i == 0 ) iw = NX-1; if(i == NX-1) ie = 0; double diffX = dnx*(C[ie] - 2.0*cCenter + C[iw]); Cn[i] = cCenter + diffX; } tmp=C; C=Cn; Cn=tmp;

step++; }

Page 16: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

gnuplotを使ったアニメーション

if(step%1==0){ gnuplot->PlotSymbol("plot (exp(-4*pi*pi*" + std::to_string(alpha*dt*(double)step) + ")*cos(2*pi*x)+1)*0.5,", x, C, NX, step); gnuplot->Flush(); }

理論解をプロット

データをシンボルでプロットプロットの更新

C(x, t) = e�4⇡2↵t(cos(2⇡x) + 1)/2

何step毎に出力するか(適当に調整)

Page 17: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

プログラム全景#include <iostream> #include <cmath> #include "GnuplotInterface.h"

int main(int argc, const char * argv[]) { GnuplotInterface* gnuplot = new GnuplotInterface(); gnuplot->SetAxisLabel("x", "x"); gnuplot->SetAxisLabel("y", "C"); gnuplot->SetGraphRange("x", 0.0, 1.0); gnuplot->SetGraphRange("y", 0.0, 1.0); const int NX=10; const double dx = 1.0/(double)(NX); const double alpha = 1.0; const double dnx = 0.10; const double dt = dnx/(alpha*(1.0/dx/dx)); std::cout << "dt: " << dt << std::endl; const double Tend = 0.2; const int stepEnd=(int)(Tend/dt) + 1; double* x = new double [NX]; for(int i=0; i<NX; i++) x[i]=((double)i+0.5)*dx; double* C = new double [NX]; double* Cn = new double [NX]; double* tmp; for(int i=0; i<NX; i++) C[i]=(cos(2.0*M_PI*x[i])+1.0)*0.5; int step=0; gnuplot->PlotSymbol("plot (exp(-4*pi*pi*" + std::to_string(alpha*dt*(double)step) + ")*cos(2*pi*x)+1)*0.5,", x, C, NX, step); gnuplot->Flush(); while(step<stepEnd){ for(int i=0; i<NX; i++){ double cCenter = C[i]; int iw = i - 1; int ie = i + 1; if(i == 0 ) iw = NX-1; if(i == NX-1) ie = 0; double diffX = dnx*(C[ie] - 2.0*cCenter + C[iw]); Cn[i] = cCenter + diffX; } tmp=C; C=Cn; Cn=tmp; step++; if(step%1==0){ gnuplot->PlotSymbol("plot (exp(-4*pi*pi*" + std::to_string(alpha*dt*(double)step) + ")*cos(2*pi*x)+1)*0.5,", x, C, NX, step); gnuplot->Flush(); } } delete [] x; delete [] C; delete [] Cn; delete gnuplot; return 0; }

Page 18: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

【課題】中心差分の精度

@2C

@x2

����n

i

!Cn

i+1 � 2Cni + Cn

i�1

�x2

【課題】テイラー展開を用いて中心差分の精度を調べる!

ヒント:C

ni+1 = C

ni +

1

1!

@C

@x

����n

i

�x+1

2!

@2C

@x2

����n

i

�x2 +

1

3!

@3C

@x3

����n

i

�x3 +O(�x

4)

Page 19: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

【課題】精度の数値的検証

@2C

@x2

����n

i

!Cn

i+1 � 2Cni + Cn

i�1

�x2

【課題】適当な関数に対して中心差分を適用し、格子幅の減少に伴う誤差の減少率を調べる。その結果が前頁の理論的検討と合っていることを確認する!

例:       とすると            。C(x) = eax

を中心として     における値を与え、差分を計算。x = 1 x±�x

を小さくしていき、理論値と比較する。�x

d2C(x)/dx2 = a2eax

Page 20: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

【課題】精度の数値的検証

Page 21: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

2次元拡散方程式

i = 0

j = 0

1 2 3 4

1

2

3

4

Cn+1ij = Cn

ij +↵�t

�x2(Cn

i+1j � 2Cnij + Cn

i�1j) +↵�t

�y2(Cn

ij+1 � 2Cnij + Cn

ij�1)

Cij Ci+1jCi�1j

Cij�1

Cij+1

d = ↵�t

✓1

�x2+

1

�y2

const int NX=10; const int NY=10; const double dx = 1.0/(double)(NX); const double dy = 1.0/(double)(NY); const double alpha = 1.0; const double dnmax = 0.10; const double dt = dnmax/(alpha*(1.0/dx/dx + 1.0/dy/dy)); const double dnx = alpha*dt/dx/dx; const double dny = alpha*dt/dy/dy; double* x = new double [NX]; double* y = new double [NY]; for(int i=0; i<NX; i++) x[i]=((double)i+0.5)*dx; for(int j=0; j<NY; j++) y[j]=((double)j+0.5)*dy; double* C = new double [NX*NY]; double* Cn = new double [NX*NY]; double* tmp; for(int j=0; j<NY; j++){ for(int i=0; i<NX; i++){ int m = NX*j + i; C[m]=sin(M_PI*x[i])*sin(M_PI*(y[j])); } }

1次元配列で二次元データを扱う

C(x, y, 0) = sin⇡x sin⇡y初期条件の例

m = Nx ⇥ j + i 配列インデックス

Page 22: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

2次元拡散方程式:結果の出力gnuplotを使った二次元プロット GnuplotInterface* gnuplot = new GnuplotInterface(); gnuplot->SetAxisLabel("x", "x"); gnuplot->SetAxisLabel("y", "y"); gnuplot->Injection("set cbrange [0:1]\n"); gnuplot->Injection("set size square\n");

...

if(step%1==0){ gnuplot->PlotMap("splot", x, y, C, NX, NY, step); gnuplot->Flush(); }

GnuplotInterface* gnuplot = new GnuplotInterface(); gnuplot->SetAxisLabel("x", "x"); gnuplot->SetAxisLabel("y", "y"); ...

if(step%1==0){ gnuplot->PlotMesh("splot", x, y, C, NX, NY, step); gnuplot->Flush(); }

Page 23: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

1次元拡散方程式:陰解法

d =↵�t

�x2

@C

@t= ↵

@2C

@x2

Cn+1i � Cn

i

�t= ↵

Cn+1i+1 � 2Cn+1

i + Cn+1i�1

�x2

�dCn+1i�1 + (1 + 2d)Cn+1

i � dCn+1i+1 = Cn

i

3つとも未知数のため、単純な代入計算では解は求まらない

Page 24: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

陰解法:連立方程式

�dCn+1Nx�1 + (1 + 2d)Cn+1

0 � dCn+11 = Cn

0

�dCn+10 + (1 + 2d)Cn+1

1 � dCn+12 = Cn

1

�dCn+11 + (1 + 2d)Cn+1

2 � dCn+13 = Cn

2

�dCn+1Nx�2 + (1 + 2d)Cn+1

Nx�1 � dCn+10 = Cn

Nx�1

...

各格子点について差分式を書き下すと次のようになる。

Nx個の方程式と未知数からなる連立方程式なので、線形代数の方法(ガウスの消去法)を適用すれば解ける。 ただし、その手の方法は、このように係数行列の要素がほとんど0の場合には非常に非効率。 反復法と呼ばれる方法を使う

Page 25: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

連立方程式の反復解法:例方程式・未知数が3つだけの小規模な問題を考える。

解はわからないが、適当な推定値を与える。たとえば、

C(0)0 = C(0)

1 = C(0)2 = 0

上付添字(0)は最初(0回目)に推定された値、という意味。

i = 0 :

i = 1 :

i = 2 :

ここから、ある計算を繰り返す(反復(iterate)する)ことで、推定値を正しい答え(解)に近づけていく!

5C0 + 2C1 + (0)C2 = 4

C0 + 6C1 + 3C2 = 2

(0)C0 + C1 + 2C2 = 4

Page 26: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

連立方程式の反復解法:例

隣接点i-1, i+1の現在の推定値(0)を代入して、中心の点iの次の推定値(1)を求める!

i = 0 :

i = 1 :

i = 2 :

5C0 + 2C1 = 4 ! 5C(1)0 = 4� 2C(0)

1

(0)C0 + C1 + 2C2 = 4 ! 2C(1)2 = 4� C(0)

1

新しい推定値(1)を使って、同じ計算をもう一度行えば次の推定値(2)が求まる。一般にk+1番目の推定値は、

C(k+1)2 = (4� C(k)

1 )/2

C(k+1)0 = (4� 2C(k)

1 )/5

C0 + 6C1 + 3C2 = 2 ! 6C(1)1 = 2� (C(0)

0 + 3C(0)2 )

C(k+1)1 = [2� (C(k)

0 + 3C(k)2 )]/6

Page 27: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

【課題】連立方程式の反復解法:小規模問題

C(k+1)2 = (4� C(k)

1 )/2

C(k+1)0 = (4� 2C(k)

1 )/5

反復計算を繰り返すと次第に正しい答えに近づく(と期待している)が、「倍精度で表現できる範囲で完全に正しい答え」まで繰り返す必要はない(し、大きい問題では非現実的)。そこで、自分が必要としている精度の解が得られたら反復を打ち切る(計算終了)。

1回反復する際に、未知数の変化量を計算し、各未知数の変化量のうち最大のものを調べる。その値が自分で設定した数値よりも小さければ、反復を終了すればよい。

【課題】この問題を反復法で解く!

C(k+1)1 = [2� (C(k)

0 + 3C(k)2 )]/6

Page 28: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

#include <iostream> #include <cmath>

int main(int argc, const char * argv[]) { int NX = 3; double* C = new double [NX]; double* Cn = new double [NX]; double* Aw = new double [NX]; double* Ap = new double [NX]; double* Ae = new double [NX]; double* S = new double [NX]; Aw[0] = 0.0; Ap[0] = 5.0; Ae[0] = 2.0; Aw[1] = 1.0; Ap[1] = 6.0; Ae[1] = 3.0; Aw[2] = 1.0; Ap[2] = 2.0; Ae[2] = 0.0; S[0] = 4.0; S[1] = 2.0; S[2] = 4.0; C[0] = 0.0; C[1] = 0.0; C[2] = 0.0; double tolerance = 1.0e-6; double dcmax = 1.0e30; int iteration = 0; while(dcmax > tolerance){ for(int i=0; i<NX; i++){ double Cw = 0.0; double Ce = 0.0; if(i != 0) Cw = C[i-1]; if(i != NX-1) Ce = C[i+1]; Cn[i] = (S[i] - (Aw[i]*Cw + Ae[i]*Ce))/Ap[i]; } dcmax = 0.0; for(int i=0; i<NX; i++){ double delta = fabs(C[i] - Cn[i]); if(delta > dcmax) dcmax = delta; C[i] = Cn[i]; } iteration++; std::cout << "iteration: " << iteration << std::endl; for(int i=0; i<NX; i++) std::cout << C[i] << std::endl; } delete [] C; delete [] Cn; delete [] Aw; delete [] Ap; delete [] Ae; delete [] S; return 0; }

【課題】連立方程式の反復解法:小規模問題

Page 29: 細川・林・石田・長谷部 2019 2Qhayashi/handout/programmingII2019...濃度Cの時間変化を支配する方程式 濃度は位置と時間の関数 Cの移流と拡散を表現する方程式(advection-diffusion

【課題】1次元拡散方程式:陰解法

【課題】1次元拡散方程式を陰解法で解く!

*この解法をヤコビ法(Jacobi method)という