source: CIVL/examples/translation/mpi/diffusion2d.c@ 6280cc6

1.23 2.0 acw/focus-triggers main test-branch
Last change on this file since 6280cc6 was 6280cc6, checked in by Ziqing Luo <ziqing@…>, 12 years ago

changed diffusion2d.c and Makefile

git-svn-id: svn://vsl.cis.udel.edu/civl/trunk@1747 fb995dde-84ed-4084-dfe6-e5aef3e2452c

  • Property mode set to 100644
File size: 10.1 KB
RevLine 
[6280cc6]1/* diffusion2d.c: parallel 2d-diffusion equation solver with constant boundaries
[696be79]2 * slicing matrix as a checker board.
[6280cc6]3 * To execute: mpicc diffusion2d.c ; mpiexec -n 4 ./a.out 2 2
4 * To verify: civl verify diffusion2d.c
[696be79]5 */
6#include<stdio.h>
7#include<stdlib.h>
8#include<assert.h>
9#include<string.h>
10#include<mpi.h>
11
12/* Message tags */
13#define FROMLEFT 0
14#define FROMRIGHT 1
15#define FROMTOP 2
16#define FROMBOTTOM 3
17#define DATAPASS 4
18#define comm MPI_COMM_WORLD
19
20#ifdef _CIVL
21
[6280cc6]22$input long NXB = 5; //nx upper bound
23$input long nx; //global number of columns in matrix
[696be79]24$assume 1 <= nx && nx <= NXB;
[6280cc6]25$input long NYB = 5; //ny upper bound
26$input long ny; //global number of rows of matrix
[696be79]27$assume 1 <= ny && ny <= NYB;
[6280cc6]28$input double u_init[ny+2][nx+2]; //initial value of temperatures, including boundaries
29$input double k; //constant coefficient
[696be79]30$assume k > 0.0 && k < 0.5;
[6280cc6]31$input int NSTEPSB = 3; //boundary of number of steps
32$input int nsteps; //number of steps
[696be79]33$assume 1<=nsteps && nsteps<=NSTEPSB;
[6280cc6]34$input int wstep = 1; //write frame every this many time steps
35double oracle[nsteps][ny+2][nx+2]; //solution computed sequentially, done by proc 0 only
36$input int NPROCSXB; //bound number of components of columns
37$input int NPROCSX = 2; //number of components of columns
38$assume NPROCSX > 1 && NPROCSX <= NPROCSXB;
39$input int NPROCSYB; //bound number of components of rows
40$input int NPROCSY = 2; //number of components of rows
41$assume NPROCSY > 1 && NPROCSY <= NPROCSYB;
42$input int _NPROCS = NPROCSX * NPROCSY;
43
[696be79]44#else
45
[6280cc6]46long nx, ny;
47int nsteps, wstep;
[696be79]48int NPROCSX, NPROCSY;
[6280cc6]49double constTemp; //value of constant boundaries for test
50double initTemp; //value of initial tempretrue for test
[696be79]51double k;
52
53#endif
54
55/* Global variables */
[6280cc6]56int nprocs, rank, left, right, top, bottom;
57int nxl, nyl;
58long firstCol, firstRow;
[696be79]59double ** u_curr;
60double ** u_next;
61
[6280cc6]62/* Following book keeping functions are designed based on such orgnization:
63 * row 0: 0 1 2
64 * row 1: 3 4 5
65 * ... */
[696be79]66/* Compute the global column index of cells owned by the process */
[6280cc6]67long firstColForProc(int rank) {
68 long tmp = (rank - (rank / NPROCSX)*NPROCSX)*nx;
69
70 return tmp/NPROCSX;
[696be79]71}
72
73/* Compute the global row index of cells owned by the process */
[6280cc6]74long firstRowForProc(int rank) {
75 long tmp = ((rank / NPROCSX)*ny);
76
77 return tmp/NPROCSY;
[696be79]78}
79
80/* Computes the number of columns owned by the process */
81int countColForProc(int rank) {
[6280cc6]82 long a = firstColForProc(rank);
83 long b;
[696be79]84
85 if((rank / NPROCSX) == ((rank+1) / NPROCSX))
86 b = firstColForProc(rank+1);
87 else
88 b = nx;
89 return b - a;
90}
91
92/* Computes the number of rows owned by the process */
93int countRowForProc(int rank) {
[6280cc6]94 long a = firstRowForProc(rank);
95 long b = firstRowForProc(rank+NPROCSX);
[696be79]96
97 return b - a;
98}
99
100/* Get the owner process of the given cell */
[6280cc6]101int OWNER(long col, long row) {
102 long tmp = ((NPROCSY * (row+1))-1);
103 int procRow = tmp / ny;
104 int procCol;
105
106 tmp = ((col + 1) * NPROCSX - 1);
107 procCol = tmp / nx;
108 tmp = procRow * NPROCSX;
109 return tmp + procCol;
[696be79]110}
111
112
[6280cc6]113/* initialize all data values owned by each process */
114void initData() {
[696be79]115#ifdef _CIVL
116
117 // sets vertical constant boundaries
118 if(left == MPI_PROC_NULL)
[6280cc6]119 for(int i=0; i<nyl+2; i++)
120 u_next[i][0] = u_curr[i][0] = u_init[i + firstRow][0];
[696be79]121 if(right == MPI_PROC_NULL)
[6280cc6]122 for(int i=0; i<nyl+2; i++)
123 u_next[i][nxl+1] = u_curr[i][nxl+1] = u_init[i + firstRow][nx+1];
[696be79]124 // sets horizontal constant boundaries
125 if(top == MPI_PROC_NULL)
[6280cc6]126 for(int i=0; i<nxl+2; i++)
127 u_next[0][i] = u_curr[0][i] = u_init[0][i + firstCol];
[696be79]128 if(bottom == MPI_PROC_NULL)
[6280cc6]129 for(int i=0; i<nxl+2; i++)
130 u_next[nyl+1][i] = u_curr[nyl+1][i] = u_init[ny+1][i + firstCol];
131 for(int i=1; i<nyl+1; i++)
132 memcpy(&u_curr[i][1], &u_init[firstRow + i][firstCol + 1], nxl * sizeof(double));
133
134#else
135
136 for(int i=0; i < nyl+2; i++)
137 for(int j=0; j < nxl+2; j++)
138 if(i == 0 || j == 0 || i == nyl+1 || j == nxl+1)
139 u_next[i][j] = u_curr[i][j] = constTemp;
140 else
141 u_curr[i][j] = initTemp;
142
[696be79]143#endif
[6280cc6]144}
[696be79]145
146/* Initialize all global variables */
147void initialization(int argc, char * argv[]) {
148#ifndef _CIVL
149
150 nsteps = 300;
151 wstep = 5;
152 nx = 15;
153 ny = 15;
154 if(argc < 3) {
[6280cc6]155 printf("Program needs 2 arguments to specify the number of processes in x direction and y direction:\n"
156 "It should go with the format: mpiexec -n NPROCS diffusion2d "
157 "NPROCSX NPROCSY\n"
158 "NPROCSX: number of processes in x direction\n"
159 "NPROCSY: number of processes in y direction\n"
160 "NPROCS: the product of NPROCSX and NPROCSY\n");
[696be79]161 assert(0);
162 }
163 NPROCSX = atoi(argv[1]);
164 NPROCSY = atoi(argv[2]);
[6280cc6]165 assert(0 < NPROCSX * NPROCSY &&
166 NPROCSX * NPROCSY <=nprocs);
[696be79]167 constTemp = 0.0;
168 initTemp = 100.0;
169 k = 0.13;
[6280cc6]170 printf("Diffusion2d with k=%f, nx=%ld, ny=%ld, nsteps=%d, wstep=%d\n",
[696be79]171 k, nx, ny, nsteps, wstep);
172
173#endif
174
175 nxl = countColForProc(rank);
176 nyl = countRowForProc(rank);
177 u_curr = (double **)malloc((nyl + 2) * sizeof(double *));
178 assert(u_curr);
179 u_next = (double **)malloc((nyl + 2) * sizeof(double *));
180 assert(u_next);
[6280cc6]181 for(int i=0; i < nyl + 2; i++){
[696be79]182 u_curr[i] = (double *)malloc((nxl + 2) * sizeof(double));
183 assert(u_curr[i]);
184 u_next[i] = (double *)malloc((nxl + 2) * sizeof(double));
185 assert(u_next[i]);
186 }
187 firstCol = firstColForProc(rank);
188 firstRow = firstRowForProc(rank);
189 // computes neighbors
190 if(firstCol != 0)
191 left = OWNER(firstCol - 1, firstRow);
192 else
193 left = MPI_PROC_NULL;
194 if(firstRow != 0)
195 top = OWNER(firstCol, firstRow - 1);
196 else
197 top = MPI_PROC_NULL;
198 if(firstCol + nxl < nx)
199 right = OWNER(firstCol + nxl, firstRow);
200 else
201 right = MPI_PROC_NULL;
202 if(firstRow + nyl < ny)
203 bottom = OWNER(firstCol, firstRow + nyl);
204 else
205 bottom = MPI_PROC_NULL;
[6280cc6]206
[696be79]207#ifdef _CIVL
[6280cc6]208
[696be79]209 // In CIVL mode process with rank 0 will be responsible for computing the diffusion2d equation
210 // sequentially such that the results can be used to compare with the ones of parallel run.
211 if(rank == 0) {
[6280cc6]212 for(long i = 0; i < ny + 2; i++)
213 for(long j = 0; j < nx + 2; j++)
[696be79]214 oracle[0][i][j] = u_init[i][j];
215 for(int t=1; t < nsteps; t++)
[6280cc6]216 for(long i = 0; i < ny + 2; i++)
217 for(long j = 0; j < nx + 2; j++)
[696be79]218 if(i==0 || j==0 || i == ny + 1 || j == nx + 1)
219 oracle[t][i][j] = oracle[t-1][i][j];
220 else
221 oracle[t][i][j] = oracle[t-1][i][j] +
222 k*(oracle[t-1][i+1][j] + oracle[t-1][i-1][j] +
223 oracle[t-1][i][j+1] + oracle[t-1][i][j-1] - 4*oracle[t-1][i][j]);
224 }
225
226#endif
227}
228
229void update() {
230 double **tmp;
231
[6280cc6]232 for(int i = 1; i < nyl + 1; i++)
233 for(int j = 1; j < nxl + 1; j++) {
[696be79]234 u_next[i][j] = u_curr[i][j] +
235 k*(u_curr[i+1][j] + u_curr[i-1][j] +
236 u_curr[i][j+1] + u_curr[i][j-1] - 4*u_curr[i][j]);
237 }
238 //swap two pointers
239 tmp = u_curr;
240 u_curr = u_next;
241 u_next = tmp;
242}
243
244void exchange() {
245 double sendbuf[nyl];
246 double recvbuf[nyl];
247
248 // sends top string, receives bottom string
249 MPI_Sendrecv(&u_curr[1][1], nxl, MPI_DOUBLE, top, FROMBOTTOM, &u_curr[nyl+1][1], nxl,
250 MPI_DOUBLE, bottom, FROMBOTTOM, comm, MPI_STATUS_IGNORE);
251 // sends bottom string, receives top string
252 MPI_Sendrecv(&u_curr[nyl][1], nxl, MPI_DOUBLE, bottom, FROMTOP, &u_curr[0][1], nxl,
253 MPI_DOUBLE, top, FROMTOP, comm, MPI_STATUS_IGNORE);
254 // sends left most string, receives right most string
255 for(int i = 0; i < nyl; i++) sendbuf[i] = u_curr[i+1][1];
256 MPI_Sendrecv(sendbuf, nyl, MPI_DOUBLE, left, FROMRIGHT, recvbuf, nyl,
257 MPI_DOUBLE, right, FROMRIGHT, comm, MPI_STATUS_IGNORE);
258 if(right != MPI_PROC_NULL)
259 for(int i = 0; i < nyl; i++) u_curr[i+1][nxl+1] = recvbuf[i];
260 // sends right most string, receives left most string
261 for(int i = 0; i < nyl; i++) sendbuf[i] = u_curr[i+1][nxl];
262 MPI_Sendrecv(sendbuf, nyl, MPI_DOUBLE, right, FROMLEFT, recvbuf, nyl,
263 MPI_DOUBLE, left, FROMLEFT, comm, MPI_STATUS_IGNORE);
264 if(left != MPI_PROC_NULL)
265 for(int i = 0; i < nyl; i++) u_curr[i+1][0] = recvbuf[i];
266}
267
[6280cc6]268void printData(int time, int firstCol, int nxl, int currRow, double * buf) {
[696be79]269
[6280cc6]270 for(int i=0; i<nxl; i++) {
271 printf("%6.2f", *(buf + i));
[696be79]272#ifdef _CIVL
[6280cc6]273 $assert(*(buf + i) == oracle[time][currRow + 1][firstCol + i + 1]) : \
[696be79]274 "Error: disagreement at time %d position [%d][%d]: saw %lf, expected %lf", \
[6280cc6]275 time, currRow, firstCol + i,
276 *(buf + i), oracle[time][currRow + 1][firstCol + i + 1];
[696be79]277#endif
278 }
279}
280
281void write_frame(int time) {
282 double * buf; // buffer of data to print
283
[6280cc6]284 buf = (double *)malloc(nxl * sizeof(double));
285 //sends data row by row
286 if(rank != 0){
287 for(int i=0; i<nyl; i++) {
288 memcpy(buf, &u_curr[i+1][1], nxl*sizeof(double));
289 MPI_Send(buf, nxl, MPI_DOUBLE, 0, DATAPASS, comm);
[696be79]290 }
[6280cc6]291 }
292 free(buf);
[696be79]293 if(rank == 0) {
294 printf("\n-------------------- time step:%d --------------------\n", time);
[6280cc6]295 for(int i=0; i < NPROCSY; i++) {
296 int numRows = countRowForProc(i*NPROCSX);
297
298 for(int j=0; j < numRows; j++) {
299 for(int k=i*NPROCSX; k < (i+1)*NPROCSX; k++) {
300 if(k!=0){
301 int senderx = firstColForProc(k);
302 int sendery = firstRowForProc(k);
303 int senderNxl = countColForProc(k);
304 double * recvbuf = (double *)malloc(senderNxl * sizeof(double));
305
306 MPI_Recv(recvbuf, senderNxl, MPI_DOUBLE, k, DATAPASS, comm, MPI_STATUS_IGNORE);
307 printData(time, senderx, senderNxl, sendery+j, recvbuf);
308 free(recvbuf);
309 } else {
310 printData(time, firstCol, nxl, firstRow+j, &u_curr[j+1][1]);
311 }
312 }
313 printf("\n");
[696be79]314 }
315 }
[6280cc6]316 }
[696be79]317}
318
319int main(int argc, char * argv[]) {
320 int i,j;
321
322#ifdef _CIVL
323
324 // elaborating nx, ny, NPROCSX and NPROCSY...
325 elaborate(nx);
326 elaborate(ny);
327 elaborate(NPROCSX);
328 elaborate(NPROCSY);
329
330#endif
331 MPI_Init(&argc, &argv);
332 MPI_Comm_rank(comm, &rank);
333 MPI_Comm_size(comm, &nprocs);
334 initialization(argc, argv);
[6280cc6]335 initData();
[696be79]336 for(i=0; i<nsteps; i++) {
337 if(nxl != 0 && nyl != 0) {
338 if(i%wstep == 0)
339 write_frame(i);
340 exchange();
341 update();
342 }
343 }
344 for(i=0; i<nyl+2; i++) {
345 free(u_curr[i]);
346 free(u_next[i]);
347 }
348 free(u_curr);
349 free(u_next);
350 return 0;
351}
Note: See TracBrowser for help on using the repository browser.