Лабораторная работа № 2. Решение уравнения Пуассона в трехмерной области методом Зейделя, страница 2

flag=(Abs(fold-F[l][i*Iz+j])<eps);

}

return flag;

}

main(int argc,char** argv)

{

float *x0,*x1,*y0,*z0,*y1,*z1;// м-цы граней

int i,j,jj,ii,k,i1,i2;

int *sendcounts,*displs; // массивы размерностей и смещений

char file[20];

float s,alfa;

FILE *fd,*fd1;

int flag=0,*flg,iter=0;

MPI_Status st;

MPI_Request req;

struct timeval tv1,tv2;

MPI_Init(&argc,&argv);

MPI_Comm_size(MPI_COMM_WORLD,&size);

MPI_Comm_rank(MPI_COMM_WORLD,&rank);

if((fd1=fopen("gran.txt","rt"))==NULL)

{printf("Запусти генератор\n");

MPI_Finalize();

return(1);

}

/* Читаем данные */

fscanf(fd1,"%f %f",&alfa,&eps);

fscanf(fd1,"%d %d %d",&Ix,&Iy,&Iz);

fscanf(fd1,"%f %f %f",&hx2,&hy2,&hz2);

hx2*=hx2;hy2*=hy2;hz2*=hz2; // возводим шаги в квадрат

dim=Ix/size;

ost=Ix%size;// кол-во первых процессоров со строками остатка

c=2/hx2+2/hy2+2/hz2+alfa;

sendcounts=(int *)malloc(size*sizeof(int));

displs=(int *)malloc(size*sizeof(int));

xdims(sendcounts,displs);

/* M – число слоев для данного процессора. Первый и последний процессоры получают по одному дополнительному слою для обмена данными, остальные – по два слоя */

M=(((rank==0)||(rank==size-1)) ? (sendcounts[rank]+1):(sendcounts[rank]+2));

/* Первый процесс не имеет первого дополнительного слоя */

i1=rank ? 1:0;  

/* Выделяем память для F, слой – одномерный массив длины Iy*Iz */

F=(float **)malloc(M*sizeof(float *));

for(i=0;i<M;i++)

{

F[i]=(float *)malloc(Iy*Iz*sizeof(float));

for(j=0;j<Iy*Iz;j++)

F[i][j]=0;

}

/* Выделяем память для вспомогательных массивов граней */

x0=(float *)malloc(Iy*Iz*sizeof(float ));

y0=(float *)malloc(Ix*Iz*sizeof(float ));

y1=(float *)malloc(Ix*Iz*sizeof(float ));

z0=(float *)malloc(Ix*Iy*sizeof(float ));

z1=(float *)malloc(Ix*Iy*sizeof(float ));

if(rank==size-1) // последний процессор читает данные и рассылает остальным

{

/* Читаем грань Х=0 */

for(i=0;i<Iy*Iz;i++)

fscanf(fd1,"%f",&x0[i]);

MPI_Isend(&x0[0],Iy*Iz,MPI_FLOAT,0,tag,MPI_COMM_WORLD,&req);

/* Читаем грань Х=Хм */

for(i=0;i<Iy*Iz;i++)

fscanf(fd1,"%f",&F[M-1][i]);

/* Заполняем для пересылки грани Y */

for(i=0;i<size;i++)

{ sendcounts[i]*=Iz; // кол-во элементов для ш-го процессора  

displs[i]*=Iz; // смещение по массиву y0

}

/* Читаем грань Y=0 */

for(i=0;i<Ix*Iz;i++)

fscanf(fd1,"%f",&y0[i]);

for(k=0;k<size-1;k++)

MPI_Isend(&y0[displs[k]],sendcounts[k],MPI_FLOAT,k,tag+1,

MPI_COMM_WORLD,&req);

for(i=1;i<M-1;i++)

for(j=0;j<Iz;j++)

F[i][j]=y0[displs[size-1]+(i-1)*Iz+j];

/* Читаем грань Y=Yм */

for(i=0;i<Ix*Iz;i++)

fscanf(fd1,"%f",&y1[i]);

for(k=0;k<size-1;k++)

MPI_Isend(&y1[displs[k]],sendcounts[k],MPI_FLOAT,k,tag+2,

MPI_COMM_WORLD,&req);

for(i=1;i<M-1;i++)

for(j=0;j<Iz;j++)

F[i][Iz*(Iy-1)+j]=y1[displs[size-1]+(i-1)*Iz+j];

/* Читаем грань Z=0 */

for(i=0;i<Ix*Iy;i++)

fscanf(fd1,"%f",&z0[i]);

xdims(sendcounts,displs); // заново заполняем массивы для Z

for(i=0;i<size;i++)

{ sendcounts[i]*=Iy;

displs[i]*=Iy;

}

for(k=0;k<size-1;k++)

MPI_Isend(&z0[displs[k]],sendcounts[k],MPI_FLOAT,k,tag+3,

MPI_COMM_WORLD,&req);

for(i=1;i<M-1;i++)

for(j=0;j<Iy;j++)

F[i][Iz*j]=z0[displs[size-1]+(i-1)*Iy+j];

/* Читаем грань Z=Zm */

for(i=0;i<Ix*Iy;i++)

fscanf(fd1,"%f",&z1[i]);

for(k=0;k<size-1;k++)

MPI_Isend(&z1[displs[k]],sendcounts[k],MPI_FLOAT,k,tag+4,

MPI_COMM_WORLD,&req);

for(i=1;i<M-1;i++)

for(j=0;j<Iy;j++)

F[i][Iz*(j+1)-1]=z1[displs[size-1]+(i-1)*Iy+j];

}

else

{/* Прием данных от последнего компьютера */

if(rank==0)

{  MPI_Irecv(&F[0][0],Iy*Iz,MPI_FLOAT,size-1,tag,MPI_COMM_WORLD,&req);

MPI_Wait(&req,&st);

}

/* Грань Y=0 */

MPI_Irecv(y0,sendcounts[rank]*Iz,MPI_FLOAT,size-1,tag+1,

MPI_COMM_WORLD,&req);

MPI_Wait(&req,&st);

for(i=i1;i<sendcounts[rank]+i1;i++)

for(j=0;j<Iz;j++)

F[i][j]=y0[(i-i1)*Iz+j];

/* Грань Y=Ym */

MPI_Irecv(y1,sendcounts[rank]*Iz,MPI_FLOAT,size-1,tag+2,          

MPI_COMM_WORLD,&req);

MPI_Wait(&req,&st);

for(i=i1;i<sendcounts[rank]+i1;i++)

for(j=0;j<Iz;j++)

F[i][(Iy-1)*Iz+j]=y1[(i-i1)*Iz+j];