/******************************************************************* * diffusion2d.c: parallel 2d-diffusion solver with constant * boundaries. * * This example contains a sequential 2d-diffusion solver which * computes results for each time step, they will be used as * specifications to compare with the results of the parallel version. * * To execute: mpicc diffusion2d.c ; mpiexec -n 4 ./a.out Or replace * "4" with however many procs you want to use. * * To verify: civl verify diffusion2d. * Author: Ziqing Luo ********************************************************************/ #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 #include $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 = 5; // upper bound for nsteps $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 = 2; // upper bound for NPROCSX $input int NPROCSX; // number of procs in x direction $assume(NPROCSX >= 1 && NPROCSX <= NPROCSXB); $input int NPROCSYB = 2; // upper bound for NPROCSY $input int NPROCSY; // number of procs in y direction $assume(NPROCSY >= 1 && NPROCSY <= NPROCSYB); $input int _mpi_nprocs = NPROCSX * NPROCSY; $assume(NPROCSX == _mpi_nprocs); #else long nx, ny; int nsteps, wstep; int NPROCSX, NPROCSY; double constTemp; // value of constant boundaries for test double initTemp; // value of initial temperature for test double k; #endif /* Global variables */ int nprocs, rank; int left, right, top, bottom;// ranks of neighbors int nxl; // local dimension of x int nyl; // local dimension of y long firstCol; // index of the first column in global array long firstRow; // index of the first row in global array /* dynamically-allocated 2d array of doubles specifying state of local * grid in current time step. Dimensions are u_curr[nyl+2][nxl+2]. */ double ** u_curr; /* dynamically-allocated 2d array of doubles specifying state of local * grid in next time step. Dimensions are u_next[nyl+2][nxl+2]. */ double ** u_next; /* dynamically-allocated 1d temporary buffer. Length is recvbuf[nxl+1] */ double * recvbuf; /* The processes are arranged geometrically as follows for the case * NPROCSX = 3: * row 0: 0 1 2 * row 1: 3 4 5 * ... * This function computes the global index of the first column * owned by the process of the given rank. rank must be in the * range [0, _mpi_nprocs-1]. The result will in the range [0, nx-1]. */ long firstColForProc(int rank) { long tmp = (rank - (rank / NPROCSX)*NPROCSX)*nx; return tmp/NPROCSX; } /* This function computes the global index of the first row owned by the process of the given rank. rank must be in the range[0, _mpi_nprocs-1]. The result will in the range [0, ny-1]. */ long firstRowForProc(int rank) { long tmp = ((rank / NPROCSX)*ny); return tmp/NPROCSY; } /* Computes the number of columns owned by the process. The result will be in the range [0, nx]. */ 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. The result will be in the range [0, ny]. */ 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 // Data is initialized with totally unconstrained values // for verification. // set the vertical boundary cells: if (left == MPI_PROC_NULL) for (int i=0; i