source: CIVL/examples/translation/mpi/diffusion2d_cb.c@ e0b45cc

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

diffusion2d example with checker board slicing strategy

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

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