问题
I am trying to calculate the position of some bodies that is based in their previous positions. So in every k loop I need every C array to be updated with the new coordinates (x,y,z) of the bodies that is calculated and stored in the Cw arrays. I tried MPI_Allgather but I can't find the right syntax to achieve it.
I've checked the output with the serial version of the problem for k=1 and the values of F,V and Cw arrays are right so the only problem is the MPI_Allgather. The dt variable for now is equal to 1 for simplicity. I've tried this but none of ther work. The first one updates only the first row C array right from the Cw and 2 more values but in wrong places and the rest is the same as when is filled in the beginning. The second gives Segmentation fault
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);
Here is the code
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
}
The output that I expect is this provided by the serial program https://drive.google.com/open?id=1fwLu8Jk3JEorFTvNJyOtti3K_zIw0ncw
The mpi version with this code
MPI_Allgather(&(Cw[0][0]),length*3,MPI_FLOAT,&(C[0][0]),length*3,MPI_FLOAT,MPI_COMM_WORLD);
gives this output https://drive.google.com/open?id=14cEFFRvNGUN_RK3u8Z31iRDtiTJs6_8I
回答1:
Once again this pointers-to-pointers nonsense (for scicomp): you are passing the pointers to the rows via MPI, not the contents.
I suggest that you avoid to allocate an array as N independent rows, as in:
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));
}
The arrays allocated in this way aren't linear in memory, and cannot be used by the MPI functions globally. When you pass C
, you are passing just the array of pointers. Passing &C[0][0]
, you are passing the array of the first 3 elements, but the other 3-elements-arrays aren't contiguous in memory, since they've been allocated independently. So a segfault is the best that you can achieve, being random results, the worst.
It's correct to allocate the needed memory in one single block, that MPI function can handle properly:
float *C,*Cw;
C = malloc( N * 3 * sizeof(float) );
Cw = malloc( length * 3 * sizeof(float) );
and replace any memory access as
dx=C[j][0]-C[i][0];
dy=C[j][1]-C[i][1];
dz=C[j][2]-C[i][2];
with
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];
In this way, passing C
will result in passing the array contents correctly.
来源:https://stackoverflow.com/questions/58364672/mpi-allgather-with-2d-arrays