source: CIVL/examples/translation/mpi/diffusion2d_cb.c@ 998356f

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

changed for replacing some for loop assignments with memcpy

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