教堂中的共享内存n体模拟

时间:2018-10-06 18:14:52

标签: parallel-processing chapel

我正在尝试重新实现Peter Pacheco在“并行编程简介”中的6.1.6章中介绍的n体模拟的共享内存实现。在该章中,它是使用OpenMP实现的。

这是我使用OpenMP的并行实现。这是使用Chapel的串行实现。我在使用Chapel实现共享内存并行实现时遇到问题。由于无法在forall循环中获取线程的排名,因此我无法使用与OpenMP实现相同的方法。我将不得不使用coforall循环,创建任务并手动分发迭代。这似乎不切实际,这表明在Chapel中有一种更优雅的解决方案。

我正在寻找有关如何使用Chapel提供的工具更好地解决此问题的指导和建议。

1 个答案:

答案 0 :(得分:4)

我的建议是在您的forall循环中的forces上使用(+)reduce intent,这将为每个任务提供自己的forces私有副本,然后是(sum)在任务完成时将其单个副本还原为原始forces变量。这可以通过在您的forall循环中附加以下附带条款来完成:

  forall q in 0..#n_bodies with (+ reduce forces) {

在这里,我正在寻找其他方法来使代码更加优雅,并建议针对此问题从2D数组更改为数组数组,以折叠一堆类似代码声明的三重奏。将x,y,z分量简化为单个语句。我还使用了pDomain变量,并为[0..#3] real创建了类型别名,以消除代码中的某些冗余。噢,我删除了useMath模块中的IO,因为它们在Chapel程序中是自动使用的。

这是离开我的地方

config const filename = "input.txt";
config const iterations = 100;
config const out_filename = "out.txt";
const X = 0;
const Y = 1;
const Z = 2;
const G = 6.67e-11;
config const dt = 0.1;

// Read input file, initialize bodies                                       
var f = open(filename, iomode.r);
var reader = f.reader();

var n_bodies = reader.read(int);
const pDomain = {0..#n_bodies};

type vec3 = [0..#3] real;

var forces: [pDomain] vec3;
var velocities: [pDomain] vec3;
var positions: [pDomain] vec3;
var masses: [pDomain] real;

for i in pDomain {
  positions[i] = reader.read(vec3);

  velocities[i] = reader.read(vec3);

  masses[i] = reader.read(real);
}

f.close();
reader.close();

for i in 0..#iterations {
  // Reset forces                                                           
  forces = [0.0, 0.0, 0.0];

  forall q in pDomain with (+ reduce forces) {
    for k in pDomain {
      if k <= q {
        continue;
      }
      var diff = positions[q] - positions[k];
      var dist = sqrt(diff[X]**2 + diff[Y]**2 + diff[Z]**2);
      var dist_cubed = dist**3;

      var tmp = -G * masses[q] * masses[k] / dist_cubed;
      var force_qk = tmp * diff;

      forces[q] += force_qk;
      forces[k] -= force_qk;
    }
  }


  forall q in pDomain {
    positions[q] += dt * velocities[q];
    velocities[q] += dt / masses[q] * forces[q];
  }
}

var outf = open(out_filename, iomode.cw);
var writer = outf.writer();

for q in pDomain {
  writer.writeln("%er %er %er %er %er %er".format(positions[q][X], positions[q][Y], positions[q][Z], velocities[q][X], velocities[q][Y], velocities[q][Z]));
}

writer.close();
outf.close();

您可以考虑进行的另一项更改是用以下整个数组语句替换更新位置和速度的forall循环:

    positions += dt * velocities;                                           
    velocities += dt / masses * forces;                                     

主要的折衷是forall将使用单个并行循环以融合的方式实现语句,而全数组语句则不会(至少在当前的1.18版编译器中)。