Симуляция n-тела с общей памятью в часовне - PullRequest
0 голосов
/ 06 октября 2018

Я пытаюсь повторно реализовать реализацию симуляции n-body для общей памяти, представленную в главе 6.1.6 «Введение в параллельное программирование» Питера Пачеко.В этой главе это было реализовано с использованием OpenMP.

Вот моя параллельная реализация с использованием OpenMP .А вот последовательная реализация с использованием Chapel .У меня проблемы с реализацией параллельной реализации совместно используемой памяти с помощью Chapel.Поскольку нет способа получить ранг потока в цикле forall, я не могу использовать тот же подход, что и в реализации OpenMP.Мне пришлось бы использовать цикл coforall, создавать задачи и распределять итерации вручную.Это не кажется практичным и предполагает, что есть более элегантный способ решить эту проблему в часовне.

Я ищу рекомендации и предложения о том, как лучше решить эту проблему с помощью инструментов, предоставленных часовней.

1 Ответ

0 голосов
/ 09 октября 2018

Я бы предложил использовать (+) уменьшить намерение на forces в цикле Форалла, что даст каждой задаче свою собственную частную копию forces, а затем (сумму) уменьшитих отдельные копии возвращаются в исходную переменную forces по мере выполнения задач.Это можно сделать, добавив следующее выражение with к циклу forall:

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

Пока я искал другие способы сделать код немного более элегантным и предложил бы перейти с 2D-массива намассив массивов для этой задачи, чтобы свести кучу трио подобных операторов кода для компонентов x, y, z к одному выражению.Я также использовал вашу переменную pDomain и создал псевдоним типа для [0..#3] real, чтобы удалить некоторую избыточность в коде.О, и я удалил use из Math и 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();

Еще одно изменение, которое вы могли бы рассмотреть, заключается в замене петли Форалла, которая обновляет позиции и скорости, следующими операторами целого массива:

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

, где основным компромиссом будет то, что Форалл будет реализовыватьоператоры в смешанном виде с использованием одного параллельного цикла, в то время как операторы из целого массива не будут (по крайней мере, в текущей версии компилятора версии 1.18).

...