/* diffusion2d.c: parallel 2d-diffusion equation solver with constant boundaries * slicing matrix as a checker board. * To execute: mpicc diffusion2d.c ; mpiexec -n 4 ./a.out 2 2 * To verify: civl verify diffusion2d.c */ #include #include #include #include #include /* Message tags */ #define FROMLEFT 0 #define FROMRIGHT 1 #define FROMTOP 2 #define FROMBOTTOM 3 #define DATAPASS 4 #define comm MPI_COMM_WORLD #ifdef _CIVL $input long NXB = 5; //nx upper bound $input long nx; //global number of columns in matrix $assume 1 <= nx && nx <= NXB; $input long NYB = 5; //ny upper bound $input long ny; //global number of rows of matrix $assume 1 <= ny && ny <= NYB; $input double u_init[ny+2][nx+2]; //initial value of temperatures, including boundaries $input double k; //constant coefficient $assume k > 0.0 && k < 0.5; $input int NSTEPSB = 3; //boundary of number of steps $input int nsteps; //number of steps $assume 1<=nsteps && nsteps<=NSTEPSB; $input int wstep = 1; //write frame every this many time steps double oracle[nsteps][ny+2][nx+2]; //solution computed sequentially, done by proc 0 only $input int NPROCSXB; //bound number of components of columns $input int NPROCSX = 2; //number of components of columns $assume NPROCSX > 1 && NPROCSX <= NPROCSXB; $input int NPROCSYB; //bound number of components of rows $input int NPROCSY = 2; //number of components of rows $assume NPROCSY > 1 && NPROCSY <= NPROCSYB; $input int _NPROCS = NPROCSX * NPROCSY; #else long nx, ny; int nsteps, wstep; int NPROCSX, NPROCSY; double constTemp; //value of constant boundaries for test double initTemp; //value of initial tempretrue for test double k; #endif /* Global variables */ int nprocs, rank, left, right, top, bottom; int nxl, nyl; long firstCol, firstRow; double ** u_curr; double ** u_next; /* Following book keeping functions are designed based on such orgnization: * row 0: 0 1 2 * row 1: 3 4 5 * ... */ /* Compute the global column index of cells owned by the process */ long firstColForProc(int rank) { long tmp = (rank - (rank / NPROCSX)*NPROCSX)*nx; return tmp/NPROCSX; } /* Compute the global row index of cells owned by the process */ long firstRowForProc(int rank) { long tmp = ((rank / NPROCSX)*ny); return tmp/NPROCSY; } /* Computes the number of columns owned by the process */ int countColForProc(int rank) { long a = firstColForProc(rank); long b; if((rank / NPROCSX) == ((rank+1) / NPROCSX)) b = firstColForProc(rank+1); else b = nx; return b - a; } /* Computes the number of rows owned by the process */ int countRowForProc(int rank) { long a = firstRowForProc(rank); long b = firstRowForProc(rank+NPROCSX); return b - a; } /* Get the owner process of the given cell */ int OWNER(long col, long row) { long tmp = ((NPROCSY * (row+1))-1); int procRow = tmp / ny; int procCol; tmp = ((col + 1) * NPROCSX - 1); procCol = tmp / nx; tmp = procRow * NPROCSX; return tmp + procCol; } /* initialize all data values owned by each process */ void initData() { #ifdef _CIVL // sets vertical constant boundaries if(left == MPI_PROC_NULL) for(int i=0; i