🎃

プログラミングにおける周期的境界条件

2024/06/21に公開

はじめに

プログラミングにおける周期的境界条件は少し厄介なので備忘録もかねてまとめた。
使用言語はJuliaだが、ChatGPTでも使って好きな言語に書き換えて欲しい。

序章

周期的境界条件

よく物理のテキストでみる周期的境界条件は次の形である:
f(x) = f(x + c).
ここで、c は定数である。
物理的には、c だけ平行移動したところも同じものとして扱っている。

シミュレーションでの例

これを、1次元のシュミレーションで考えてみよう。
システムを x \in [0,a] に制限し周期的境界条件を適用すると、a=c となる。x>a であれば、xx-a に置き直せばよいし、x<0 なら、x+a に置き直せば良い。単に、システムの中に置き直しているだけである。

  • 注意
    正確には x=0x=a は周期的境界条件から同じものになる。そのため、x \in [0,a) または x\in(0,a] にする必要がある。

具体例

具体的な数値で考えてみよう。上の設定で、a=1 として粒子の位置を考えてみよう。粒子の座標が x=1.5 というのは、x=0.5 と同じことである。また、x=-0.2x = 0.8 と同じになる。
(これはかつてのRPGでずっと右に行き続けると、左から出てくることと同じである。)
実際に、シミュレーションをしてみよう。今回は x \in [-1,2] となっているものを、システムを[0,1]にして、周期的境界条件を適用する。

[-1,2]の運動
using Plots
anim =@animate for t in -1.0:0.1:2.0
    scatter([t], [0], label = "t = $t", ylims = (-1, 1), xlims = (-2, 2))
end
gif(anim, "anim.gif", fps = 10)

周期的境界条件の適用
function periodic_boundary_conditions(x, L) # x: 位置, L: 系の長さ
    if x > L
        x -= L # x = x - L と同じ
    elseif x < 0
        x += L # x = x + L と同じ
    end
    return x
end

anim =@animate for t in -1.0:0.1:2.0
    scatter([periodic_boundary_conditions(t, 1)], [0], label = "t = $t", ylims = (-1, 1), xlims = (-2, 3))
end

gif(anim, "anim_periodic_boundary_conditions.gif", fps = 10)


期待していた x \in [0,1] が得られた。(当然、tの範囲は同じにしてある。インチキをしているわけではない!!。念の為。)

2次元の場合

それぞれの軸で1次元でやったものを行えば良い。すなわち、x \in [0,L_x], y \in [0,L_y]であれば、

function 2D_PBCs(x,y,Lx,Ly) #x,y:粒子のx,y座標. Lx, Ly:x,yそれぞれの系の長さ
    if x > L
        x -= Lx # x = x - L と同じ
    elseif x < 0
        x += Lx # x = x + L と同じ
    end
    if y > Ly
        y -= Ly
    elseif y < 0
        y += Ly
    return x,y
end

任意のシステムサイズの場合

英語版の周期的境界条件のwiki https://en.wikipedia.org/wiki/Periodic_boundary_conditions に書いてある。 "Practical implementation: continuity and the minimum image convention" という節を参照すること。
(英語読めないよって人は google 翻訳とか DeepL とか AI を使えばよい。)

多粒子の場合

粒子が N 個の場合はそれぞれの粒子 x_1, x_2, \cdots, x_N について周期的境界条件を適用すれば良い。

本章

序章では、粒子の位置をシステムの中に引き戻す方法を述べた。上の操作だけでよいのだろうか?
実は、例えば、粒子間距離に依存する力が働くときは上の状況だけでは上手くいかない。

相互作用があるときの周期的境界条件

簡単のため、2粒子系を考え、システムを [0,1] と制限して考えよう。さらに、相互作用は重力とする。すなわち、2粒子間の距離の2乗に反比例すると仮定する。粒子が下図のような配置のとき、粒子が感じる力はどのようになるだろうか。ただし、粒子の位置はそれぞれ x_1 = 0.1, x_2 = 0.9 とした(左側の粒子を粒子1、右側を粒子2とし、下付きインデックスで表した。)

