我正在并行化我的粒子单元代码,我用它来模拟地球内的 2D 和 3D 变形。使用 OpenMP 可以轻松并行化代码的几个例程,并且可以很好地扩展。但是,我在处理从粒子到网格单元的插值的代码的关键部分中遇到了问题。粒子在每次迭代中四处移动(根据速度场)。许多计算在规则的、不变形的网格上执行是最有效的。因此,每次迭代都涉及从“随机”分布的粒子到网格单元的通信。
该问题可以用以下简化的一维代码来说明:
//EXPLANATION OF VARIABLES (all previously allocated and initialized, 1D arrays)
//double *markerval; // Size Nm. Particle values. Are to be interpolated to the grid
//double *grid; // Size Ng=Nm/100 Grid values.
//uint *markerpos; // Size Nm. Position of particles relative to grid (each particle
// knows what grid cell it belongs to) possible values are 0,1,...Ng-1
//#pragma omp parallel for schedule(static) private(e)
for (e=0; e<Nm; e++) {
//#pragma omp atomic
grid[markerpos[e]]+=markerval[e];
}
在最坏的情况下,粒子位置是随机的,但通常,粒子在内存中彼此相邻,在空间中也彼此相邻,因此也在网格内存中。
如何有效地并行化此过程?多个粒子映射到同一个网格单元,因此如果上述循环直接并行化,则存在竞争条件和缓存交换的非零机会。使更新原子化可以防止竞争条件,但会使代码比顺序情况慢得多。
我还尝试为每个线程制作一个网格值的私有副本,然后将它们添加起来。然而,这可能需要在代码中使用太多内存,并且对于这个例子,它并没有很好地随着线程数量而扩展(我不确定其中的原因)。
第三种选择可能是从网格映射到粒子,然后循环通过网格索引而不是粒子索引。但是,我担心这会涉及很多,并且需要对代码进行重大更改,而且我不确定它会有多大帮助,因为它还需要使用计算成本也很高的排序例程。
有没有人有过这个或类似问题的经验?