周期边界条件下Verlet算法MD模拟的逃逸能量 我试图在C++中编写一个非常基本的MD仿真代码,用于在具有周期性边界条件的30x30x30盒中的125个粒子系统。我已经成功地初始化了盒子,但是每当我在多个时间步上运行代码时,对于某些粒子,能量会爆炸,位置
周期边界条件下Verlet算法MD模拟的逃逸能量 我试图在C++中编写一个非常基本的MD仿真代码,用于在具有周期性边界条件的30x30x30盒中的125个粒子系统。我已经成功地初始化了盒子,但是每当我在多个时间步上运行代码时,对于某些粒子,能量会爆炸,位置不会落在盒子内。我相当肯定这是一个周期性边界条件的问题,但我不能弄清楚问题是什么。我已在下面附上我的代码,如有任何建议,我将不胜感激。谢谢周期边界条件下Verlet算法MD模拟的逃逸能量 我试图在C++中编写一个非常基本的MD仿真代码,用于在具有周期性边界条件的30x30x30盒中的125个粒子系统。我已经成功地初始化了盒子,但是每当我在多个时间步上运行代码时,对于某些粒子,能量会爆炸,位置,c++,C++,周期边界条件下Verlet算法MD模拟的逃逸能量 我试图在C++中编写一个非常基本的MD仿真代码,用于在具有周期性边界条件的30x30x30盒中的125个粒子系统。我已经成功地初始化了盒子,但是每当我在多个时间步上运行代码时,对于某些粒子,能量会爆炸,位置不会落在盒子内。我相当肯定这是一个周期性边界条件的问题,但我不能弄清楚问题是什么。我已在下面附上我的代码,如有任何建议,我将不胜感激。谢谢 /***************************************************
/******************************************************************************************************************************************
* Program:
* Create MD simulation for small system of particles
******************************************************************************************************************************************/
//include
#include <fstream>
#include <vector>
#include <math.h>
#include <stdlib.h>
#include <cstring>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
int N; //number of particles
int l; //length of box
double T; //temp
double dt; //time step
double m; //mass
int nsteps; //number of time steps
//properties of lj potential
double sigma;
double rcut;
double ecut;
double ep;
double K; //kinetic energy of system
double Kp; //I have a time delay in the KE calculation so I need to store the value
double energy; //energy
//vector with position data
std::vector<std::vector<double> > r;
//vector with previous position data
std::vector<std::vector<double> > rp;
//vector with velocity data
std::vector<std::vector<double> > v;
//vector with force data
std::vector<std::vector<double> > f;
//vector with acceleration data
std::vector<std::vector<double> > a;
//vector to store position difference between two steps
std::vector<std::vector<double> > dr2t;
void init_pos(int l, int N);
void init_vel(int N, double T, double dt);
void force(int N, double dt);
void accel(double m);
void integrate(double dt);
void vel(double dt);
int main () {
// simulation parameters
N = 125;
l = 30;
T = 0.3;
dt = 0.001;
m = 1;
nsteps = 501;
//properties of lj potential
sigma = 1;
rcut = 3.5*sigma;
ep = 1;
ecut = 4*ep*(pow((sigma/rcut),12.0) - pow((sigma/rcut),6.0));
//initialize the positions and velocities
init_pos(l,N);
init_vel(N,T,dt);
//open file to store positions
FILE * out_pos;
out_pos = fopen("Shea_positions.dat", "w");
//open file to store energy info
FILE * out_en;
out_en = fopen("Shea_energy.dat", "w");
//header in pos file for time step 0
fprintf(out_pos, "%d \n", N);
fprintf(out_pos, "Time Step: 0 \n");
//print positions of each particle
for(int i=0; i<N; i++) {
fprintf(out_pos, "%d %f %f %f\n", i, r[i][0], r[i][1], r[i][2]);
}
//time loop to perform multiple steps
for (int t=1; t<nsteps; t++) {
//header in file for each time step
//fprintf(out_pos, "\n");
fprintf(out_pos, "%d \n", N);
fprintf(out_pos, "Time Step: \t%d \n", t);
Kp = K; //kinetic energy of system at current time step (calculated in next time step after initialization)
//perform calculations at each time step
force(N, dt);
accel(m);
integrate(dt);
vel(dt);
//print positions of each particle
for(int i=0; i<N; i++) {
fprintf(out_pos, "%d %f %f %f\n", i, r[i][0], r[i][1], r[i][2]);
}
//output to energy file
fprintf(out_en, "%d %f %f %f\n", t-1, energy, Kp, energy+Kp);
}
fclose(out_pos);
fclose(out_en);
}
/*********************************************************************************************************************************/
//function to initialize positions
void init_pos(int l, int N) {
int n = (int) cbrt(N); //number of particles in row
int a = 1; //lattice spacing
r.resize(N, std::vector<double>(3, 0));
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
for (int k=0; k<n; k++) {
int num_part = i*n*n+j*n+k;
r[num_part][0] = i*a-n/2*a;
r[num_part][1] = j*a-n/2*a;
r[num_part][2] = k*a-n/2*a;
}
}
}
}
/*********************************************************************************************************************************/
//function to initialize velocities
void init_vel(int N, double T, double dt) {
int RANDMAX=10000;
rp.resize(N, std::vector<double>(3, 0));
v.resize(N, std::vector<double>(3, 0));
std::vector<double> vcom(3, 0);
double sumv2 = 0;
K=0; //initialize kinetic energy at 0
for (int i=0; i<N; i++) {
for (int alpha=0; alpha<3; alpha++) {
v[i][alpha] = ((double)(rand() % RANDMAX) / RANDMAX)-0.5; //assign random velocities from -0.5 to 0.5
vcom[alpha] += v[i][alpha]; //calculate the com velocity
sumv2 += v[i][alpha]*v[i][alpha];
}
}
for (int alpha=0; alpha<3; alpha++) {
vcom[alpha] /= N; //translational velocity of system to remove
}
sumv2 = sumv2/N; //average KE per particle
double sf = sqrt(3*T/(sumv2)); //scaling factor
for (int i=0; i<N; i++) {
for (int alpha=0; alpha<3; alpha++) {
v[i][alpha] -= vcom[alpha]; //correct for com velocity
v[i][alpha] *= sf; //multiply by scaling factor to give the correct temp
rp[i][alpha] = r[i][alpha] - v[i][alpha]*dt; //calculate the previous position
}
K += 0.5*m*(v[i][0]*v[i][0]+v[i][1]*v[i][1]+v[i][2]*v[i][2]); //find total kinetic energy of the system
}
}
/*********************************************************************************************************************************/
//calculate force on each particle from the lj potential
void force(int N, double dt) {
f.resize(N, std::vector<double>(3, 0));
energy = 0.;
std::vector<double> dr(3, 0);
double dr2;
for (int i=0; i<N; i++) {
for (int j=0; j<i; j++) {
//calculate distance vector between two particles
dr[0] = r[i][0]-r[j][0];
dr[1] = r[i][1]-r[j][1];
dr[2] = r[i][2]-r[j][2];
//make sure pbc works by taking minimum dist between particles i and j
dr[0] -= l*round(dr[0]/l);
dr[1] -= l*round(dr[1]/l);
dr[2] -= l*round(dr[2]/l);
dr2 = dr[0]*dr[0] + dr[1]*dr[1] + dr[2]*dr[2]; //distance between particles i and j squared
if(dr2<rcut*rcut) {
double invr2 = 1./dr2;
double invr6 = invr2*invr2*invr2;
double ff = 48.* invr2*invr6*(invr6-0.5); //modulus of the force on a particle
//add force to particle i
f[i][0] += ff*dr[0];
f[i][1] += ff*dr[1];
f[i][2] += ff*dr[2];
//add equal and oppostie force to particle j
f[j][0] -= ff*dr[0];
f[j][1] -= ff*dr[1];
f[j][2] -= ff*dr[2];
//calculate the potential energy of the particle
energy += 4*invr6*(invr6-1)-ecut;
}
}
}
}
/*********************************************************************************************************************************/
//calculate the acceleration of the particle from the force
void accel(double m) {
a.resize(N, std::vector<double>(3, 0));
for (int i=0; i<N; i++) {
for (int alpha=0; alpha<3; alpha++) {
a[i][alpha] = f[i][alpha]/m;
}
}
}
/*********************************************************************************************************************************/
//integrate to get the new position of the particle after one time step
void integrate(double dt) {
dr2t.resize(N, std::vector<double>(3, 0));
for (int i=0; i<N; i++) {
for (int alpha=0; alpha<3; alpha++) {
double rr = 2*r[i][alpha] - rp[i][alpha] + dt*dt*a[i][alpha]; //new pos from velocity verlet alg
printf("%f %f %f \n", rr,r[i][alpha],rp[i][alpha]);
//printf("%f \n", a[i][alpha]);
if (rr >= l/2) {
rr -= l;
}
if (rr < -l/2) {
rr += l;
}
dr2t[i][alpha] = rr - rp[i][alpha]; //difference between new position and previous position so you can find velocity
dr2t[i][alpha] -= l*round(dr2t[i][alpha]/l);
rp[i][alpha] = r[i][alpha]; //current position becomes previous position
r[i][alpha] = rr; //new position becomes current positions
}
}
}
/*********************************************************************************************************************************/
//velocity
void vel(double dt) {
K = 0;
for (int i=0; i<N; i++) {
for (int alpha=0; alpha<3; alpha++) {
//printf("%f %f %f \n", dr2t[i][0], dr2t[i][1], dr2t[i][2]);
v[i][alpha] = dr2t[i][alpha]/(2*dt);
}
K += 0.5*m*(v[i][0]*v[i][0]+v[i][1]*v[i][1]+v[i][2]*v[i][2]);
}
}
/*********************************************************************************************************************************/
/******************************************************************************************************************************************
*节目:
*为小粒子系统创建MD模拟
******************************************************************************************************************************************/
//包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int N//粒子数
int l//箱长
双T//临时雇员
双dt//时间步长
双m//大量
int nsteps//时间步数
//lj势的性质
双西格玛;
双rcut;
双ecut;
双ep;
双K//系统动能
双Kp//我在KE计算中有一个时间延迟,所以我需要存储该值
双能量//能量
//带位置数据的向量
std::向量r;
//具有先前位置数据的向量
std::向量rp;
//带速度数据的矢量
std::向量v;
//带有力数据的向量
std::向量f;
//带加速度数据的矢量
std::载体a;
//用于存储两个步骤之间的位置差的向量
std::载体dr2t;
无效初始位置(整数l,整数N);
无效初始值(整数N,双T,双dt);
空隙力(int N,双dt);
真空加速(双m);
虚积分(双dt);
无效水平(双dt);
int main(){
//模拟参数
N=125;
l=30;
T=0.3;
dt=0.001;
m=1;
nsteps=501;
//lj势的性质
西格玛=1;
rcut=3.5*西格玛;
ep=1;
ecut=4*ep*(功率((sigma/rcut),12.0)-功率((sigma/rcut),6.0);
//初始化位置和速度
初始位置(l,N);
初始水平(N,T,dt);
//打开文件以存储位置
文件*输出位置;
out_pos=fopen(“Shea_positions.dat”、“w”);
//打开文件以存储能量信息
文件*out_en;
out_en=fopen(“Shea_energy.dat”,“w”);
//时间步长0的pos文件中的标头
fprintf(输出位置,“%d\n”,n);
fprintf(out_pos,“时间步长:0\n”);
//打印每个粒子的位置
对于(int i=0;i问题通常是浮点物理不精确,小错误会累积。可以使用缩放整数,也可以添加一个小阻尼因子。一种诊断方法是检查每个粒子总能量的百分比。如果只有一个粒子增长,则输出值并调试它。如果所有粒子都有规律地增长,则只需对其进行归一化和调整通过相同的因子使总能量保持不变。问题是你的势是奇异的。Verlet方法只有在势是光滑的情况下才能很好地工作。因此,每当两个粒子非常接近时,能量就会发生无法形容的事情。在某种程度上,这可以通过减小步长来减少,但一般问题仍然存在s