生成一组随机 x,y,z 数字,它们之间的差异最小,在定义的限制之间

Posted

技术标签:

【中文标题】生成一组随机 x,y,z 数字,它们之间的差异最小,在定义的限制之间【英文标题】:Generate a set of random x,y,z numbers, with a minimum difference between them, between defined limits 【发布时间】:2017-05-08 09:43:45 【问题描述】:

所以我正在尝试进行分子动力学模拟,并尝试用随机粒子填充 3D 矩形体积,这些随机粒子均匀分布在整个体积中。每个分子都有一个固定的半径 r(sphere),其中每个分子的 r 可以不同。所以我希望在体积中生成球体,然后在距该点的 ( 2(r+tolerance) ) 距离内不应存在其他球体(公差会非常小,如 10^-6)。

此外,通道将具有指定的长度、宽度和宽度,因此随机化应在单个方向上的这些限制内进行,具有上述类似条件,即如果分子更靠近壁,则不应生成分子比它的半径+公差。

我最初尝试的是结构化晶格,但这意味着我的分子数量将与维度相关,这对我不起作用。所以我写了以下算法(我想粘贴我的代码,但它不起作用,现在它是一个大的,夸张的混乱,并且几乎让我的电脑崩溃了一次。

所以逻辑是

1.) 对于每个粒子,使 max_X=X-(radius+tol)。对 Y 和 Z 执行相同操作。

2.) 对于每个粒子,生成 0 到 max_X 之间的随机数。

3.) 计算每个粒子之间的距离并创建一个违反上述任何条件的粒子列表。

4.) 遍历列表并重新生成这些粒子。

5.) 创建另一个违规粒子对列表。

6.) 过去。冲洗并重复,直到列表的大小为零。

所以,它不起作用。我需要这段代码最终为大量粒子执行,所以我需要它尽可能高效和 OpenMP 可并行化。我在 for 循环前面使用标准的陈词滥调的#pragma omp parallel for 方法来并行化计算,但是在运行时,在超强风扇噪音大约 5 到 10 分钟之后,无论有没有编译指示,它都不起作用。

我是一个非编码背景的人,最近开始学习用 C++ 编写复杂的代码,所以我现在不能做一些花哨的事情,比如结构、类或指针。不过,我正在使用 std::vectors 。如果你们能告诉我一条出路,我会很高兴的,如果你们在罗利及其周边地区,我会亲自开车过来给你们一杯冰镇啤酒。几天来一直在尝试这样做,这是我的代码中唯一主要的非功能性内容。

帮忙?!!!

PS/EDIT:为了清楚起见,这不是家庭作业,否则我现在应该问教授了。它是一个独立项目的一部分,我将在完成后免费分发。

【问题讨论】:

您的算法是否适用于少量粒子?也许现在它没有完成,因为卷太紧了,也许另一种随机化方法会更合适。 不。尝试了 10 个粒子。如果我推入 10000 也是一样 粒子半径是给定的,还是随机生成的?另外,对于算法的第1步,“X”是什么?第 1 步的结果是一个 max_X 值,但不清楚它在哪里使用(我假设在第 2 步中随机应该在 0 和 max_X 之间进行,对吗?) 1.) 半径也是随机生成的。 2.)是的,我的错误。编辑它。生成在 0 和 max_X 之间完成。 X 是体积在 X 方向上的实际尺寸。 你的意思是它不起作用?这是否意味着最终列表中有一些粒子发生碰撞? 【参考方案1】:

CGAL 正是您所需要的,但请:

“我不能做一些花哨的事情,比如结构、类或指针”会让你一事无成。我们可以帮助您实现目标,但您还需要至少熟悉结构、类和 STL。

【讨论】:

我明白,我想我这么说是很糟糕的。我愿意学习任何东西。我需要从标准 C++ 库中做一些事情,因为后来这里的 HPC 不支持添加你的第三方库,这是我最大的问题。 除非是大学项目,否则不要重新发明***。如果是大学项目,至少使用 struct Point3D double x, double y, double z 来帮助代码健全。 @AyushAgrawal:能加代码就加代码。它是否来自 Boost 在法律和学术上都是相关的,但是添加自己的代码在技术上与添加 Boost 代码并没有太大区别。但是<random><vector> 是标准的(如在 ISO 标准 14882:2014 中),而不是第三方。 好吧,我从来没有真正在网站上找到适合我的应用程序的东西。我需要一些带有约束的随机生成的东西,这似乎不会在那里发生,至少不是以我可以组合在一起的方式。 如果您在谈论网格算法,是的,它就在那里,但我需要一些可扩展且实际上是随机的,这可能会转化为较差的网格。没有程序会在网格不佳时停止生成。如果我最终发布代码,我不想通过生成网格然后提取其点来解决算法。【参考方案2】:

