嵌套 for 循环和 Verlet 列表优化 C++

Nested for loops and Verlet lists optimization C++

提问人:Carlos Andrés del Valle 提问时间:5/15/2021 更新时间:5/15/2021 访问量:213

问:

我正在用 C++ 模拟分子动力学。我的代码的主要结构如下

particle Molecule[N];
collider Newton;
//initialization of the molecules
    for(t=0; t<=tmax; t+=dt){
    for(int i=0; I<N; i++)Newton.MovePosition(Molecule[i]);
    Newton.CalculateForces(Molecule);
    for(int i=0; I<N; i++)Newton.MoveVelocity(Molecule[i])
    for(int i=0; I<N; i++)Newton.MovePosition(Molecule[i]);
    .
    .
    .
}

其中,碰撞器类是粒子类的友元,知道每个粒子的位置、速度等。这些粒子与正常的 Lenard Jhones 电位相互作用。在计算力中,我有这样的东西

for(int i=0; i<N; i++)
  for(int j=i+1;j<N; j++ )
    Molecule[i].F=......

我基本上是在计算其他每个分子对分子 i 施加的力。 我遇到的问题是这个程序效率非常低。我有 2 个嵌套的 for 循环。计算力和积分算法中的力的那个。我想优化这段代码,因为有 25 个粒子和 10^5 次迭代,运行需要很长时间,对于模拟,我想做,我必须至少有 10^3 个分子和 10^5 次迭代。 我尝试了以下方法:

  1. 我尝试使用并行 for 并行化 for 循环 #omp 并且工作速度比串行版本慢。
  2. 我读过 Verlet 列表,基本上,粒子不会与所有粒子相互作用,而只会与它们的邻居相互作用。这意味着力计算嵌套循环的大小要小得多。这样做的问题在于,要完成列表,您必须遍历所有粒子,并以某种方式告诉每个粒子是它的邻居。然后循环访问该邻居数组。我一直在思考如何以有效的方式做到这一点,但我还没有想出答案。
  3. 为了降低 Verlet 列表实现的计算成本,我发现了一种叫做跳过列表的东西,这使得在列表中搜索某些内容成为 O(ln(N)) 操作而不是 O(N)。但实际上,我不太了解它是如何工作的,也不知道如何集成到 Verlet 列表问题中。
  4. 过去,我做过空间并行化,每个内核对空间中的某个区域进行计算。这样做的问题是它与 Verlet 列表不兼容,我读过 Verlet 列表更好。
  5. 由于移动位置和速度的运算类似于 V+=Fdt常数,我认为一些约简算法会有所帮助,但我对约简算法一无所知,因此有所帮助。
  6. 最后,我认为也许在 c++ 17 或 20 中,算法库中可能有一些东西可以提供帮助,但我对算法知之甚少,所以我花了很长时间来阅读文档并确定它的有用之处。到目前为止,我已经开始添加带有向量而不是数组的 for auto。此外,我还有一个小库,允许我将变量定义为 3D 向量并进行正常的向量运算。

因此,我被困在一个位置上,我对编程的了解不够,不知道该做什么,以及我发现的解决方案在哪里遇到了与我现在相同的问题。 所以,如果有人可以帮助我提供关于如何集成所有这些东西的建议,或者如何优化我的代码,或者如果它知道一个特殊的数据结构或算法可以帮助我,我真的很感激你的帮助。 目标是使单个时间步长的积分算法至少为 O(N)。 谢谢。

C++ 算法 循环 优化 verlet-integration

评论

1赞 ChrisMM 5/15/2021
矢量化是关键。此外,Verlet 列表也每 10 次左右迭代重新计算一次。不确定你是如何组织你的类的,可能有帮助使用分子不同组分的数组(改进的访问模式)。另外,请记住 a 对 b 的力等于 b 对 a 的负力(如果您还没有)。
0赞 Carlos Andrés del Valle 5/15/2021
对于矢量化,您的意思是使用 std::vector 还是其他东西?我已经实施了 3 牛顿定律。类分子有一个 3D 向量,用于表示作用在它上面的位置、速度和力,所以我可以通过 1 次运算进行加法、乘法、获得范数等等。您知道或在哪里可以看到 Verlet 列表实现的良好文档吗?感谢您的评论。
0赞 ChrisMM 5/15/2021
请参阅 stackoverflow.com/questions/1422149/what-is-vectorization ...我可以试着挖掘我在这方面的旧论文,这些论文显示了加速。我有使用任务、MPI 和两者的并行版本。关键是分配工作负载,并以“处理器/内存友好”的方式加载数据
0赞 Carlos Andrés del Valle 5/15/2021
这将有很大帮助。谢谢。特别是关于 Verlet 列表。
1赞 Jérôme Richard 5/15/2021
请注意,OpenMP 可以帮助轻松地对代码进行矢量化(以及特定于编译器的指令),但使用对象编程往往会阻止编译器对代码进行矢量化(导致代码变慢)。请注意 AoS VS SoA 性能问题。使用 SoA 通常在性能方面更好,因为它可以帮助编译器矢量化代码,并且通常可以减少缓存未命中的数量。

答: 暂无答案