您如何以这样的方式编写2D boids仿真程序,使其可以使用来自不同来源(群集,gpu)的处理能力。
在上面的示例中,无色粒子四处移动,直到它们聚集(黄色)并停止移动。
问题是,尽管左上方的实体不太可能与右下方的实体进行交互,但所有实体都可能彼此交互。如果将域划分为不同的段,则可能会加快整个过程的速度。但是,如果实体希望跨入另一个段,则可能会出现问题。
目前,该仿真可用于具有良好帧速率的5000个实体,如果可能,我想尝试使用数百万个实体。
可以使用四叉树进一步优化吗?还有其他建议吗?
您如何以这样的方式编写2D boids仿真程序,使其可以使用来自不同来源(群集,gpu)的处理能力。
在上面的示例中,无色粒子四处移动,直到它们聚集(黄色)并停止移动。
问题是,尽管左上方的实体不太可能与右下方的实体进行交互,但所有实体都可能彼此交互。如果将域划分为不同的段,则可能会加快整个过程的速度。但是,如果实体希望跨入另一个段,则可能会出现问题。
目前,该仿真可用于具有良好帧速率的5000个实体,如果可能,我想尝试使用数百万个实体。
可以使用四叉树进一步优化吗?还有其他建议吗?
Answers:
硕士论文粒子流体的并行模拟Mattias Linde的可能会为大规模模拟的数据分区和算法提供一些见识。
他的论文面向光滑粒子流体力学,该方法对于幼稚的解决方案倾向于在模拟中使用“空间散列”,其散列大小与粒子的内核足迹大小相近。
由于在典型的SPH内核中交互距离是固定的,因此这种分区优化对于扩展系统几乎是必不可少的。
我很久以前学到的术语是游戏的信息速度。
如果您的Boid的速度为1并且他们只关心邻居,那么信息的速度为3,也就是说,与您相距2格的Boid可能在一帧之内位于您关注的范围内:
交互中每个boid 1平方运动(1 + 1)加上您可以注意到的事物的距离(1)等于3。
在此基础上,我们了解到我们可以将地图切成块,大小可以随意调整,但是信息的速度可以重叠到任何相邻的块中。
我假设您只允许小伙子移动一个方块,但他们可以看到三个方块
如果要运行大型并行模拟,则可以分成10x10的网格,但每个边缘重叠5个正方形。每当您的一个人离本地块边缘的信息距离之内时,您就应该更新邻居,并且一旦它们越过边界,它们就不属于您。如果邻居说他们控制的一个辫子已经移到您的块中,则您必须接管它的AI。
这意味着通信被本地化到相邻的块管理器,并且流量减少到最小。运行的作业越多,可用于模拟的CPU越多,但是运行的作业越多,它们重叠的越多,因此随着模拟的进行,作业/块之间传递的信息越多。在这里,您必须精打细算,并根据AI的复杂性和可用的硬件来调整块大小。
通过阅读您的问题,您似乎可以利用四叉树,创建四叉树并为不同处理单元上的每个段运行仿真。这将导致仅对彼此靠近的对象进行检查。但您需要在每个周期同步线程。这意味着将其中一些投标从一个处理组转移到另一个处理组。通常,每个周期将包含3个步骤:
*要创建群组,您可以使用以下模式:
请注意,某些投标可能是多个组的一部分,但是此模式可为您提供更准确的结果。您也可以使用此模式创建任意数量的组,这只是您要找到多少个花样和一个屏幕尺寸的数字,什么是您需要创建的最佳组数。
- 编辑 -
@LarsViklund sugested论文中描述了关于分段的另一种想法,这样就减少了重复检查的次数,并且无需增加/减少步骤之间的线程数:
请注意,某些区域仍然是两组的一部分。区域的宽度和宽度都准确的2*maximum speed
。在您的情况下,如果Boid在每个模拟步骤中移动一个像素,则只需在每2组之间共享2个像素宽度的区域。还有一个很小的区域,它是4组的一部分。但一般来说,此方法更容易实现,并且如果正确实现,则要快得多。顺便说一下,这种方式没有反向移动,如果某个对象可以移动,那么它就可以移动而不再需要检查。
我最近以其中一些答案为起点解决了这个问题。要记住的最有帮助的事情是,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的论文,看是否有意义。
我假设您的系统是一个环形系统,您可以划分到空间,以便每个单元都有其子区域。
在每个步骤中,粒子都将移动,离开子区域的粒子将被发送到相关的处理器。一个通信步骤将使处理器同步,并采取最后一个后步骤来详细说明异物的位置(如果有)。
这里有三个问题:
可以选择矩形,但与圆弧相比,显示出较小的面积/周长比。边界越大,粒子越多。虽然子弹头显示出最佳的A / p比,但不能用于镶嵌,因此您应该对一些具有平均A / p比的(可能是半规则的)镶嵌进行镶嵌。显然,通过单元坐标计算流苏索引应该很简单,因此在尝试进行非常特殊的去雄化之前,请先考虑一下。
根据您所拥有的通信基础设施的类型,您可以考虑如何分散处理器之间的跨边界信息。广播,对等重建与对等通信都是选择。
您应该使您的详细说明保持平衡,因为每个步骤都需要进行同步。您可以选择将区域静态或动态分配给处理器。如果您的空间确实被活动粒子覆盖,那么这不是什么大问题,但是我相信在这种情况下它可能是不正确的,因为碰撞会使粒子失活。如果所有处理器共享跨境信息,则可以采取一些捷径,但是您必须对此进行一些考虑
尝试我的模拟以获得线索https://github.com/wahabjawed/Boids-Simulation
我是在XNA上开发的