首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >分子动力学模拟中的势能计算

分子动力学模拟中的势能计算
EN

Stack Overflow用户
提问于 2020-03-22 23:07:08
回答 1查看 118关注 0票数 0

背景

想象一下,我们在一个长度为L的盒子里有N个粒子,它们相互作用(通过Lennard Jones势)。

我想计算系统的总势能。我实现了POT函数,它计算所有粒子的所有贡献,并给出正确的结果(这是经过测试的,可以假设为真)。

我还写了一个函数POT_ONE,它只计算一个粒子相对于所有其他粒子的势能。这意味着,如果我想计算总势能,我必须调用这个函数N次(确保粒子不与自身相互作用),然后除以2,因为我重复计算了相互作用。

目标

我的目标是使第二个函数产生与第一个函数相同的结果。

问题

有一件事真的很奇怪:如果我放入4个粒子,两个函数会得到相同的结果。如果我放入第五个,那么就会有偏差。然后对于6,7,8个粒子,同样,它给出了正确的结果,然后对于N=9,我得到了不同的结果。在N=1000的例子中,我从POT_ONE得到的结果大概是113383820348202024。

我在N=5上的结果是: POT为0.003911,POT_ONE为12.864234

如果有人试图运行代码并想要检查N=4的情况,他/她应该更改定义为全局变量的粒子数(np),然后注释行pos[12]=1;pos[13]=1;pos[14]=1;

代码

代码语言:javascript
运行
复制
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

/*GENERAL PARAMETERS*/
int dim=3; //number of dimensions
int np=5; //number of particles
double L=36.413; //box length (A)
double invL=1/36.413; //inverse of box length

/*ARGON CHARACTERISTICS*/
double sig=3.4; // Angstroms (A)
double e=0.001; // eV


double distSQ(double array[]){
    /*calculates the squared distance given the array x=[dx,dy,dz]*/

    int i;
    double r2=0;
    for(i=0;i<dim;i++) r2+=array[i]*array[i];
    return r2;
}//distSQ

void MIC(double dr[],double L, int dim){
    /* MINIMUM IMAGE CONVENTION: dr[] is the array dr = [dx,dy,dz] describing relative
       positions of two particles, L is the box length, dim the number
       of dimensions */

    int i;
    for(i=0;i<dim;i++) dr[i]-=round(dr[i]*invL)*L;
}//MIC

void POT(double x1[],double* potential){
    /*given the positions of each particle in the form x=[x0,y0,z0;x1,y1,z1;...;xn-1,yn-1,zn-1],
      the number of dimensions dim and particles np, it calculates the potential energy of the configuration*/

    //variables for potential calculation
    int i,j,k;
    double *x2;
    double r2inv; // 1/r^2
    double foo,bar;
    double dr[dim];
    *potential=0; // set potential energy to zero

    //main part of POT
    for(i=0;i<np-1;i++){
        x2=x1+dim;
        for(j=i+1;j<np;j++){
                //calculate relative distances between particles i & j
                //apply periodic BCs and then calculate squared distance
                //and the potential energy between them.
                for(k=0;k<dim;k++) dr[k] = x2[k]-x1[k];
                MIC(dr,L,dim); //periodic boundary conditions
                r2inv=1/distSQ(dr);
                //calculate potential energy
                foo = sig*sig*r2inv;
                bar = foo*foo*foo;
                *potential+=bar*(bar-1);

        }//for j
    x1+=dim;
    }//for i
    *potential*=4*e; //scale and give energy units
}//POT

void POT_ONE(int particle,double pos[],double* potential){

    *potential=0;
    int i,k;
    double dr[dim];
    double r2inv,foo,bar;
    double par_pos[dim];
    int index=particle*dim;
    par_pos[0]=pos[index];
    par_pos[1]=pos[index+1];
    par_pos[2]=pos[index+2];

    for(i=0;i<np;i++){
        if(i!=particle){
            for(k=0;k<dim;k++) dr[k]=pos[k]-par_pos[k];
            MIC(dr,L,dim);
            r2inv=1/distSQ(dr);
            foo=sig*sig*r2inv;
            bar=foo*foo*foo;
            *potential+=bar*(bar-1);
        }
        pos+=dim;
    }
    *potential*=4*e; //scale and give energy units
}//POT_ONE

int main(){

    int D=np*dim;
    double* pos=malloc(D*sizeof(double));
    double potential=0; //calculated with POT
    double U=0; ////calculated with POT_ONE
    double tempU=0;
    pos[0]=0;pos[1]=0;pos[2]=0;
    pos[3]=4;pos[4]=0;pos[5]=0;
    pos[6]=0;pos[7]=4;pos[8]=0;
    pos[9]=0;pos[10]=0;pos[11]=4;
    pos[12]=1;pos[13]=1;pos[14]=1;

    POT(pos,&potential);
    printf("POT: %f\n", potential);

    int i,j;
    for(i=0;i<np;i++){
        POT_ONE(i,pos,&tempU);
        U+=tempU;
    }
    U=U/2;
    printf("POT_ONE: %f\n\n", U);

    return 0;
}
EN

回答 1

Stack Overflow用户

发布于 2020-03-22 23:56:22

您的错误出现在POT中,您在内部循环的末尾忘记更新x2

代码语言:javascript
运行
复制
for (i = 0; i < np - 1; i++) {
    double *x2 = x1 + dim;

    for (j = i + 1; j < np; j++) {
        // ... calculate stuff ..

        x2 += dim;
    }

    x1 += dim;
}

一种更简单、可读性更好的变体是完全放弃指针算法,使用无聊的旧索引:

代码语言:javascript
运行
复制
    for (k = 0; k < dim; k++) {
        dr[k] = x[j * dim + k] - x[i * dim + k];
    }

进一步的观察:

  • 请使您的变量位于使用它们的作用域的本地。函数顶部的大量未初始化变量使跟踪变量变得非常困难,即使在像您这样的短函数中也是如此。
  • 请考虑从函数中返回单个值,而不是传递指针。在我看来,这使得像距离的平方这样的函数更具可读性。
  • 你的代码的结构很难看清,因为所有的东西都非常紧密地运行在一起,即使是注释。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60800968

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档