数学の具体的な計算にPythonを使って、数学もPythonも同時に学んでしまいましょう。今回はPythonを使って、ベクトル場を描写したいと思います。ベクトル場を分析するにあたり、いわゆるベクトル解析の知識を少し使います。Pythonでのベクトル解析については以下の記事で扱っています:
pianofisica.hatenablog.com
pianofisica.hatenablog.com
あわせて読んでみてください。
ベクトル場の描画
具体例1(一様なベクトル場)
一様なベクトル場 は次のようにして描画できます:
import numpy as np import matplotlib.pyplot as plt plt.figure() # 表示範囲の設定 Lx, Ly = 3. , 3. # メッシュの生成 gridWidth = float(1/2) X, Y= np.meshgrid(\ np.arange(-Lx, Lx, gridWidth),\ np.arange(-Ly, Ly,gridWidth)) # ベクトル場 (Vx, Vy)の入力 Vx = 2. Vy = 1. # ベクトル場の描画 plt.quiver(X,Y,Vx,Vy,color='grey') plt.xlim([-Lx,Ly]) plt.ylim([-Ly,Ly]) # グラフの描画 plt.grid() plt.draw() plt.show()
より次の図を得ます:
具体例2(2次元流体力学の複素ポテンシャル)
位置に依存するベクトル場として を考えてみましょう。
Vx = X**2 - Y**2 Vy = - 2*X*Y plt.quiver(X,Y,Vx,Vy,color='grey') plt.xlim([-Lx,Ly]) plt.ylim([-Ly,Ly]) plt.grid() plt.draw() plt.show()
によって、ベクトル場の様子が次のように図示されます:
実はこのベクトル場はちょっと特殊な性質を持っています。これを示すために、ベクトル解析の計算を少しやってみます(詳しい計算については過去記事を参照してください):
import sympy as sp sp.var(' x y z ', real= True) def grad(f): return sp.expand(sp.Matrix([[sp.diff(f,x)],[sp.diff(f,y)],[sp.diff(f,z)]])) def div(V): return sp.expand(sp.diff(V[0,0],x)+sp.diff(V[1,0],y)+sp.diff(V[2,0],z)) def rot(V): return sp.expand(sp.Matrix(\ [[sp.diff(V[2,0],y)-sp.diff(V[1,0],z)],\ [sp.diff(V[0,0],z)-sp.diff(V[2,0],x)],\ [sp.diff(V[1,0],x)-sp.diff(V[0,0],y)]])) V = sp.Matrix([[x**2-y**2],[-2*x*y],[0]]) [div(V),rot(V)]
から
がわかります。まず第2の式から、ベクトル場 が適当な関数 によって
と書けることがわかります(ポアンカレの補題)。実際、 として
ととることで、ベクトル場 が得られます:
f = sp.Rational(1,3)*(x**3 - 3*x*y**2) grad(f)
さらに、この事実と、 の第1の式とから
(ここで自明な 方向の微分は落としました)であり、ここで得た関数 は2次元ラプラス方程式の解になっていることがわかります。
さて、関数 を因数分解すると
ですから、零点集合 は次の3つの直線によって与えられることがわかります:
これらの直線とベクトル場を重ねて図示してみましょう:
Q = np.linspace( -Ly, Ly, int(1e2) ) P1 = np.zeros(int(1e2)) P2 = np.sqrt(3)*Q P3 = -np.sqrt(3)*Q plt.quiver(X,Y,Vx,Vy,color='grey') plt.xlim([-Lx,Ly]) plt.ylim([-Ly,Ly]) plt.grid() plt.draw() plt.plot(P1, Q) plt.plot(P2, Q) plt.plot(P3, Q) plt.show()
図から読み取れることは、これら3本の直線とベクトル場 が直交していることです。実際に計算して確かめてみましょう:
def Dot(A, B): return sp.expand((A.transpose()*B)[0,0]) e1 = sp.Matrix([[0],[1],[0]]) e2 = sp.Matrix([[sp.sqrt(3)],[1],[0]]) e3 = sp.Matrix([[sp.sqrt(3)],[-1],[0]]) [Dot(V.subs(x, 0),e1), Dot(V.subs(x, sp.sqrt(3)*y),e2), Dot(V.subs(x, -sp.sqrt(3)*y),e3)]
さらに、次の関数
の零点 を考えると、今度はベクトル場 と平行する(流れが収斂する)方向になっていることがわかります:
R = np.linspace( -Lx, Lx, int(1e2) ) S1 = np.zeros(int(1e2)) S2 = np.sqrt(3)*R S3 = -np.sqrt(3)*R plt.quiver(X,Y,Vx,Vy,color='grey') plt.xlim([-Lx,Ly]) plt.ylim([-Ly,Ly]) plt.grid() plt.draw() plt.plot(R, S1) plt.plot(R, S2) plt.plot(R, S3) plt.show()
タネ明かし
何かトリックがありそうですね。唐突ですが、2次元座標 から複素数 を
によって導入してみましょう。すると
z = x + sp.I*y F = sp.expand(z**2) [sp.re(F), sp.im(F)]
より
であることがわかります。さらには
G = sp.expand(sp.Rational(1,3)*z**3) [sp.re(G), sp.im(G)]
より
だったことがわかります。そしてベクトル場を特徴づける直線(ベクトル場と直交する・平行する)が3本ずつあったのは、変換
を考えたときに、関数 を不変に保つ群の作用:
これらの存在による帰結だったのです。まず、複素数による積が、複素平面における回転を記述したことを思い出しましょう。すると、上の例で見た直線 は、直線 にそれぞれ を掛けて回転させて得られる直線に他なりません。実は、この例で取り上げたベクトル場の背後には、こういった構造が仕込まれていたのでした。
以上の事情は一般的なものであって、任意の自然数 について
とすると
が成り立つことが示せて、またベクトル場を特徴付ける直線(ベクトル場と直交する・平行する)が 本ずつ出てきます。これらの性質は、2次元流体力学の特別な場合における『複素ポテンシャル』の手法として利用されています。