Симуляция n-тела с общей памятью в часовне

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

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

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

1 ответ

Решение

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

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

В то время как здесь, я искал другие способы сделать код немного более элегантным и предложил бы перейти от двумерного массива к массиву массивов для этой проблемы, чтобы свернуть кучу трио подобных операторов кода для 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;                                     

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

Другие вопросы по тегам