如何在我对有吸引力的颗粒的模拟中添加硬球排斥
How to add hard-sphere repulsion in my simulation of attractive particles?
我模拟了一个互相吸引的粒子系统。吸引力的强度取决于颗粒之间的距离。边界条件和相互作用是周期性的。由于吸引力,粒子彼此相处并聚集了一个圆圈。
我想添加硬球的排斥,以便每当两个或多个粒子聚集在相同位置时,我希望它们在连接其中心的线路中分开,直到它们不重叠为止。我该怎么做?
当存在吸引人的相互作用时,添加硬球的情况比通常的情况要困难,因为在某些情况下可能有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;
}
我假设您想模拟具有吸引人和硬核排斥部分的粒子气体。
许多粒子系统的分子动力学模拟是一个发达的科学领域。这种模拟的困难部分是最初以不重叠的方式采样粒子。这是在Metropolis等人的古典论文中解决的。但是无论如何,您还是忽略了这部分。也有许多教科书和论文解释,如何用硬球进行分子动力学模拟,例如This或This或1959年的论文,它们首先使用了分子动力学。
如果您的项目要显示出像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。这可能会导致您的问题的一部分。
修复该错误后,您可以使用两个解决方案。如果颗粒足够接近,则第一个是上面描述的软排斥潜力。第二个是在上述引用的基于事件的MD中与论文完全一样。
如果每个粒子之间的距离都小于半径的总和(它们在太空中重叠),则考虑每个粒子都有半径,模拟该硬球的最常见方法是。将他们的中心与(虚拟)弹簧联系起来,将它们带走。
排斥力的公式类似于f = -k*(l-l_0),其中k是修改接触硬度的经验常数,l_0是两个粒子的半径和l是实际的两个中心之间的距离。仅当两个粒子重叠时,才考虑这项力量!
要这样做,如果粒子重叠,则必须在每时每刻对粒子的每一对夫妻进行测试。如果是这样,请计算弹簧的力并考虑到它。
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 如何在C++中从两个单独的for循环中添加两个数组
- 如何使用Google Mock来模拟gettimeofday()
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- 如何仅为一个函数添加延迟
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 使用std::transform将一个范围的元素添加到另一个范围中
- G锁定铸造到基础上会释放模拟行为
- 如何将更多文件夹添加到c++include路径
- 如何将元素添加到数组的线程安全函数?
- QT通过C++添加映射QML项目
- 如何将点击的信号和插槽添加到qt中的自定义按钮中
- 如何使用重载的相等(==)运算符向测试用例添加描述
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 有什么好的方法可以让系统调用代理允许在单元测试中进行模拟
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 只能向C++添加一定数量的字符
- 将模拟类添加到 stl 容器
- 如何在我对有吸引力的颗粒的模拟中添加硬球排斥
- 在C++中模拟自上而下添加时出现分段错误