この場合は、2粒子間の距離 r = 0.8 になると考えたくなる。しかし、最初に述べた通り、周期的境界条件というのは「平行移動したところも同じものとして扱う」というものだった。ということは、x_2 = -0.1 (0.9-1) とみなせることになる。こっちを採用するのであれば、2粒子間の距離は x_1-(1-x_2) = 0.3 となり、重力は前者の場合よりも圧倒的に大きくなる。


私達はどちらを採用すべきなのだろうか?
何度も繰り返すが、周期的境界条件というのは平行移動したところも同じとみなせるものであった。これは、同じ系を(1次元の場合は)右と左に張り合わせたものである^{*1}。ということは、後者を採用すべきだ。言い換えれば、粒子間距離 r が最小となるような物を選ぶべきである。

次に、力の向きについて考えよう。周期的境界条件を考えないときは粒子1に働く力は x 軸正の向きだった。しかし、周期的境界条件を考え、x_2 = -0.1 にすると、粒子1に働く力は x 軸負の向きになる。この力の向きは正負を考えてあげれば簡単に解決する。

まとめると今回の場合は次のようになる。r を周期的境界条件を適用しないときの粒子間の距離とする。

  1. r > 0.5 ならば rr-1 にする(ベクトルの向きも入れてある)。
  2. r < -0.5 ならば rr+1 にする。
  3. それ以外は何もしない。
    プログラミングのコードで書けば、
粒子間距離に対する周期的境界条件
r = x1 - x2 # x1, x2 はそれぞれの粒子の位置
if r > 0.5 # 系のサイズを1とした。
    r -= 1. # 1. は 1.0 の省略記法
elseif r < -0.5
    r += 1.
end

これを一般化すれば、周期的境界条件の英語版 wiki(上記リンク)にあった(B)が得られる。

多次元の場合

例えば、2次元であれば x, y 座標それぞれに適用すればよい。3次元も同様。

結論

シミュレーションにおける周期的境界条件で大事なことは次の2つになる。

  1. 粒子の位置に適用すること。
  2. 粒子間距離に適用すること。

実装するためのコードは次のようになる。(英語版 wiki のコードを Julia で書き換えただけ。)

粒子の位置に適用
if x < -L / 2 # L:システムサイズ, x: 粒子の位置
    x -= L
elseif x > L / 2
    x += L
end
粒子間距離に適用
r = x1 - x2 # x1, x2: 粒子 1, 2 の位置
if r > L / 2
    r -= L
elseif r < - L / 2
    r += L
end

今後の予定

周期的境界条件の具体例は書いていないので、2次元で相互作用を重力ポテンシャルにしたときの多体運動のコードを書く予定(予定は未定)。
2024年6月21日追記
https://zenn.dev/phlogis/articles/a2f5fea4e3d4f8

補足

*1 について

張り合わせたものというのは、f(x)=x^2, x \in [-1,2] のグラフを使って見るとわかる。周期的境界条件なしでは下図となる。

一方、境界条件を適用し x\in[0,1] とすると、[-1,0], [1,2][0,1] を張り合わせたものになっていることがわかる。(下図)

P.S.
インチキではないことの証明として上の画像のソースコードをおいておく。

周期的境界条件なし
f(x) = x^2
plot(f, -1, 2, label = "f(x) = x^2", xlabel = "x", ylabel = "f(x)")
周期的境界条件あり
f(x) = x^2
x = [i for i in -1:0.01:2]
x_PBCs = [PBCs(i, 1) for i in x] # PBCsは一番最初にかいた自作関数と同じ
y = f.(x_PBCs)
plot(x, y, label = "f(x) = x^2", xlabel = "x", ylabel = "f(x)")

参考文献

  1. https://en.wikipedia.org/wiki/Periodic_boundary_conditions

Discussion