流体の中に小さな羽根車を置いたとき、その羽根車がどの軸周りにどれだけ速く回転するかを表す量が 回転(rotation, curl)です。日本語では「回転」、英語では “curl” と呼ぶのが一般的で、記号としては $\mathrm{rot}\, \bm{F}$ や $\nabla \times \bm{F}$ と書きます。
回転はベクトル場の「渦の強さ」を定量化する微分演算子であり、電磁気学のファラデーの法則($\nabla \times \bm{E} = -\frac{\partial \bm{B}}{\partial t}$)やアンペールの法則($\nabla \times \bm{B} = \mu_0 \bm{J}$)、流体力学の渦度など、物理法則の記述に不可欠です。
本記事の内容
- 回転の直感的な理解(渦の強さ)
- 回転の数学的定義
- ストークスの定理
- 保存場と回転の関係($\nabla \times (\nabla f) = \bm{0}$)
- 具体例と計算
- Pythonでの回転の可視化
前提知識
この記事を読む前に、以下の記事を読んでおくと理解が深まります。
回転とは
直感的な理解
ベクトル場を流体の速度場だと考えます。流体の中に小さな羽根車を浮かべたとき:
- 羽根車が回転する → その場所で流体に 渦 がある → $\nabla \times \bm{F} \neq \bm{0}$
- 羽根車が回転しない → 渦がない → $\nabla \times \bm{F} = \bm{0}$
回転ベクトル $\nabla \times \bm{F}$ の 方向 は回転軸の方向(右ねじの法則に従う)、大きさ は回転の強さ(角速度の2倍)を表します。
循環との関係
閉曲線 $C$ に沿ったベクトル場 $\bm{F}$ の 循環(circulation)は:
$$ \begin{equation} \Gamma = \oint_C \bm{F} \cdot d\bm{r} \end{equation} $$
回転の各成分は、対応する座標面上の微小閉曲線に沿った循環を面積で割った極限として得られます。
$$ (\nabla \times \bm{F}) \cdot \bm{n} = \lim_{\Delta S \to 0} \frac{1}{\Delta S} \oint_{\partial \Delta S} \bm{F} \cdot d\bm{r} $$
回転の数学的定義
定義
ベクトル場 $\bm{F}(x, y, z) = (F_x, F_y, F_z)$ の 回転(curl / rotation)は:
$$ \begin{equation} \mathrm{rot}\, \bm{F} = \nabla \times \bm{F} = \begin{pmatrix} \dfrac{\partial F_z}{\partial y} – \dfrac{\partial F_y}{\partial z} \\[10pt] \dfrac{\partial F_x}{\partial z} – \dfrac{\partial F_z}{\partial x} \\[10pt] \dfrac{\partial F_y}{\partial x} – \dfrac{\partial F_x}{\partial y} \end{pmatrix} \end{equation} $$
行列式による覚え方
回転は、次の行列式の形式的な展開として覚えることができます。
$$ \begin{equation} \nabla \times \bm{F} = \begin{vmatrix} \bm{e}_x & \bm{e}_y & \bm{e}_z \\[4pt] \dfrac{\partial}{\partial x} & \dfrac{\partial}{\partial y} & \dfrac{\partial}{\partial z} \\[4pt] F_x & F_y & F_z \end{vmatrix} \end{equation} $$
第1行に沿って余因子展開すると:
$$ \begin{align} \nabla \times \bm{F} &= \bm{e}_x \left(\frac{\partial F_z}{\partial y} – \frac{\partial F_y}{\partial z}\right) – \bm{e}_y \left(\frac{\partial F_z}{\partial x} – \frac{\partial F_x}{\partial z}\right) + \bm{e}_z \left(\frac{\partial F_y}{\partial x} – \frac{\partial F_x}{\partial y}\right) \end{align} $$
2次元のスカラー回転
2次元ベクトル場 $\bm{F}(x, y) = (F_x, F_y)$ の場合、回転の $z$ 成分のみが意味を持ちます。
$$ (\nabla \times \bm{F})_z = \frac{\partial F_y}{\partial x} – \frac{\partial F_x}{\partial y} $$
これをスカラー量として扱い、スカラー回転 と呼ぶことがあります。
回転に関する重要な恒等式
勾配の回転は零
スカラー場 $f$ の勾配の回転は常に零ベクトルです。
$$ \begin{equation} \nabla \times (\nabla f) = \bm{0} \end{equation} $$
証明:
$$ \begin{align} [\nabla \times (\nabla f)]_x &= \frac{\partial}{\partial y}\frac{\partial f}{\partial z} – \frac{\partial}{\partial z}\frac{\partial f}{\partial y} = \frac{\partial^2 f}{\partial y \partial z} – \frac{\partial^2 f}{\partial z \partial y} = 0 \end{align} $$
$f$ が $C^2$ 級ならば偏微分の順序を交換できるので、各成分が $0$ になります。$y$, $z$ 成分も同様です。$\square$
回転の発散は零
ベクトル場 $\bm{F}$ の回転の発散は常に零です。
$$ \begin{equation} \nabla \cdot (\nabla \times \bm{F}) = 0 \end{equation} $$
証明:
$$ \begin{align} \nabla \cdot (\nabla \times \bm{F}) &= \frac{\partial}{\partial x}\left(\frac{\partial F_z}{\partial y} – \frac{\partial F_y}{\partial z}\right) + \frac{\partial}{\partial y}\left(\frac{\partial F_x}{\partial z} – \frac{\partial F_z}{\partial x}\right) + \frac{\partial}{\partial z}\left(\frac{\partial F_y}{\partial x} – \frac{\partial F_x}{\partial y}\right) \\ &= \frac{\partial^2 F_z}{\partial x \partial y} – \frac{\partial^2 F_y}{\partial x \partial z} + \frac{\partial^2 F_x}{\partial y \partial z} – \frac{\partial^2 F_z}{\partial y \partial x} + \frac{\partial^2 F_y}{\partial z \partial x} – \frac{\partial^2 F_x}{\partial z \partial y} \\ &= 0 \end{align} $$
偏微分の順序交換により、各項がペアとなって打ち消し合います。$\square$
ストークスの定理
定理
ストークスの定理は、線積分と面積分を結ぶ定理です。
曲面 $S$(法線ベクトル $\bm{n}$ 付き)の境界が閉曲線 $\partial S = C$ であるとき:
$$ \begin{equation} \oint_C \bm{F} \cdot d\bm{r} = \iint_S (\nabla \times \bm{F}) \cdot d\bm{S} \end{equation} $$
ここで $C$ の向きと $\bm{n}$ の向きは右ねじの関係にあります。
定理の意味
左辺は「閉曲線 $C$ に沿った $\bm{F}$ の循環」です。右辺は「$C$ を縁に持つ曲面上での回転の面積分(通過する渦の総量)」です。
つまり、閉曲線に沿った循環は、その内部の渦の強さの合計に等しい ということです。
ガウスの発散定理との対比
| ガウスの発散定理 | ストークスの定理 | |
|---|---|---|
| 結ぶ関係 | 体積分 ↔ 面積分 | 面積分 ↔ 線積分 |
| 微分演算子 | 発散 $\nabla \cdot \bm{F}$ | 回転 $\nabla \times \bm{F}$ |
| 境界 | 閉曲面 $\partial V$ | 閉曲線 $\partial S$ |
保存場
定義
ベクトル場 $\bm{F}$ が 保存場(conservative field)であるとは、あるスカラー場 $\phi$ が存在して:
$$ \bm{F} = \nabla \phi $$
と書けることです。$\phi$ を $\bm{F}$ の スカラーポテンシャル と呼びます。
保存場の同値条件
単連結な領域では、以下は同値です。
(1) $\bm{F} = \nabla \phi$ となるスカラー場 $\phi$ が存在する
(2) $\nabla \times \bm{F} = \bm{0}$(渦なし)
(3) 任意の閉曲線 $C$ に対して $\oint_C \bm{F} \cdot d\bm{r} = 0$
(1) → (2): $\nabla \times (\nabla \phi) = \bm{0}$(先述の恒等式)
(2) → (3): ストークスの定理より $\oint_C \bm{F} \cdot d\bm{r} = \iint_S (\nabla \times \bm{F}) \cdot d\bm{S} = 0$
(3) → (1): 線積分が経路に依存しないので、ポテンシャルを $\phi(\bm{r}) = \int_{\bm{r}_0}^{\bm{r}} \bm{F} \cdot d\bm{r}’$ で定義できます。
具体例
例1: 回転場 $\bm{F} = (-y, x, 0)$
$$ \nabla \times \bm{F} = \begin{vmatrix} \bm{e}_x & \bm{e}_y & \bm{e}_z \\ \frac{\partial}{\partial x} & \frac{\partial}{\partial y} & \frac{\partial}{\partial z} \\ -y & x & 0 \end{vmatrix} $$
$$ \begin{align} (\nabla \times \bm{F})_x &= \frac{\partial 0}{\partial y} – \frac{\partial x}{\partial z} = 0 \\ (\nabla \times \bm{F})_y &= \frac{\partial(-y)}{\partial z} – \frac{\partial 0}{\partial x} = 0 \\ (\nabla \times \bm{F})_z &= \frac{\partial x}{\partial x} – \frac{\partial(-y)}{\partial y} = 1 + 1 = 2 \end{align} $$
$$ \nabla \times \bm{F} = (0, 0, 2) = 2\bm{e}_z $$
一様に $z$ 軸方向に回転しています。
例2: 保存場 $\bm{F} = (2xy, x^2, 0)$
$$ \begin{align} (\nabla \times \bm{F})_z &= \frac{\partial(x^2)}{\partial x} – \frac{\partial(2xy)}{\partial y} = 2x – 2x = 0 \end{align} $$
他の成分も $0$ なので $\nabla \times \bm{F} = \bm{0}$ です。ポテンシャルは $\phi = x^2 y$ です($\nabla(x^2 y) = (2xy, x^2, 0) = \bm{F}$)。
例3: 剛体回転 $\bm{F} = \bm{\omega} \times \bm{r}$
角速度 $\bm{\omega} = (0, 0, \omega)$ で回転する剛体の速度場は:
$$ \bm{F} = \bm{\omega} \times \bm{r} = (-\omega y, \omega x, 0) $$
回転は:
$$ \nabla \times \bm{F} = (0, 0, 2\omega) = 2\bm{\omega} $$
流体力学では、この $\nabla \times \bm{v}$ を 渦度(vorticity)$\bm{\omega}_v$ と呼びます。渦度は角速度の2倍に等しいです。
Pythonでの実装
回転の数値計算
import numpy as np
def curl_2d(Fx, Fy, dx, dy):
"""
2次元ベクトル場のスカラー回転(z成分)を数値計算する
Parameters
----------
Fx, Fy : ndarray, shape (ny, nx)
ベクトル場の x, y 成分
dx, dy : float
格子間隔
Returns
-------
ndarray, shape (ny, nx)
回転の z 成分(スカラー)
"""
dFy_dx = np.gradient(Fy, dx, axis=1)
dFx_dy = np.gradient(Fx, dy, axis=0)
return dFy_dx - dFx_dy
# テスト: F = (-y, x) → curl F = 2
x = np.linspace(-3, 3, 100)
y = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x, y)
dx = x[1] - x[0]
dy = y[1] - y[0]
Fx = -Y
Fy = X
curl_z = curl_2d(Fx, Fy, dx, dy)
print(f"F = (-y, x)")
print(f"解析的な curl F (z成分) = 2")
print(f"数値的な curl F (mean) = {curl_z.mean():.6f}")
回転の可視化
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-3, 3, 200)
y = np.linspace(-3, 3, 200)
X, Y = np.meshgrid(x, y)
dx = x[1] - x[0]
dy = y[1] - y[0]
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
skip = 15
# --- 例1: 回転場 F = (-y, x)(一様な回転)---
ax = axes[0, 0]
Fx, Fy = -Y, X
curl_z = curl_2d(Fx, Fy, dx, dy)
contour = ax.contourf(X, Y, curl_z, levels=20, cmap='RdBu_r', alpha=0.7)
plt.colorbar(contour, ax=ax, label='$\\mathrm{curl}_z$')
ax.quiver(X[::skip, ::skip], Y[::skip, ::skip],
Fx[::skip, ::skip], Fy[::skip, ::skip],
color='black', scale=40, width=0.003)
ax.set_title('$\\mathbf{F} = (-y, x)$: $\\mathrm{curl}_z = 2$')
ax.set_xlabel('$x$')
ax.set_ylabel('$y$')
ax.set_aspect('equal')
# --- 例2: 保存場 F = (2xy, x^2)(curl = 0)---
ax = axes[0, 1]
Fx = 2*X*Y
Fy = X**2
curl_z = curl_2d(Fx, Fy, dx, dy)
contour = ax.contourf(X, Y, curl_z, levels=20, cmap='RdBu_r', alpha=0.7)
plt.colorbar(contour, ax=ax, label='$\\mathrm{curl}_z$')
ax.quiver(X[::skip, ::skip], Y[::skip, ::skip],
Fx[::skip, ::skip], Fy[::skip, ::skip],
color='black', scale=80, width=0.003)
ax.set_title('$\\mathbf{F} = (2xy, x^2)$: $\\mathrm{curl}_z = 0$ (Conservative)')
ax.set_xlabel('$x$')
ax.set_ylabel('$y$')
ax.set_aspect('equal')
# --- 例3: せん断流 F = (y, 0)(一方向だけの回転)---
ax = axes[1, 0]
Fx = Y
Fy = np.zeros_like(X)
curl_z = curl_2d(Fx, Fy, dx, dy)
contour = ax.contourf(X, Y, curl_z, levels=20, cmap='RdBu_r', alpha=0.7)
plt.colorbar(contour, ax=ax, label='$\\mathrm{curl}_z$')
ax.quiver(X[::skip, ::skip], Y[::skip, ::skip],
Fx[::skip, ::skip], Fy[::skip, ::skip],
color='black', scale=30, width=0.003)
ax.set_title('$\\mathbf{F} = (y, 0)$: $\\mathrm{curl}_z = -1$ (Shear)')
ax.set_xlabel('$x$')
ax.set_ylabel('$y$')
ax.set_aspect('equal')
# --- 例4: 空間依存の回転 F = (-y^2, x^2) ---
ax = axes[1, 1]
Fx = -Y**2
Fy = X**2
curl_z = curl_2d(Fx, Fy, dx, dy)
contour = ax.contourf(X, Y, curl_z, levels=20, cmap='RdBu_r', alpha=0.7)
plt.colorbar(contour, ax=ax, label='$\\mathrm{curl}_z$')
ax.quiver(X[::skip, ::skip], Y[::skip, ::skip],
Fx[::skip, ::skip], Fy[::skip, ::skip],
color='black', scale=80, width=0.003)
ax.set_title('$\\mathbf{F} = (-y^2, x^2)$: $\\mathrm{curl}_z = 2x + 2y$')
ax.set_xlabel('$x$')
ax.set_ylabel('$y$')
ax.set_aspect('equal')
plt.tight_layout()
plt.savefig("curl_examples.png", dpi=150, bbox_inches='tight')
plt.show()
ストークスの定理の数値検証
import numpy as np
# ストークスの定理の数値検証
# F = (-y, x, 0) について、xy平面の単位円で検証
# 右辺: 面積分 ∫∫ (∇×F)·dS
# ∇×F = (0, 0, 2), dS = (0, 0, 1)dA → ∫∫ 2 dA = 2π (単位円の面積πに2を掛ける)
N = 1000
r_vals = np.linspace(0, 1, N)
theta_vals = np.linspace(0, 2*np.pi, N)
R, THETA = np.meshgrid(r_vals, theta_vals)
dr = r_vals[1] - r_vals[0]
dtheta = theta_vals[1] - theta_vals[0]
# 面積分(極座標で)
curl_z = 2.0 # 一様
surface_integral = np.sum(curl_z * R * dr * dtheta)
print(f"面積分(右辺): {surface_integral:.6f}")
# 左辺: 線積分 ∮ F · dr
# 単位円上: x = cosθ, y = sinθ, dx = -sinθ dθ, dy = cosθ dθ
# F = (-sinθ, cosθ), dr = (-sinθ, cosθ)dθ
# F · dr = sin²θ + cos²θ = 1 → ∮ 1 dθ = 2π
theta = np.linspace(0, 2*np.pi, 10000)
dtheta = theta[1] - theta[0]
x = np.cos(theta)
y = np.sin(theta)
Fx = -y # -sinθ
Fy = x # cosθ
dx_dt = -np.sin(theta) # dx/dθ
dy_dt = np.cos(theta) # dy/dθ
line_integral = np.sum(Fx * dx_dt + Fy * dy_dt) * dtheta
print(f"線積分(左辺): {line_integral:.6f}")
print(f"解析解: {2*np.pi:.6f}")
print(f"一致: {np.isclose(surface_integral, line_integral, atol=0.01)}")
保存場の判定
import numpy as np
def is_conservative_2d(Fx_func, Fy_func, x_range, y_range, N=100, tol=1e-6):
"""
2次元ベクトル場が保存場かどうかを数値的に判定する
Parameters
----------
Fx_func, Fy_func : callable
ベクトル場の x, y 成分の関数
x_range, y_range : tuple
(min, max)
N : int
格子点数
tol : float
判定のしきい値
Returns
-------
bool
"""
x = np.linspace(*x_range, N)
y = np.linspace(*y_range, N)
X, Y = np.meshgrid(x, y)
dx = x[1] - x[0]
dy = y[1] - y[0]
Fx = Fx_func(X, Y)
Fy = Fy_func(X, Y)
curl_z = curl_2d(Fx, Fy, dx, dy)
max_curl = np.max(np.abs(curl_z))
return max_curl < tol, max_curl
# テスト1: 保存場 F = (2xy, x^2)
is_cons, max_c = is_conservative_2d(
lambda X, Y: 2*X*Y,
lambda X, Y: X**2,
(-3, 3), (-3, 3)
)
print(f"F = (2xy, x^2): 保存場={is_cons}, max|curl|={max_c:.2e}")
# テスト2: 非保存場 F = (-y, x)
is_cons, max_c = is_conservative_2d(
lambda X, Y: -Y,
lambda X, Y: X,
(-3, 3), (-3, 3)
)
print(f"F = (-y, x): 保存場={is_cons}, max|curl|={max_c:.2e}")
# テスト3: 保存場 F = (y + 2x, x + 3y^2)
is_cons, max_c = is_conservative_2d(
lambda X, Y: Y + 2*X,
lambda X, Y: X + 3*Y**2,
(-3, 3), (-3, 3)
)
print(f"F = (y+2x, x+3y^2): 保存場={is_cons}, max|curl|={max_c:.2e}")
まとめ
本記事では、回転(rot/curl)の定義と意味を解説しました。
- 回転 $\nabla \times \bm{F}$ は各点での 渦の強さと方向 を表すベクトル場である
- 行列式の形式で覚えると便利: $\nabla \times \bm{F} = \det(\bm{e}, \nabla, \bm{F})$
- ストークスの定理: 閉曲線に沿った循環 = 内部の回転の面積分
- 勾配の回転は零: $\nabla \times (\nabla f) = \bm{0}$(保存場は渦なし)
- 回転の発散は零: $\nabla \cdot (\nabla \times \bm{F}) = 0$
- $\nabla \times \bm{F} = \bm{0}$ は $\bm{F}$ が保存場であるための必要十分条件(単連結領域の場合)
次のステップとして、以下の記事も参考にしてください。