“3.) 计算每个粒子之间的距离并创建一个违反上述任何条件的粒子列表。”

这是一个O(N*N) 算法。而且你反复这样做。你这样做的频率可能取决于分子的密度,但我希望你不是在模拟固体。

有一种适当的方法可以做到这一点。将体积切成小盒子,大小大致为radius^3。现在您只需要检查每个盒子内的碰撞,以及与它的 26 个邻居的碰撞。如果你有很多很多这样的小盒子,那么只检查 27 个小盒子的效率要高得多。

如果您使用整数/定点坐标,并使用 2 的幂来获取确切的框大小,则可以轻松找到正确的框。例如。如果半径为 250,则将框设为 256x256x256,这样就可以通过除以 256 来找到正确的框。这是硬件上的位移。

【讨论】:

【参考方案3】:

我将首先对目前所采用的方法做一些说明:

首先,应该调查少数粒子(例如 1、2、10)会发生什么,以了解为什么它没有完成。 我怀疑的问题是违反约束的列表永远不会为空。也许代码中存在错误,或者粒子太难适应矩形体积。 步骤 3) 和 4) 的组合似乎效率低下。不能保证违反约束的球体列表会从一个步骤减少到下一个步骤。 例如,对于很多领域,很可能每个领域都至少有一个与之重叠。在这种情况下,每次都需要重新生成所有球体,导致没有进展。 在步骤 3) 和 4) 中,如果一对球体违反了约束,则重新生成两个球体。考虑只重新生成其中一个(可能是随机选择的)可能会很有用。

另一种方法是逐个生成球体。 虽然新添加的球体违反了先前放置的任何约束,但请重试随机放置它。如果它不违反任何约束,则固定其位置,然后继续下一个球体。

【讨论】:

嗯,最后一种方法看起来很聪明,并且可以按顺序运行,但我需要一种可以稍后并行化并扩大规模的算法。作为更新,我正在考虑找到所有粒子的最大半径,并将其用作截止点来简化问题。不确定它是否会起作用,如果以后我的粒度偏差很大,肯定不会有帮助。 我的方法中的一个问题可能会通过并行编程来解决,如下所示。假设我们在早期放置了一个球体,使得它相对于之前放置的那些是合法的,但会阻止后续放置。在这种情况下,后面的球体将很难找到它们的位置。这里的解决方案是完全停止生成并在球体的随机尝试次数超过预定义的最大尝试次数时重新开始。一种有用的替代方法是并行启动多个此类顺序进程。 抱歉,您能否以不同的方式解释您的方法? 没什么花哨的,并行方法只包括独立运行顺序过程的多个实例。此外,请确保为不同的进程使用不同的随机种子,以防止所有进程生成完全相同的结果。【参考方案4】:

我知道有两个很好的答案

一种是泊松圆盘采样的推广,称为泊松球分布。 POisson 圆盘采样是为了对 2D 点之间的最小距离(因此是圆盘)进行采样而发明的。

泊松球用于在 3D 纸上进行采样:

https://pdfs.semanticscholar.org/26c3/490a9f2bdf8082d351639ff596f000f8e319.pdf

【讨论】:

【参考方案5】:

另一种方法是使用准随机数。对于准随机 Sobol 序列,有一条语句表示点之间的最小正距离为 0.5*sqrt(d)/N,其中d 是问题的维度(在您的情况下为 3),@ 987654323@ 是在超立方体中采样的点数。该男子本人的论文http://www.sciencedirect.com/science/article/pii/S0378475406002382。

Sobol 准随机数的合理实现在 GNU 科学库 (GSL) 中

【讨论】:

以上是关于生成一组随机 x,y,z 数字,它们之间的差异最小,在定义的限制之间的主要内容,如果未能解决你的问题,请参考以下文章

生成每个之间距离最小的3-d随机点?

如何同时训练两个神经网络以最小化它们的输出之间的差异?

MATLAB中,怎样把一组给定的数据随机排列?

生成随机数并将它们放入一组[重复]

C#如何生成随机不重复的数字

[CSP-S模拟测试]:小Y的图(最小生成树+LCA)