HOME > natural science Laboratory > コンピュータ・シミュレーション講座 > TIPS 集

メトロポリス法を用いた、カノニカル集団の計算(3次元)

文責:遠藤 理平 (2009年3月28日) カテゴリ:TIPS 集(104)

前回は、簡単のために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.静的構造因子の計算
を行う。



▲このページのトップNPO法人 natural science トップ

▲このページのトップNPO法人 natural science トップ