MPI_Allgather с 2D-массивами - PullRequest
0 голосов
/ 13 октября 2019

Я пытаюсь рассчитать положение некоторых тел, основанное на их предыдущих позициях. Поэтому в каждом цикле k мне нужно, чтобы каждый массив C обновлялся новыми координатами (x, y, z) тел, которые вычисляются и хранятся в массивах Cw. Я попытался MPI_Allgather, но я не могу найти правильный синтаксис для его достижения.

Я проверил вывод с последовательной версией проблемы для k = 1 и значения массивов F, V и Cwверно, единственная проблема - MPI_Allgather. Переменная dt на данный момент равна 1 для простоты. Я пробовал это, но ничего из этой работы. Первый обновляет только первый ряд C-массива прямо из Cw и еще 2 значения, но в неправильных местах, а остальное такое же, как при заполнении в начале. Второе дает ошибку сегментации

MPI_Allgather(&(Cw[0][0]),length*3,MPI_FLOAT,&(C[0][0]),length*3,MPI_FLOAT,MPI_COMM_WORLD);

MPI_Allgather(Cw,length*3,MPI_FLOAT,C,length*3,MPI_FLOAT,MPI_COMM_WORLD);

Вот код

float **C,**Cw;

C=malloc(N*sizeof(float*));
Cw=malloc(length*sizeof(float*));

for(i=0;i<length;i++)
{
    Cw[i]=malloc(3*sizeof(float));
}

for(i=0;i<N;i++)
{
    C[i]=malloc(3*sizeof(float));
}


for(k=0;k<loop;k++)
{
    for(i=start;i<=end;i++)                      
    {
        for(j=0;j<N;j++)                        
        {
            if(i!=j)
            {
                dx=C[j][0]-C[i][0];
                dy=C[j][1]-C[i][1];
                dz=C[j][2]-C[i][2];

                d=sqrt(pow(dx,2)+pow(dy,2)+pow(dz,2));

                F[i-start][0] -= G*M[i]*M[j]/pow(d,3)*dx;
                F[i-start][1] -= G*M[i]*M[j]/pow(d,3)*dy;
                F[i-start][2] -= G*M[i]*M[j]/pow(d,3)*dz;
            }
        }
    }

    for(i=0;i<length;i++)
    {
        for(j=0;j<3;j++)
        {
            a=F[i][j]/M[i+start];                 // α=F/m
            V[i][j]=V[i][j]+a*1;                 // V(n+1)=Vn+α*Δt
            Cw[i][j]=C[i+start][j]+V[i][j]*1;    // R(n+1)=Rn+Vn*Δt
        }
    }

    // where MPI_Allgather takes place
}

Я ожидаю, что на выходе получится последовательная программа https://drive.google.com/open?id=1fwLu8Jk3JEorFTvNJyOtti3K_zIw0ncw

MPIверсия с этим кодом

MPI_Allgather(&(Cw[0][0]),length*3,MPI_FLOAT,&(C[0][0]),length*3,MPI_FLOAT,MPI_COMM_WORLD);

дает этот вывод https://drive.google.com/open?id=14cEFFRvNGUN_RK3u8Z31iRDtiTJs6_8I

1 Ответ

0 голосов
/ 14 октября 2019

Еще раз, это бессмыслица указателей на указатели (для scicomp): вы передаете указатели на строки через MPI, а не содержимое.

Я предлагаю вам избегать выделения массива в виде N независимых строк, например:

float **C,**Cw;

// I guess that you missed to paste these two lines
C  = malloc( N * sizeof(float*) );    
Cw = malloc( length * sizeof(float*) );

for(i=0;i<length;i++)
{
    Cw[i]=malloc(3*sizeof(float));
}

for(i=0;i<N;i++)
{
    C[i]=malloc(3*sizeof(float));
}

Массивы, выделенные таким образом, не являются линейными в памяти и не могут использоватьсяMPI функционирует глобально. Когда вы передаете C, вы передаете только массив указателей. Проходя &C[0][0], вы передаете массив первых 3 элементов, но другие 3-элементные массивы не являются смежными в памяти, так как они были выделены независимо. Таким образом, segfault - это лучшее, чего вы можете достичь, будучи случайным результатом, худшим.

Правильно распределить необходимую память в одном отдельном блоке, который функция MPI может правильно обработать:

float *C,*Cw;
C  = malloc( N * 3 * sizeof(float) );    
Cw = malloc( length * 3 * sizeof(float) );

и замените любой доступ к памяти как

            dx=C[j][0]-C[i][0];
            dy=C[j][1]-C[i][1];
            dz=C[j][2]-C[i][2];

на

            dx=C[3*j+0]-C[3*i+0];
            dy=C[3*j+1]-C[3*i+1];
            dz=C[3*j+2]-C[3*i+2];

Таким образом, передача C приведет к правильной передаче содержимого массива.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...