如何在模拟有吸引力的粒子时添加硬球排斥?

时间:2017-12-01 15:49:42

标签: c++ c++11 simulation

我已经模拟了一个彼此吸引的二维粒子系统。吸引力取决于粒子之间的距离。边界条件和相互作用是周期性的。由于吸引力,粒子彼此相互聚集并聚集在一起。

我想添加硬球排斥力,这样,当两个或多个粒子聚集在同一个位置时,我希望它们分开连接它们的中心的线,直到它们不重叠。我怎么能这样做?

当存在吸引相互作用时添加硬球的情况比通常的情况更难,因为可能存在4个或更多颗粒处于相同位置的情况。

这是我的代码:

#include <iostream>
#include <math.h>
#include <vector>
#include <array>
#include <list>
#include <random>
#include <functional>
#include <fstream>
#include <string>
#include <sstream>
#include <algorithm>
#include <chrono>
#include <set>

using namespace std;

    std::minstd_rand gen(std::random_device{}());
    std::uniform_real_distribution<double> unirnd(0, 1);

double PBCtwo(double pos, double L)
    {
    if(pos > L / 2.0)
        return pos-L;
    else if (pos < -L /2.0)
        return L + pos;
    else
        return pos;
    }

// main function
int main()
{   long c = 0;
    int N=4000; 
    double rho, v0, tr,xr,l0, eta,dt, x[N],y[N],L=pow(N / rho , 0.5),l0_two = l0 * l0;
                rho = 2;
                v0 =300;eta = 1;dt = 0.0001;l0 = 1; c_prod = 500;c_display = 100;tr = -0.4;        
    // write initial configuration to the file
    ofstream configFile;
    configFile.open ("Initial Configuration.txt");
    configFile << to_string(N) << "\n";
    configFile << to_string(L) << "\n";
    for (int i = 0; i < N; i++)
    {   x[i] = unirnd(gen) * L;
        y[i] = unirnd(gen) * L;
        configFile << to_string(x[i]) << "\t" << to_string(y[i]) <<   "\n";
    }
    configFile.close();

    while (c < c_prod)
        {
        double dx[N], dy[N];
        c++;
        for(int i = 0; i < N; i++)
           {
            dx[i] = 0;
            dy[i] = 0;
            double S_try = 0.0, S_trx = 0.0;
            for(int j = 0; j < N; j++)
              {
                if (j==i) continue;
                   double delta_x = x[i]-x[j],  
                          delta_y = y[i]-y[j];
                       double r_x_ij = PBCtwo(delta_x,L),
                              r_y_ij = PBCtwo(delta_y,L),
                              r_ij_square = r_x_ij * r_x_ij + r_y_ij * r_y_ij;
                       if (r_ij_square > l0_two)
                          { 
                          double r_ij = sqrt(r_ij_square);
                          r_x_ij/= r_ij; 
                          r_y_ij/= r_ij;
                          double S_tr = 1 /r_ij_square;
                          S_trx += r_x_ij * S_tr;
                          S_try += r_y_ij * S_tr;
                          }
                }
            dx[i] += tr * S_trx;  
            dy[i] +=  tr * S_try;
            }
        for(int i = 0; i < N; i++)
            {
            x[i]+=  dt * dx[i];
            y[i]+=  dt * dy[i];
            if (x[i] > L){
              x[i]-= L;} 
            else if( x[i] < 0) {
            x[i]+= L;}
            if (y[i] > L){
             y[i]-= L;} 
            else if( y[i] < 0){
                y[i]+= L;}
            }
        }
    ofstream finalConfigFile;
    finalConfigFile.open ("Final Configuration.txt");
    finalConfigFile << to_string(N) << "\n";
    finalConfigFile << to_string(L) << "\n";
    for (int i = 0; i < N; i++)
        {
        finalConfigFile << to_string(x[i]) << "\t" << to_string(y[i]) <<"\n";   
        }
    finalConfigFile.close();
    return 0;
}

2 个答案:

答案 0 :(得分:0)

模拟这个硬球体的最常用方法是,考虑到每个粒子都有半径,如果两个粒子之间的距离小于半径之和(它们在空间上重叠),则将它们的中心与(虚拟)连接起来春天将带走他们。

排斥力的公式类似于F = -k *(l-l_0),其中k是修改接触硬度的经验常数,l_0是两个粒子的半径之和,l是实际两个中心之间的距离。如果两个粒子重叠,只考虑这个力!

要做到这一点,你必须每时每刻测试一对粒子的重叠。如果是这样,计算弹簧的力并将其考虑在内。

答案 1 :(得分:0)

我认为你想模拟一种具有潜力的粒子气体,它具有吸引力和硬核排斥性部分。

多粒子系统的分子动力学模拟是一个发达的科学领域。这种模拟的难点在于最初以不重叠的方式对粒子进行采样。这在Metropolis et al的经典论文中得到了解决。但无论如何你忽略了这一部分。还有许多教科书和论文解释了如何使用硬球进行分子动力学模拟,如thisthis1959 paper, where they first used Molecular Dynamics

如果您的项目要显示像Windows屏幕保护程序中碰撞的漂亮球体,只需让您的核心潜力更柔和,减少您的时间步长,它将像魅力一样工作。如果您的目标是科学严谨,请阅读这些论文,不要忘记控制节能。例如,可以通过替换

来添加软排斥
double S_tr = 1 /r_ij_square;

通过

double S_tr = 1.0 / r_ij_square - 1.0 / (r_ij_square * r_ij_square);

代码格式,结构和变量命名还有很多不足之处。我建议尝试使用clang-format工具。结构上,周期性边界条件有很多重复。

有了令人厌恶的潜力,你可能会得到一个经历相变的系统,这是一个令人兴奋的研究对象。祝好运!

更新:

请注意,以下代码存在错误:

double rho, v0, tr, xr, l0, eta, dt, x[N], y[N];
double L = pow(N / rho , 0.5), l0_two = l0 * l0;
// ...
l0 = 1;

你首先计算l0_two = l0 * l0(永远不要用l开始变量名,它很容易将它与1混淆,sqrt(x)应该优于pow(x,0.5))然后分配l0 = 1.因此l0_two未定义,可能被赋值为0.这可能会导致部分问题。

修复该bug后,您可以选择两种解决方案。如果粒子足够接近,首先是上述的软排斥势。第二种方法与paper with event-based MD cited above完全一样。