メトロポリス法を用いた、カノニカル集団の計算(3次元)
前回は、簡単のために1次元の場合の計算プログラムを実行したが、今回は3次元の場合を考える。
境界付近の粒子の取り扱い方については、境界に近い粒子(r_c<3、単位は粒子の直径)に、
隣のイメージセルからの影響をカウントするということで、周期的境界条件を課すという方法をとった。
今回は、力の切断距離を次のように導入する。
rx_c = L/2 , ry_c = L/2 , rz_c = L/2
これは、2粒子間の距離の3成分のうちどれかが L/2 を超えたときに、
その粒子との相互作用を無視して、その代わりにイメージセル内にある粒子からの相互作用をカウントする(下図)。
周期的境界条件を課したとき、イメージセルからの作用の模式図
これは、レナード・ジョーンズ・ポテンシャルのような、弱い引力(r^{-7})の場合には正当化される。
VisualC++ プログラムソース
2000モンテカルロステップの後(平衡状態)、1000ステップ分をサンプルする。
粒子数 N=100(一定)
粒子数密度 rho = 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001 (rho=N/V)
温度 T = 0.00001, 0.0001, 0.001, 0.01, 0.1, 1.0, 10, 100, 1000, 10000
セルの一辺 L = V^{1/3} = (rho/N)^{1/3}
/* メトロポリス法を用いた、カノニカル集団の計算(3次元) ポテンシャル:レナード・ジョーンズポテンシャル */ /* メトロポリス(3次元) */ #include <math.h> #include <stdlib.h> #include <time.h> #include <fstream> #include <iostream> #include <sstream> #include <string> #include "mt19937ar.h" #include <cstdio> #include <iomanip> #include <stdio.h> using namespace std; double PI = 3.1415926535897932384; double e = 2.7182818284590452354; // 関数のプロトタイプ宣言 double phi_LJ( double r1_0, double r1_1, double r1_2, double r2_0, double r2_1, double r2_2, double L); int main(){ init_genrand((unsigned)time(NULL)); int N = 100, monte_time=3000, t_0=2000; double R[100][3] = {0.0}; double sigma = 1.0, L,T,rho,v,dl; double U_i=0.0, U_k= 0.0; v = 4.0 / 3.0 * PI * pow(sigma, 3); for(int rho_step=5 ; rho_step >= 0 ; rho_step--){ rho = pow(10.0, -1.0 * double(rho_step)); dl = pow(1.0/rho,1.0/3.0); L = pow(N/rho,1.0/3.0); for(int T_step=0 ; T_step <= 10 ; T_step++){ T = pow(10.0, double(T_step - 5)); for(int n=0; n<N; n++){ for(int jj=0; jj<3;jj++) R[n][jj] = L * genrand_real1(); } U_i = 0.0; //初期位置エネルギーの計算 for(int i=0; i<N-1; i++ ){ for(int j=i+1; j<N; j++ ){ U_i += 4.0 * phi_LJ(R[i][0],R[i][1],R[i][2],R[j][0],R[j][1],R[j][2],L); } } //モンテカルロ計算開始 for(int t=0; t<=monte_time;t++){ cout << rho << " " << T << "-" <<t << " potenshal=" << U_i <<endl; for(int n=0;n<N;n++){ double dx = dl/2.0 * (1.0 - 2.0 * genrand_real1()); double dy = dl/2.0 * (1.0 - 2.0 * genrand_real1()); double dz = dl/2.0 * (1.0 - 2.0 * genrand_real1()); R[n][0] += dx; R[n][1] += dy; R[n][2] += dz; if(R[n][0] > L) R[n][0] -= L; if(R[n][0] < 0) R[n][0] += L; if(R[n][1] > L) R[n][1] -= L; if(R[n][1] < 0) R[n][1] += L; if(R[n][2] > L) R[n][2] -= L; if(R[n][2] < 0) R[n][2] += L; U_k = 0.0; // ポテンシャルの計算 for(int i=0; i<N-1; i++ ){ for(int j=i+1; j<N; j++ ){ U_k += 4.0 * phi_LJ(R[i][0],R[i][1],R[i][2],R[j][0],R[j][1],R[j][2],L); } } if(U_i < U_k){ if(genrand_real1() > pow(e, -(U_k-U_i)/T)){ R[n][0] -= dx; R[n][1] -= dy; R[n][2] -= dz; if(R[n][0] > L) R[n][0] -= L; if(R[n][0] < 0) R[n][0] += L; if(R[n][1] > L) R[n][1] -= L; if(R[n][1] < 0) R[n][1] += L; if(R[n][2] > L) R[n][2] -= L; if(R[n][2] < 0) R[n][2] += L; } }else{ U_i = U_k; } } if(t>=t_0){ //粒子座標表示 ostringstream fname; fname << "data/position(" << rho_step << "-" << T_step << "-" << t-t_0 << ").data"; string fname2 = fname.str(); ofstream fout_position; fout_position.open(fname2.c_str()); for(int n=0; n<N; n++){ fout_position << R[n][0] << " " << R[n][1] << " " << R[n][2] << endl; } fout_position.close(); } } } } } double phi_LJ( double r1_0, double r1_1, double r1_2, double r2_0, double r2_1, double r2_2,double L){ double rx , ry , rz ,Lh; Lh = L/2.0; rx = r1_0 - r2_0; ry = r1_1 - r2_1; rz = r1_2 - r2_2; if(rx > Lh) rx -= L; if(rx < -Lh) rx += L; if(ry > Lh) ry -= L; if(ry < -Lh) ry += L; if(rz > Lh) rz -= L; if(rz < -Lh) rz += L; double r2 = pow(rx,2) + pow(ry,2) + pow(rz,2) ; return pow(1.0/r2,6) - pow(1.0/r2,3) ; }
今後の予定
計算結果を用いて、
1.動径分布関数の計算
2.圧力の計算
3.静的構造因子の計算
を行う。