在给定体积中随机放置 N 个硬球

计算科学 计算物理学 计算几何
2021-12-02 13:59:14

我需要放ñ给定半径的球体R在卷中随机[-0.5,0.5]3,没有任何球体重叠。

如果我选择让所有球体占据总体积的约 57% 的值,我发现很难得到结果。放置的基本方案一世- 之后的第一个粒子一世-1粒子已放置:

  • 选择随机位置
  • 检查与任何其他球体的重叠
  • if(overlap): 检查新随机选择的位置
  • 重复直到一世已放置
  • 放置下一个粒子

但是,放置的粒子越多,我的随机发生器就越不可能找到有足够空间的位置,并且重叠检查需要的时间就越多。为了ñ=500,R=0.5/7.7,该算法勉强能够放置340个粒子(此时重叠称为数十亿次)。

C++ 代码:

using namespace std;

//this function places N hard spheres of radius R on random coordinates in a [-0.5,0.5]^3 box

vector <particle> random_positions_hard_spheres (int N, double R){
vector <particle> positions;

static seed_seq seed_sequence { 100, 78639, 193, 55555, 3, 2348089, 6474367, 264441578 };
static mt19937 gen (seed_sequence);
uniform_real_distribution<double> random_double(-0.5, 0.5);
double x,y,z;
double d=2*R;

for(size_t i=0; i<N; ++i){

    x=random_double(gen);
    y=random_double(gen);
    z=random_double(gen);

    positions.push_back({x,y,z});

    //find position with no overlap
    int j=0;
    while(overlap_index(positions, i, d)){

        positions[i]={random_double(gen), random_double(gen), random_double(gen)};
        ++j;
    }
    cout <<"overlap was called "+to_string(j)+" times"<<endl;
    cout <<"particle "+to_string(i)+" was placed"<<endl;

}

return positions;
}

重叠函数检查粒子是否一世与任何先前放置的粒子重叠。

1个回答

欢迎来到计算科学 StackExchange!

您正在尝试做的事情相当困难,并且需要更复杂的方法。0.57 的体积分数正好位于硬球相图的结晶分支内。致密无规填料的产生是当前研究的一个活跃领域。

原则上,蒙特卡罗模拟或逐次碰撞分子动力学程序可以“平衡”通过随机放置远小于所需尺寸的球体而制备的初始配置。然后,想法是在模拟过程中稳步增加球体直径,直到达到所需的体积分数。

根据您已有的内容,编写蒙特卡洛代码不会太难:

  1. 将所需数量的较小球体插入体积中,在随机选择的位置处,像现在一样检查重叠。
  2. 进行蒙特卡洛:循环所有ñ球体顺序。尝试以随机方向少量移动每个球体。测试与其他的重叠ñ-1领域。如果有任何重叠,则拒绝移动并将球体留在原来的位置。
  3. 每隔一段时间,尝试将所有球体的直径增加一个非常小的量,检查所有12ñ(ñ-1)重叠。如果有任何重叠,保持直径不变并继续。

在分子动力学程序过程中稳定增加直径的替代方法是“随机堆积”的标准计算方法之一。由于Lubachevsky 和 ​​Stillinger,其使用示例可以在 arXiv上找到(也发表在Phys Rev Lett, 84 2064 (2000)上)。

当然,问题在于原则上,在该体积分数下,系统应该在结晶状态下稳定,而不是在随机堆积状态下。在实践中,这可能不是问题:系统可能会在随机填充状态下“卡住”,其体积分数取决于压缩率,如Phys Rev Lett中所述。

可以在网上找到硬球的 MD 程序,例如DynamO,或者您可以在各种书籍和论文中找到有关如何编写程序的指导。有一些提高程序速度的标准技巧,基本上是通过列出球体的近邻列表:对于 500 阶的系统大小,这些是值得的,但不会带来巨大的加速。