数値計算実習
桂田 祐史
2015 年 7 月 15 日 , 2015 年 7 月 22 日
1 レポート課題
(
書きかけ)
締め切りは
8
月1
日18:00,
提出方法はOh-o! Meiji.
複数のファイルを送りたい場合は、zip
でまとめて送って下さい。もし容量制限に引っかかった場合は、早目にメールで相談。以下のいずれかをして下さい。使用するプログラミング言語の選択は基本的に自由ですが、
こちらが直接相談に乗るためには、自分の
MacBook Air
で実行できて、見せることが出来る 必要がある。[
1
](1)
湧き出しまたは渦糸の流線・等ポテンシャル線、ベクトル場を適当に(
流れの様子が 良く分かるように)
可視化する。(2)
自分で思いつく正則関数を5
つ以上試し、そのう ちの1
つを選んで、それを複素速度ポテンシャルとする流れについて、流線、等ポテン シャル、ベクトル場を適当に可視化し、それをもとにどういう流れであるか説明する。[2]渦なし非圧縮の定常流で、流体の占める領域の境界での流速が分かっている場合に、速 度ポテンシャル、流れ関数を有限要素法で計算して、当ポテンシャル線
,
流線,
ベクトル 場を可視化せよ。[3]自分が選んだ単連結領域
Ω
を単位円盤D
1 に双正則にうつす写像φ: Ω → D(0; 1)
の を 基本解の方法を用いて数値的に求めよ。結果を何らかの方法で確かめること(
もしも真の 写像が分かっている場合はそれとの比較、像が実際に単位円になっていることなど。)
。2 簡単な流れの可視化
2.1 おさらい
流体の
2
次元の流れを考える。速度場をv =
( u v
)
とするとき、
ω := v
x− u
yで定義される
ω
を渦度と呼び、いたるところω = 0
であるとき、流れは渦なしという。非圧縮条件
div v = 0
が成り立つとき、流れは非圧縮であるという。•
渦なしならば速度ポテンシャルが存在: ∃ ϕ s.t. grad ϕ = (
ϕ
xϕ
y)
= v.
さらに非圧縮なら ば△ ϕ = 0.
例えば領域の境界で
v
が分かれば、△ ϕ = 0 (in Ω)
∂ϕ
∂n = v · n (on ∂ Ω)
•
非圧縮ならば流れ関数が存在: ∃ ψ s.t.
( ψ
y− ψ
x)
= v.
さらに渦なしならば△ ψ = 0.
•
渦なし非圧縮ならばf := ϕ + iψ
は正則関数で、f
′= u − iv .
•
曲線で、その接線ベクトルが速度ベクトルと方向が同じものを流線と呼ぶ。定常流の場 合、流線は粒子の軌跡と一致する。ψ =
定数 は流線を表す。• ϕ =
定数 で表される曲線を等ポテンシャル線と呼ぶ。•
渦なし非圧縮流では、流線と等ポテンシャル線は互いに直交する。2.2 簡単な流れ
2.2.1
一様な流れc ∈ C , f(z) = cz
の場合、c = U e
−iα(U > 0, α ∈ R )
とする。複素速度はu − iv = f
′= U e
−iα.
すなわち
v = (
u v
)
= (
U cos α U sin α
) .
速度ポテンシャルと流れ関数は
{
ϕ = U (x cos α + y sin α),
ψ = U ( − x sin α + y cos α)
図
1:
一様な流れ2.2.2
湧き出し、吸い込みm ∈ R , f(z) = m log z (
多価関数!)
の場合、z = re
iθ とすると、u − iv = f
′= m z = m
r (cos θ − i sin θ) .
すなわちv = (
u v
)
=
m
r cos θ m
r sin θ
.
速度ポテンシャルと流れ関数は{
ϕ = m log r ψ = mθ
原点の周りを一周する任意の閉曲線
C
を取ると、C
から外に湧き出る流量は∫
C
v · nds =
∫
C
dψ = Im
∫
C
df = Im
∫
C
f
′(z)dz = Im
∫
C
m
z dz = 2πm.
(
既に見たように、n ds =
( − dy dx
)
であり、
v · n ds = − vdx + udy = ψ
xdx + ψ
ydy = dψ
で ある。)
m > 0
ならば原点から湧き出す流れ、m < 0
ならば原点に吸い込まれる流れ、を表す。これは
C \ { 0 }
で渦なしの流れである。2.3 渦糸
κ ∈ R , f (z) = iκ log z
の場合、z = re
iθ とすると、u − iv = f
′= iκ z = κ
r i (cos θ − i sin θ) = κ
r (sin θ + i cos θ) .
すなわちv = (
u v
)
=
κ r sin θ
− κ r cos θ
= κ r
( 0 1
− 1 0 ) (
cos θ sin θ
)
= κ r
(
cos
−2π− sin
−2πsin
−2πcos
−2π) ( cos θ sin θ
)
.
図
2:
湧き出し 速度ポテンシャルと流れ関数は{
ϕ = − κθ ψ = κr
流線は原点を中心とする円で、等ポテンシャル線は原点を端点とする半直線である。
図
3:
渦糸3 Mathematica で一様流を可視化
複素数の計算、二変数関数の等高線と
2
次元ベクトル場の描画が出来れば良い。虚数単位は
I,
実部Re[],
虚部Im[],
共役複素数Conjugate[],
絶対値Abs[],
偏角(
の主 値) Arg[],
それとComplexExpand[]
などが用意されている。2
変数関数の等高線にはContourPlot[],
ベクトル場の描画にはVectorPlot[]
が用意され ている。これらの使い方はオンライン・ヘルプを見よ。
c=1-2I f[z_]:=c z
phi[x_,y_]:=ComplexExpand[Re[f[x+I y]]]
psi[x_,y_]:=ComplexExpand[Im[f[x+I y]]]
g1=ContourPlot[phi[x,y]==Table[c,{c,-5,5,1.0}],{x,-2,2},{y,-2,2}, ContourStyle->Directive[Red]]
g2=ContourPlot[psi[x,y]==Table[c,{c,-5,5,1.0}],{x,-2,2},{y,-2,2}, ContourStyle->Directive[Blue,Thin]]
u[x_, y_] := ComplexExpand[Re[f’[x + I y]]]
v[x_, y_] := -ComplexExpand[Im[f’[x + I y]]]
g3 = VectorPlot[{u[x, y], v[x, y]}, {x, -2, 2}, {y, -2, 2}]
g12=Show[g1,g2]
g13=Show[g1,g3]
ComplexExpand[]
は事前にEvaluate
させる効果も考えて採用したが、いつもこれを使うの が良いかは良く分からない。一様流は素直なので簡単に描画できるが、そうでないものは色々調整が必要そうだ。
4 Laplace 方程式の境界値問題を数値計算で解く
4.1 この講義に現れた境界値問題
1
つは速度ポテンシャルに対するNeumann
境界値問題で、△ ϕ = 0 (in Ω) (1)
∂ϕ
∂n = v · n (on ∂ Ω) (2)
というもの。この場合は、
Γ
1= ∅ , Γ
2= ∂ Ω, f = 0, g
2= v · n
とすれば良い。もう
1
つは、領域Ω
の写像関数f : Ω → D
1 を求めるためのDirichlet
境界値問題で、△ u = 0 (in Ω) (3)
u(z) = − log | z − z
0| (z ∈ ∂Ω).
(4)
ただし
z
0 はΩ
から選んだ任意の1
点である。このu
の1
つの共役調和関数をv
として、f (z) = (z − z
0) exp (u(z) + iv (z))
でf
が得られる。-2 -1 0 1 2 -2
-1 0 1 2
図
4:
等ポテンシャル線と流線は直交する-2 -1 0 1 2
-2 -1 0 1 2
図
5:
等ポテンシャル線と速度ベクトル4.2 FreeFem++ とは
FreeFem++
1 は、パリ第6
大学J. L. Lions
研究所のFr´ ed´ eric Hecht, Oliver Pironneau, A. Le
Hyaric,
広島国際学院大学の大塚厚二氏らが開発した、2
次元, 3
次元問題を有限要素法で解くための、 一種の
PSE (problem solving environment)
であり、ソースコード、マニュアル(
約400
ページ,幸い英文)、主なプラットホーム(Windows, Mac, Linux)
向けの 実行形式パッケー ジが公開されている。細かいことは、以前書いた紹介文「FreeFEM++ の紹介」2 を見てもらうことにする。
上記の
WWW
サイトから、FreeFem++-3.38-MacOS 10.9-mpi.pkg
のようなインストー ラーを入手して実行するだけで、簡単にインストールできる。4.3 Poisson 方程式の境界値問題に対する弱形式
Ω
をR
m の有界な領域、その境界∂Ω
がΓ
1, Γ
2 に分かれているとする。∂Ω = Γ
1∪ Γ
2, Γ
1∩ Γ
2= ∅ .
このとき、Poisson
方程式の境界値問題− △ u = f (in Ω) (5)
u = g
1(on Γ
1) (6)
∂u
∂n = g
2(on Γ
2) (7)
は、次のように弱定式化される。
Find u ∈ X
g1s.t.
∫
Ω
grad u · grad v dx =
∫
Ω
f v dx +
∫
Γ2
g
2v ds (v ∈ X).
ここで
X
g1:= {
w ∈ H
1(Ω) | w = g
1on Γ
1} , X := {
w ∈ H
1(Ω) | w = 0 on Γ
1} .
それから念のため: grad u · grad v = u
xv
x+ u
yv
y.
4.4 (1), (2) を解くための FreeFem++ のプログラム
速度ポテンシャルを求める境界値問題
△ ϕ = 0 (in Ω) (
再1)
∂ϕ
∂n = v · n (on ∂ Ω) (
再2)
1http://www.freefem.org/ff++/
2http://nalab.mind.meiji.ac.jp/~mk/labo/text/welcome-to-freefem-2012/welcome-to-freefem-2012.html
の場合は、
Γ
1= ∅ , Γ
2= ∂Ω, f = 0, g
2= v · n.
特に
Ω = { (x, y) ∈ R
2| x
2+ y
2< 1 } , v ≡ (
1 2
)
のときは、
(x, y) ∈ ∂Ω
においてn = (
x y
)
であるから、
g
2= v · n = (
1 2
)
· (
x y
)
= x + 2y.
速度ポテンシャルを求める
solveLaplace.edp
// solveLaplace.edp
border Gamma2(t=0,2*pi) { x=cos(t); y=sin(t); } int m=40;
mesh Th = buildmesh(Gamma2(m));
plot(Th, wait=1, ps="Th.eps");
savemesh(Th,"Th.msh"); // optional fespace Vh(Th,P1);
Vh u,v;
func f=0;
func g1=0; // no use func g2=x+2*y;
solve Poisson(u,v) =
int2d(Th)(dx(u)*dx(v)+dy(u)*dy(v)) -int2d(Th)(f*v)
-int1d(Th,Gamma2)(g2*v) // +on(Gamma1,u=g1)
;
plot(u,ps="equipotential.eps");
プログラムはテキスト・エディター
(テキスト・エディット, mi, emacs
など)で作成し、ター ミナルから、こんなふうにして実行
FreeFem++ solveLapalce.edp
とタイプして実行できる。
(
実は、上の弱形式は解の一意性がないので、このプログラムは少し危ういところがある。)
4.5 (3), (4) を基本解の方法で解く
(
この項は書きかけです。)
写像関数
f : Ω → D
1 を求めるための、境界値問題△ u = 0 (in Ω) (再 3)
u(z) = − log | z − z
0| (on ∂ Ω)
(
再4)
図
6: Ω
の三角形分割図
7:
一様流の等ポテンシャル線と流線 を基本解の方法(FSM)
で解いてみよう。Ω
の外部にN
個の点ζ
1, . . . , ζ
N を取り、u
(N)(z) :=
∑
N k=1Q
klog | z − ζ
k|
とおく。ここで
Q
k(k = 1, . . . , N )
は未知の実定数である。一方、∂Ω
からz
1, · · · , z
N を選び、u
(N)(z
j) = − log | z
j− z
0| (j = 1, · · · , N )
でQ
j を定める。具体的には連立1
次方程式
log | z
1− ζ
1| log | z
1− ζ
2| · · · log | z
1− ζ
N| log | z
2− ζ
1| log | z
2− ζ
2| · · · log | z
2− ζ
N|
.. . .. . . .. .. .
log | z
N− ζ
1| log | z
N− ζ
2| · · · log | z
N− ζ
N|
Q
1Q
2.. . Q
N
=
− log | z
1− z
0|
− log | z
2− z
0| .. .
− log | z
N− z
0|
を解けばよい。
Ω
をD
1 に写す等角写像を求めてみよう。実部がu
(N) と一致する正則関数f
(N)が求まれば、ϕ
(N)(z) = (z − z
0) exp f
(N)(z)
が等角写像の近似になることが期待できる。簡単のため、
Ω
はz
0 に関して星型であるとする。このときf
(N)(z) := Q
0+
∑
N k=1Q
kLog z − ζ
kz
0− ζ
k, Q
0:=
∑
N k=1Q
klog | z
0− ζ
k|
は実部が
u
(N)に等しい正則関数である。Log
を使っているが、Ω
全体で一価正則な関数になっ ている。4.6 Eigen ライブラリィを用いた計算プログラム
個人的には、この手の計算には
MATLAB
を使うのが好みであるが、ここでは、C++
でベ クトル、行列に関する演算をするための計算ライブラリィEigen
3 を利用してみる。WWW
サイトから、eigen-eigen-bdd17ee3b1b3.tar.gz
のようなソース・ファイル一式 を入手して、以下のようにインストールする(/usr/include/
にファイルをインストールする 場合)
。MacBook
のターミナルで次のようにインストール
tar xzf eigen-eigen-bdd17ee3b1b3.tar.gz cd eigen-eigen-bdd17ee3b1b3
tar cf - Eigen | (cd /usr/include/; sudo tar xpf -)
Ω = D
1= D(0; 1), z
0= 1/2
の場合を解いてみよう。この場合は、φ(z) = ε z − z
01 − z
0z
が解であることが分かっている
(ε
は| ε | = 1
を満たす定数)
。conformalmap.cpp
4/*
* conformalmap.cpp --- 等角写像の数値計算例 (基本解の方法の天野要バージョン)
*
* g++ -I/usr/X11R6/include conformalmap.cpp -L~/lib -lglscd -L/usr/X11R6/lib -lX11
*/
#include <iostream>
#include <complex>
#include <Eigen/Dense>
extern "C" {
#include <glsc.h>
};
using namespace Eigen;
// MatrixXd は大きさが指定できて、成分が double // d の変わりに i, f, cf, cd
3http://eigen.tuxfamily.org/
4http://nalab.mind.meiji.ac.jp/~mk/complex2/conformalmap.cpp
// φ(z0)=0, φ’(z0)>0 を満たす等角写像
std::complex<double> phi(std::complex<double> z, std::complex<double> z0) {
std::complex<double> w;
w = (z-z0)/(1.0-std::conj(z0)*z);
return w;
}
// 天野の方法による等角写像
std::complex<double> f(std::complex<double> z, std::complex<double> z0, int N,
double Q0,
VectorXd Q, VectorXcd zeta) {
int k;
std::complex<double> s;
s = Q0;
for (k = 0; k < N; k++)
s += Q(k) * log((z-zeta(k))/(z0-zeta(k)));
return (z-z0) * std::exp(s);
}
int main(void) {
int i, j, k, N, m;
double theta, pi, dt, R, Q0, r, dr;
// 虚数単位と原点に移る点 z0=1/2
std::complex<double> I(0,1), z0(0.6,0.0), zp, w, w2;
R = 2;
N = 80;
VectorXcd zeta(N), z(N);
VectorXd b(N), Q(N);
MatrixXd a(N,N);
pi = 4.0 * atan(1.0);
dt = 2 * pi / N;
// 円周 |z|=2 上の等分点 for (k = 0; k < N; k++)
zeta(k) = R * exp(I * (k * dt));
// std::cout << "zeta=" << zeta << std::endl;
// 単位円周 |z|=1 上の等分点 for (j = 0; j < N; j++)
z(j) = exp(I * (j * dt));
// 係数行列の準備
for (j = 0; j < N; j++) for (k = 0; k < N; k++) {
a(j,k) = log(abs(z(j)-zeta(k)));
} // 右辺
for (j = 0; j < N; j++) { b(j) = - log(abs(z(j)-z0));
}
// 電荷を求める
Q = a.partialPivLu().solve(b);
// Q0 を求める Q0 = 0;
for (k = 0; k < N; k++) {
Q0 += Q(k) * log(abs(z0-zeta(k)));
}
g_init("GRAPH", 150.0, 150.0);
g_device(G_BOTH);
g_def_scale(0, - 1.2, 1.2, -1.2, 1.2, 10.0, 10.0, 140.0, 140.0);
g_sel_scale(0);
m = 20;
// 同心円の像 dr = 1.0 / m;
dt = 2 * pi / (4 * m);
for (i = 1; i <= m; i++) { r = i * dr;
for (j = 0; j <= 4 * m; j++) { zp = r * exp(I * (j * dt));
w=f(zp,z0,N,Q0,Q,zeta);
if (j == 0)
g_move(w.real(), w.imag());
else
g_plot(w.real(), w.imag());
} }
// 放射線の像
for (j = 0; j <= 4 * m; j++) { theta = j * dt;
for (i = 0; i <= m; i++) { r = i * dr;
zp = r * exp(I * theta);
w=f(zp,z0,N,Q0,Q,zeta);
if (i == 0)
g_move(w.real(), w.imag());
else
g_plot(w.real(), w.imag());
} }
g_sleep(-1.0);
g_term();
}
g++ -I/usr/X11R6/include conformalmap.cpp -L/usr/local/lib -lglscd -L/usr/X11R6/lib -lX11
図
8: w = z − z
01 − z
0z , z
0= 1/2