您如何并行化二维Boids模拟


16

您如何以这样的方式编写2D boids仿真程序,使其可以使用来自不同来源(群集,gpu)的处理能力。

例子

在上面的示例中,无色粒子四处移动,直到它们聚集(黄色)并停止移动。

问题是,尽管左上方的实体不太可能与右下方的实体进行交互,但所有实体都可能彼此交互。如果将域划分为不同的段,则可能会加快整个过程的速度。但是,如果实体希望跨入另一个段,则可能会出现问题。

目前,该仿真可用于具有良好帧速率的5000个实体,如果可能,我想尝试使用数百万个实体。

可以使用四叉树进一步优化吗?还有其他建议吗?


您是要优化还是要并行化?这些是不同的东西。
bummzack 2011年

@bummzack如何并行化,我刚刚添加了进一步的解释,这有帮助吗?
Sycren

Answers:


7

硕士论文粒子流体的并行模拟Mattias Linde的可能会为大规模模拟的数据分区和算法提供一些见识。

他的论文面向光滑粒子流体力学,该方法对于幼稚的解决方案倾向于在模拟中使用“空间散列”,其散列大小与粒子的内核足迹大小相近。

由于在典型的SPH内核中交互距离是固定的,因此这种分区优化对于扩展系统几乎是必不可少的。


不错的论文,但是关于这个问题的准确部分似乎很多,例如@Fxlll答案。
Ali1S232 2011年

我要说的是,本文的实际部分是如何通过引入通信协议来解决边缘情况,这是最困难的部分,quad分区非常明显,并且其本身无法解决边缘情况问题。
Maik Semder 2011年

4

我很久以前学到的术语是游戏的信息速度。

如果您的Boid的速度为1并且他们只关心邻居,那么信息的速度为3,也就是说,与您相距2格的Boid可能在一帧之内位于您关注的范围内:

交互中每个boid 1平方运动(1 + 1)加上您可以注意到的事物的距离(1)等于3。

在此基础上,我们了解到我们可以将地图切成块,大小可以随意调整,但是信息的速度可以重叠到任何相邻的块中。

我假设您只允许小伙子移动一个方块,但他们可以看到三个方块

如果要运行大型并行模拟,则可以分成10x10的网格,但每个边缘重叠5个正方形。每当您的一个人离本地块边缘的信息距离之内时,您就应该更新邻居,并且一旦它们越过边界,它们就不属于您。如果邻居说他们控制的一个辫子已经移到您的块中,则您必须接管它的AI。

这意味着通信被本地化到相邻的块管理器,并且流量减少到最小。运行的作业越多,可用于模拟的CPU越多,但是运行的作业越多,它们重叠的越多,因此随着模拟的进行,作业/块之间传递的信息越多。在这里,您必须精打细算,并根据AI的复杂性和可用的硬件来调整块大小。


想象世界是1,000,000x1,000,000网格,世界上有10,000,000个波蒂,每个波蒂可以每转正好移动一个正方形,您能解释一下如何检查另一个邻域中是否有一个波蒂吗?
Ali1S232'7

我想我们可以将其分割成2000个500x500正方形或更大。每个方格都包含一个boid列表以及一个邻居列表。如果Boid退出一个正方形,它将从Boid列表中删除并添加到另一个正方形。我可以看到的此方法的问题是,如果添加的植绒大于正方形,则该植绒会增加。四叉树解决方案必须是动态的,但是我不确定这将是多么昂贵
Sycren 2011年

@Gajet:您只需要检查块中的boid或邻居管理的边界中的boid。请记住,边框通过设计保证要考虑到任何实体可以移动多远以及实体可以看到的距离。@Sycren:植绒,尽管在我们看来是一个大实体,但仍然只是小规模的影响。一群鱼没有跟随这所学校,而是跟随着他们可观察的邻居。
理查德·法比安

2

通过阅读您的问题,您似乎可以利用四叉树,创建四叉树并为不同处理单元上的每个段运行仿真。这将导致仅对彼此靠近的对象进行检查。但您需要在每个周期同步线程。这意味着将其中一些投标从一个处理组转移到另一个处理组。通常,每个周期将包含3个步骤:

  1. 将所有投标都移动一个单位。(可以使用多个线程轻松处理)
  2. 将每个投标分配给一个组*。这意味着,使用O(n)算法时,您必须选择最有可能发生碰撞的波伊德。这也可以使用多个线程来处理。
  3. 最后,您必须检查同一组中的两个伯德是否碰撞。

*要创建群组,您可以使用以下模式:

在此处输入图片说明

请注意,某些投标可能是多个组的一部分,但是此模式可为您提供更准确的结果。您也可以使用此模式创建任意数量的组,这只是您要找到多少个花样和一个屏幕尺寸的数字,什么是您需要创建的最佳组数。

- 编辑 -

@LarsViklund sugested论文中描述了关于分段的另一种想法,这样就减少了重复检查的次数,并且无需增加/减少步骤之间的线程数:

在此处输入图片说明

请注意,某些区域仍然是两组的一部分。区域的宽度和宽度都准确的2*maximum speed。在您的情况下,如果Boid在每个模拟步骤中移动一个像素,则只需在每2组之间共享2个像素宽度的区域。还有一个很小的区域,它是4组的一部分。但一般来说,此方法更容易实现,并且如果正确实现,则要快得多。顺便说一下,这种方式没有反向移动,如果某个对象可以移动,那么它就可以移动而不再需要检查。


听起来是个好主意,但是在执行步骤1之前,我需要进行碰撞检测以查看它们是否可以移动,我不会吗?
Sycren

