문제는 2차 FDM으로 2차 배열을 쪼개어 계산하는 것이다. Exchange Boundary function이 핵심적이라고 볼 수 있다.
sequential.c
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
void advance_field(int nx, int ny, double *f, double *g) {
int i, j, idx;
for (i=1; i<nx-1; i++) {
for (j=1; j<ny-1; j++) {
idx = i*ny + j;
f[idx] = 0.49*(g[idx+ny] + g[idx-ny] + g[idx+1] + g[idx-1] - 4*g[idx])
+ 2*g[idx] - f[idx];
}
}
}
int main() {
const int nx=2000, ny=2000;
int tmax=500;
double *f, *g;
int i, j, idx, tstep;
//-------------------------------------------------------------------------
// initialize coefficient and fields
//-------------------------------------------------------------------------
f = (double*)malloc(nx*ny*sizeof(double));
g = (double*)malloc(nx*ny*sizeof(double));
for (i=0; i<nx; i++) {
for (j=0; j<ny; j++) {
f[i*ny + j] = 0;
g[i*ny + j] = 0;
}
}
//-------------------------------------------------------------------------
// main loop for the time evolution
//-------------------------------------------------------------------------
for (tstep=1; tstep<=tmax; tstep++) {
//------------------------------------
// point source
//------------------------------------
idx = (nx/2-1)*ny + (ny/2-1);
g[idx] = sin(0.02*tstep);
advance_field(nx, ny, f, g);
advance_field(nx, ny, g, f);
}
//-------------------------------------------------------------------------
// gather fields and save as binary files
//-------------------------------------------------------------------------
FILE *fout;
fout = fopen("field.bin", "wb");
fwrite(f, sizeof(double), nx*ny, fout);
fclose(fout);
return 0;
}
answer.c
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<mpi.h>
void advance_field(int nx, int ny, double *f, double *g) {
int i, j, idx;
for (i=1; i<nx-1; i++) {
for (j=1; j<ny-1; j++) {
idx = i*ny + j;
f[idx] = 0.49*(g[idx+ny] + g[idx-ny] + g[idx+1] + g[idx-1] - 4*g[idx])
+ 2*g[idx] - f[idx];
}
}
}
void exchange_boundary(int nx, int ny, double *f) {
int i, j;
int nprocs, myrank;
MPI_Request req1, req2, req3, req4;
MPI_Status stat;
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
if (myrank < nprocs-1) {
MPI_Isend(&f[(nx-2)*ny], ny, MPI_DOUBLE, myrank+1, 10, MPI_COMM_WORLD, &req1);
MPI_Irecv(&f[(nx-1)*ny], ny, MPI_DOUBLE, myrank+1, 20, MPI_COMM_WORLD, &req2);
}
if (myrank > 0 ) {
MPI_Isend(&f[ny], ny, MPI_DOUBLE, myrank-1, 20, MPI_COMM_WORLD, &req3);
MPI_Irecv(&f[0], ny, MPI_DOUBLE, myrank-1, 10, MPI_COMM_WORLD, &req4);
}
if (myrank < nprocs-1) {
MPI_Wait(&req1, &stat);
MPI_Wait(&req2, &stat);
}
if (myrank > 0 ) {
MPI_Wait(&req3, &stat);
MPI_Wait(&req4, &stat);
}
}
int main(int argc, char *argv[]) {
int tnx=8000, tny=8000;
int tmax=1000;
double *f, *g, *ftot;
int nx, ny;
int i, j, idx, tstep;
int nprocs, myrank;
//-------------------------------------------------------------------------
// initialize the MPI environment
//-------------------------------------------------------------------------
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
//-------------------------------------------------------------------------
// initialize coefficient and fields
//-------------------------------------------------------------------------
nx = tnx/nprocs + 2;
ny = tny;
f = (double*)malloc(nx*ny*sizeof(double));
g = (double*)malloc(nx*ny*sizeof(double));
for (i=0; i<nx*ny; i++) {
f[i] = 0;
g[i] = 0;
}
//-------------------------------------------------------------------------
// main loop for the time evolution
//-------------------------------------------------------------------------
for (tstep=1; tstep<=tmax; tstep++) {
//------------------------------------
// point source
//------------------------------------
if (nprocs%2 == 0) {
if (myrank == nprocs/2)
//g[1*ny+(ny/2-1)] = sin(0.02*tstep);
for (j=0; j<ny; j++)
g[1*ny+j] = sin(0.02*tstep);
}
else {
if (myrank == nprocs/2)
g[(nx/2-1)*ny+(ny/2-1)] = sin(0.02*tstep);
}
advance_field(nx, ny, f, g);
exchange_boundary(nx, ny, f);
advance_field(nx, ny, g, f);
exchange_boundary(nx, ny, g);
}
//-------------------------------------------------------------------------
// gather fields and save as binary files
//-------------------------------------------------------------------------
ftot = (double*)malloc(tnx*tny*sizeof(double));
MPI_Gather(&f[1*n], (nx-2)*ny, MPI_DOUBLE, ftot, (nx-2)*ny, MPI_DOUBLE, 0, MPI_COMM_WORLD);
if (myrank == 0) {
FILE *fout;
fout = fopen("field.bin", "wb");
fwrite(ftot, sizeof(double), tnx*tny, fout);
fclose(fout);
}
//-------------------------------------------------------------------------
// finalize the MPI environment
//-------------------------------------------------------------------------
MPI_Finalize();
return 0;
}
myparallel.c
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<mpi.h>
void advance_field(int nx, int ny, double *f, double *g) {
int i, j, idx;
for (i=1; i<nx-1; i++) {
for (j=1; j<ny-1; j++) {
idx = i*ny + j;
f[idx] = 0.49*(g[idx+ny] + g[idx-ny] + g[idx+1] + g[idx-1] - 4*g[idx])
+ 2*g[idx] - f[idx];
}
}
}
void exchange_boundary(int ny, int asize, double *f, int nprocs, int myrank){
int i, j;
MPI_Request req[4];
MPI_Status stat[4];
if(myrank < nprocs-1){
MPI_Isend(&f[(asize)*ny], ny, MPI_DOUBLE, myrank+1, 123, MPI_COMM_WORLD, &req[0]);
MPI_Irecv(&f[(asize+1)*ny], ny, MPI_DOUBLE, myrank+1, 321, MPI_COMM_WORLD, &req[1]);
}
if(myrank > 0){
MPI_Irecv(&f[0], ny, MPI_DOUBLE, myrank-1, 123, MPI_COMM_WORLD, &req[2]);
MPI_Isend(&f[ny], ny, MPI_DOUBLE, myrank-1, 321, MPI_COMM_WORLD, &req[3]);
}
if(myrank < nprocs-1){
MPI_Waitall(2, req, stat);
}
if(myrank > 0){
MPI_Waitall(2, req+2, stat+2);
}
}
int main(int argc, char **argv) {
const int nx=8000, ny=8000;
int tmax=1000;
double *f, *g;
int i, j, idx, tstep;
double elapsed_time = -MPI_Wtime();
int nprocs, myrank;
int q, r, asize, xspos, xepos;
//---------------------------------
// MPI Initialization
//---------------------------------
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
q = nx/nprocs;
r = nx%nprocs;
asize = myrank<r?(q+1):q;
xspos = myrank<r?(q+1)*myrank:(q*myrank+r);
xepos = xspos + asize - 1;
//-------------------------------------------------------------------------
// initialize coefficient and fields
//-------------------------------------------------------------------------
f = (double*)malloc((asize+2)*ny*sizeof(double));
g = (double*)malloc((asize+2)*ny*sizeof(double));
for (i=1; i<asize+1; i++) {
for (j=0; j<ny; j++) {
f[i*ny + j] = 0;
g[i*ny + j] = 0;
}
}
//-------------------------------------------------------------------------
// main loop for the time evolution
//-------------------------------------------------------------------------
for (tstep=1; tstep<=tmax; tstep++) {
//------------------------------------
// point source
//------------------------------------
idx = (nx/2-1)*ny + (ny/2-1);
if(xspos <= idx/ny && idx/ny <= xepos){
g[idx-xspos*ny+ny] = sin(0.02*tstep);
if(tstep==1){
printf("idx = %d, xspos = %d, xepos = %d, idx/ny = %d\n", idx, xspos, xepos, idx/ny);
printf("pointing at g[%d] by rank %d\n", idx-xspos*ny+ny, myrank);
}
}
exchange_boundary(ny, asize, g, nprocs, myrank);
if(myrank == 0)
advance_field(asize+1, ny, f+ny, g+ny);
else if(myrank == nprocs-1)
advance_field(asize+1, ny, f, g);
else
advance_field(asize+2, ny, f, g);
exchange_boundary(ny, asize, f, nprocs, myrank);
if(myrank == 0)
advance_field(asize+1, ny, g+ny, f+ny);
else if(myrank == nprocs-1)
advance_field(asize+1, ny, g, f);
else
advance_field(asize+2, ny, g, f);
}
int *ircnt, *idisp;
double *ftot;
if (myrank == 0){
printf("nx = %d, nprocs = %d, q = %d, r = %d\n", nx, nprocs, q, r);
ircnt = (int*)malloc(sizeof(int)*nprocs);
idisp = (int*)malloc(sizeof(int)*nprocs);
ftot = (double*)malloc(sizeof(double)*nx*ny);
idisp[0] = 0;
for(i = 0; i < nprocs; i++){
ircnt[i] = (i<r?(q+1):q)*ny;
if(i>0) idisp[i] = idisp[i-1] + ircnt[i-1];
}
}
MPI_Gatherv(&f[ny], asize*ny, MPI_DOUBLE, ftot, ircnt, idisp, MPI_DOUBLE, 0, MPI_COMM_WORLD);
//-------------------------------------------------------------------------
// gather fields and save as binary files
//-------------------------------------------------------------------------
if(myrank == 0) {
FILE *fout;
fout = fopen("field2.bin", "wb");
fwrite(ftot, sizeof(double), nx*ny, fout);
fclose(fout);
elapsed_time += MPI_Wtime();
printf("nprocs = %d, elapsed time = %f\n", nprocs, elapsed_time);
free(ftot);
free(ircnt);
free(idisp);
}
free(f);
free(g);
MPI_Finalize();
return 0;
}
'Parallel Programming' 카테고리의 다른 글
| KSC 2014 1번 문제 및 답안 (0) | 2016.10.01 |
|---|---|
| KSC 2013 3번 문제 및 답안 (0) | 2016.10.01 |
| KSC 2013 1번 문제 및 답안 (0) | 2016.10.01 |
| 유한차분법(finite difference method)에서 boundary exchange하기 (0) | 2016.09.28 |
| 블록 분할코드 (0) | 2016.09.13 |
댓글