我已经模拟了一个彼此吸引的二维粒子系统。吸引力取决于粒子之间的距离。边界条件和相互作用是周期性的。由于吸引力,粒子彼此相互聚集并聚集在一起。
我想添加硬球排斥力,这样,当两个或多个粒子聚集在同一个位置时,我希望它们分开连接它们的中心的线,直到它们不重叠。我怎么能这样做?
当存在吸引相互作用时添加硬球的情况比通常的情况更难,因为可能存在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;
}
答案 0 :(得分:0)
模拟这个硬球体的最常用方法是,考虑到每个粒子都有半径,如果两个粒子之间的距离小于半径之和(它们在空间上重叠),则将它们的中心与(虚拟)连接起来春天将带走他们。
排斥力的公式类似于F = -k *(l-l_0),其中k是修改接触硬度的经验常数,l_0是两个粒子的半径之和,l是实际两个中心之间的距离。如果两个粒子重叠,只考虑这个力!
要做到这一点,你必须每时每刻测试一对粒子的重叠。如果是这样,计算弹簧的力并将其考虑在内。
答案 1 :(得分:0)
我认为你想模拟一种具有潜力的粒子气体,它具有吸引力和硬核排斥性部分。
多粒子系统的分子动力学模拟是一个发达的科学领域。这种模拟的难点在于最初以不重叠的方式对粒子进行采样。这在Metropolis et al的经典论文中得到了解决。但无论如何你忽略了这一部分。还有许多教科书和论文解释了如何使用硬球进行分子动力学模拟,如this或this或1959 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完全一样。