您可以移动它们,然后检查是否有任何碰撞发生在该移动的相反方向(对于该精确的联结),如果不让模拟继续进行。
Ali1S232

谢谢,这更有意义。除了四叉树以外,您还能想到其他方法来划分工作量吗?
Sycren

正如您所看到的,我的细分本身并不是完全是四叉树,它还有一个额外的组来提高准确性,四叉树样式更易于处理。根据世界的大小,您可以添加更多的组,这意味着每个周期的检查较少。这是内存消耗和计算速度之间的折衷。并且不一定每个组都有一个线程。您可以有一些线程来计算多个组。您也可以在两个或多个线程之间拆分组计算。
Ali1S232

@Gajet如果我对您的图片了解正确,那么将会有很多重复计算,因为这些组的重叠区域非常大。考虑到该问题要求模拟多达数百万个点,这将是一个巨大的浪费。
Maik Semder'7

2

我最近以其中一些答案为起点解决了这个问题。要记住的最有帮助的事情是,boid是一种简单的n体模拟:每个boid是一个对其邻居施加力的粒子。

我发现林德的论文难以阅读。我建议改用SJ Plimpton的“短程分子动力学快速并行算法”林德引用的。Plimpton的论文更具可读性和详细性,并且具有更好的数字:

简而言之,原子分解方法将原子子集永久分配给每个处理器,力分解方法将成对力计算子集分配给每个proc,空间分解方法将模拟盒的子区域分配给每个proc 。

我建议您尝试AD。这是最容易理解和实施的。FD非常相似。是nVidia使用FD使用CUDA进行的n身体模拟,这应该使您大致了解平铺和缩小可如何帮助大大超越串行性能。

SD实现通常是优化技术,需要一定程度的编排才能实现。它们几乎总是更快,更好地扩展。

这是因为AD / FD要求为每个投标建立一个“邻居列表”。如果每个BOID需要知道它的邻居的位置,它们之间的通信是O(ñ ²)。您可以使用verlet的邻居列表,以减少该地区各BOID检查,这可以让你重建列表每隔几个时间步,而不是每一步的大小,但它仍然是O(ñ ²)。在SD中,每个单元都保留一个邻居列表,而在AD / FD中,每个投标都具有一个邻居列表。因此,每个单元彼此通信,而不是每个博德彼此通信。通信的减少是速度提高的源泉。

不幸的是,波多黎各问题稍微破坏了SD。当boid在整个区域中有些均匀地分布时,让每个处理器跟踪一个单元是最有利的。但是您想让小伙子们聚在一起!如果您的羊群行为正常,那么您的绝大多数处理器就会滴答作响,彼此交换空列表,一小组单元最终将执行与AD或FD相同的计算。

为了解决这个问题,您可以在数学上调整像元的大小(常数)以在任何给定时间最小化空像元的数量,或者对四叉树使用Barnes-Hut算法。BH算法功能强大。矛盾的是,在并行体系结构上实现非常困难。这是因为BH树是​​不规则的,因此并行线程将以极大变化的速度遍历它,从而导致线程发散。Salmon和Dubinski提出了正交递归二等分算法,以在处理器之间平均分配四叉树,对于大多数并行体系结构,必须迭代重申。

如您所见,目前我们显然处于优化和黑魔法领域。再次尝试阅读Plimpton的论文,看是否有意义。


1

我假设您的系统是一个环形系统,您可以划分到空间,以便每个单元都有其子区域。

在每个步骤中,粒子都将移动,离开子区域的粒子将被发送到相关的处理器。一个通信步骤将使处理器同步,并采取最后一个后步骤来详细说明异物的位置(如果有)。

这里有三个问题:

  • 1)子区域的形状:

可以选择矩形,但与圆弧相比,显示出较小的面积/周长比。边界越大,粒子越多。虽然子弹头显示出最佳的A / p比,但不能用于镶嵌,因此您应该对一些具有平均A / p比的(可能是半规则的)镶嵌进行镶嵌。显然,通过单元坐标计算流苏索引应该很简单,因此在尝试进行非常特殊的去雄化之前,请先考虑一下。

  • 2)通讯协议:

根据您所拥有的通信基础设施的类型,您可以考虑如何分散处理器之间的跨边界信息。广播,对等重建与对等通信都是选择。

  • 3)分区分配:

您应该使您的详细说明保持平衡,因为每个步骤都需要进行同步。您可以选择将区域静态或动态分配给处理器。如果您的空间确实被活动粒子覆盖,那么这不是什么大问题,但是我相信在这种情况下它可能是不正确的,因为碰撞会使粒子失活。如果所有处理器共享跨境信息,则可以采取一些捷径,但是您必须对此进行一些考虑


@Fxlll我不确定您所说的环形系统是什么意思,它不是环形的。您是说,如果粒子从右侧滑出,它会重新出现在左侧?如果不是这样,则如果粒子撞击到右侧,它将尝试朝另一个方向移动。
Sycren

@Sycren好的,在这种情况下,您必须对重击和以特殊方式处理边缘区域进行一些考虑
FxIII 2011年

-1

尝试我的模拟以获得线索https://github.com/wahabjawed/Boids-Simulation

我是在XNA上开发的


仅仅链接到一个完整的项目并不是一个好的答案。读者被迫深入研究您的资料,直到找到与问题相关的部分,然后仍然需要了解它是如何解决问题的。您能用简单的英语描述您如何解决该问题,以及与其他答案所述的解决方案相比有哪些优势?如果它们有助于理解您的描述,则可以将一些简短的代码段复制并粘贴到您的答案中。
菲利普
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.