source: CIVL/examples/messagePassing/diffusion1d_good.cvl@ dd57b13

1.23 2.0 main test-branch
Last change on this file since dd57b13 was dd57b13, checked in by Stephen Siegel <siegel@…>, 12 years ago

Adding working version of diffusion1d comparison.

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

  • Property mode set to 100644
File size: 9.7 KB
Line 
1/* Composite model of sequential and parallel 1d-diffusion solvers.
2 * Compares the results of the sequential and parallel computation to
3 * determine functional equivalence of the two versions.
4 *
5 * The initial values are taken as inputs. The two global boundary
6 * points are fixed.
7 *
8 * Command line example:
9
10 civl verify -inputNPROCSB=3 -inputNSTEPSB=3 -inputWSTEP=1 \
11 -inputNXB=6 diffusion1d.cvl
12
13 */
14#include<civlc.h>
15#include<stdio.h>
16#include<stdlib.h>
17#include<assert.h>
18
19// Definitions from programs:
20#define OWNER(index) ((nprocs*(index+1)-1)/nx)
21
22// inputs:
23$input int NPROCS; // number of processes for parallel version
24$input int NPROCSB; // upper bound on nprocs
25$input double K; // k = alpha^2 * dt/(dx^2)
26$input int NSTEPS; // number of time steps
27$input int WSTEP; // write every this many time steps
28$input int NSTEPSB; // upperbound on nsteps
29$input int NX; // global number of discrete spatial points
30$input int NXB; // upper bound on nx
31$input double u_init[NX]; // initial values for temperature (u)
32
33// assumptions:
34$assume 2 <= NX && NX <= NXB;
35$assume K>0 && K<.5;
36$assume NSTEPS >= 1;
37// check this: wstep >= 1 && wstep <= NSTEPS;
38$assume NX > NPROCS;
39$assume 0 < NPROCS && NPROCS <= NPROCSB;
40$assume 0 < NSTEPS && NSTEPS <= NSTEPSB;
41
42
43
44
45// global variables:
46int output_seq[NX]; // final (color) result of sequential computation
47int output_par[NX]; // final (color) result of parallel computation
48$proc procs[NPROCS]; // the MPI processes
49$gcomm MPI_GCOMM_WORLD; // the global communicator object
50
51// MPI model:
52
53typedef enum {MPI_INT, MPI_DOUBLE} MPI_Datatype;
54#define BCAST_TAG 999
55#define MPI_PROC_NULL -1
56
57typedef struct {
58 int size;
59 int source;
60 int tag;
61} MPI_Status;
62
63#define MPI_STATUS_IGNORE NULL
64
65int sizeofDatatype(MPI_Datatype datatype) {
66 switch (datatype) {
67 case MPI_INT:
68 return sizeof(int);
69 case MPI_DOUBLE:
70 return sizeof(double);
71 default:
72 $assert(0, "Unreachable");
73 }
74}
75
76/* Sends a message. */
77void MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest,
78 int tag, $comm comm) {
79 if (dest >= 0) {
80 int size = count*sizeofDatatype(datatype);
81 $message out =
82 $message_pack(comm->place, dest, tag, buf, size);
83
84 $comm_enqueue(comm, out);
85 }
86}
87
88/* Receives a message. */
89void MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source,
90 int tag, $comm comm, MPI_Status *status) {
91 if (source >= 0) {
92 $message in = $comm_dequeue(comm, source, tag);
93 int size = count*sizeofDatatype(datatype);
94
95 $message_unpack(in, buf, size);
96 if (status != MPI_STATUS_IGNORE) {
97 status->size = $message_size(in);
98 status->source = $message_source(in);
99 status->tag = $message_tag(in);
100 }
101 }
102}
103
104void MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count) {
105 *count = status->size/sizeofDatatype(datatype);
106}
107
108void MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype,
109 int dest, int sendtag,
110 void *recvbuf, int recvcount, MPI_Datatype recvtype,
111 int source, int recvtag,
112 $comm comm, MPI_Status *status) {
113 MPI_Send(sendbuf, sendcount, sendtype, dest, sendtag, comm);
114 MPI_Recv(recvbuf, recvcount, recvtype, source, recvtag, comm, status);
115}
116
117/* Broadcasts a message from root to everyone else.
118 * Need to use a differnt comm.
119 */
120void MPI_Bcast(void *buf, int count, MPI_Datatype datatype, int root,
121 $comm comm) {
122 int place = $comm_place(comm);
123
124 if (place == root) {
125 int nprocs = $comm_size(comm);
126
127 for (int i=0; i<nprocs; i++)
128 if (i != root)
129 MPI_Send(buf, count, datatype, i, BCAST_TAG, comm);
130 } else {
131 MPI_Recv(buf, count, datatype, root, BCAST_TAG, comm, MPI_STATUS_IGNORE);
132 }
133}
134
135/* Abstract function representing conversion from temperature to color */
136//$abstract int colorOf(double x);
137int colorOf(double x) { return (int)x; }
138
139/* Sequential algorithm: performs simulation storing result of final
140 * time step in output_seq */
141void main_seq() {
142 $scope seq_scope = $here;
143 int nx, nsteps, wstep;
144 double k, *u;
145
146 void init() {
147 int i;
148 int pos = 0; // file position
149
150 // in place of reading these from file:
151 nx = NX;
152 nsteps = NSTEPS;
153 wstep = WSTEP;
154 k = K;
155 printf("Diffusion1d with nx=%d, k=%f, nsteps=%d, wstep=%d\n",
156 nx, k, nsteps, wstep);
157 assert(nx>=2);
158 assert(k>0 && k<.5);
159 assert(nsteps >= 1);
160 assert(wstep >= 1 && wstep <=nsteps);
161 u = (double*)$malloc(seq_scope, nx*sizeof(double));
162 assert(u);
163 for (i = 0; i < nx; i++) u[i] = u_init[pos++];
164 }
165
166 void write_frame(int time) {
167 for (int i=0; i<nx; i++)
168 output_seq[i] = colorOf(u[i]);
169 }
170
171 void update() {
172 int i;
173 double u_new[nx];
174
175 for (i = 1; i < nx-1; i++)
176 u_new[i] = u[i] + k*(u[i+1] + u[i-1] -2*u[i]);
177 for (i = 1; i < nx-1; i++)
178 u[i] = u_new[i];
179 }
180
181 // main body starts here:
182 init();
183 write_frame(0);
184 for (int iter = 1; iter <= nsteps; iter++) {
185 update();
186 if (iter%wstep==0) write_frame(iter);
187 }
188 free(u);
189}
190
191/* MPI Process in parallel algorithm */
192void MPI_Process (int rank) {
193 $scope proc_scope = $here; /* this scope */
194 int nx, nsteps, wstep, nprocs;
195 double k;
196 $comm MPI_COMM_WORLD; /* the MPI communicator */
197 double *u; /* temperature function */
198 double *u_new; /* temp. used to update u */
199 int left; /* rank of left neighbor */
200 int right; /* rank of right neighbor on torus */
201 int nxl; /* horizontal extent of one process */
202 int first; /* global index for local index 0 */
203 int start; /* first local index to update */
204 int stop; /* last local index to update */
205 double *buf; /* temp. buffer used on proc 0 only */
206
207 int firstForProc(int rank) {
208 return (rank*nx)/nprocs;
209 }
210
211 int countForProc(int rank) {
212 int a;
213 int b;
214
215 a = firstForProc(rank+1);
216 b = firstForProc(rank);
217 return a-b;
218 }
219
220 /* init: initializes global variables. */
221 void init() {
222 int i, j;
223 int pos = 0; // position in input file
224
225 nprocs = NPROCS;
226 if (rank == 0) {
227 // in place of reading these from file:
228 nx = NX;
229 k = K;
230 nsteps = NSTEPS;
231 wstep = WSTEP;
232 printf("Diffusion1d with nx=%d, k=%f, nsteps=%d, wstep=%d nprocs=%d\n",
233 nx, k, nsteps, wstep, nprocs);
234 }
235 MPI_Bcast(&nx, 1, MPI_INT, 0, MPI_COMM_WORLD);
236 MPI_Bcast(&k, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
237 MPI_Bcast(&nsteps, 1, MPI_INT, 0, MPI_COMM_WORLD);
238 MPI_Bcast(&wstep, 1, MPI_INT, 0, MPI_COMM_WORLD);
239 assert(nx>=nprocs);
240 assert(k>0 && k<.5);
241 assert(nx>=2);
242 assert(nsteps>=1);
243 first = firstForProc(rank);
244 nxl = countForProc(rank);
245 if (first == 0 || nxl == 0)
246 left = MPI_PROC_NULL;
247 else
248 left = OWNER(first-1);
249 if (first+nxl >= nx || nxl == 0)
250 right = MPI_PROC_NULL;
251 else
252 right = OWNER(first+nxl);
253 u = (double*)$malloc(proc_scope, (nxl+2)*sizeof(double));
254 assert(u != NULL);
255 u_new = (double*)$malloc(proc_scope, (nxl+2)*sizeof(double));
256 assert(u_new != NULL);
257 if (rank == 0) {
258 buf = (double*)$malloc(proc_scope, (1+nx/nprocs)*sizeof(double));
259 for (i=1; i <= nxl; i++)
260 u[i] = u_init[pos++]; // instead of reading from file
261 for (i=1; i < nprocs; i++) {
262 int count_i = countForProc(i);
263
264 for (j=0; j<count_i; j++)
265 buf[j] = u_init[pos++];
266 MPI_Send(buf, count_i, MPI_DOUBLE, i, 0, MPI_COMM_WORLD);
267 }
268 }
269 else {
270 buf = NULL;
271 MPI_Recv(u+1, nxl, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
272 }
273 if (rank == OWNER(0)) {
274 start = 2;
275 }
276 else {
277 start = 1;
278 }
279 if (rank == OWNER(nx-1)) {
280 stop = nxl - 1;
281 }
282 else {
283 stop = nxl;
284 }
285 }
286
287 void write_frame(int time) {
288 if (rank != 0) {
289 MPI_Send(u+1, nxl, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
290 } else {
291 int source, i, j, count, global_index;
292 MPI_Status status;
293
294 global_index = 0;
295 for (source = 0; source < nprocs; source++) {
296 if (source != 0) {
297 MPI_Recv(buf, 1+nx/nprocs, MPI_DOUBLE, source, 0,
298 MPI_COMM_WORLD, &status);
299 MPI_Get_count(&status, MPI_DOUBLE, &count);
300 } else {
301 for (i = 1; i <= nxl; i++) buf[i-1] = u[i];
302 count = nxl;
303 }
304 for (i = 0; i < count; i++) {
305 output_par[global_index] = colorOf(buf[i]);
306 global_index++;
307 }
308 }
309 }
310 }
311
312 /* exchange_ghost_cells: updates ghost cells using MPI communication */
313 void exchange_ghost_cells() {
314 MPI_Sendrecv(&u[1], 1, MPI_DOUBLE, left, 0,
315 &u[nxl+1], 1, MPI_DOUBLE, right, 0,
316 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
317 MPI_Sendrecv(&u[nxl], 1, MPI_DOUBLE, right, 0,
318 &u[0], 1, MPI_DOUBLE, left, 0,
319 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
320 }
321
322 /* update: updates u. Uses ghost cells. Purely local operation. */
323 void update() {
324 int i;
325
326 for (i = start; i <= stop; i++)
327 u_new[i] = u[i] + k*(u[i+1] + u[i-1] -2*u[i]);
328 for (i = start; i <= stop; i++)
329 u[i] = u_new[i];
330 }
331
332 // body of MPI Process procedure starts here:
333 MPI_COMM_WORLD = $comm_create($here, MPI_GCOMM_WORLD, rank);
334 init();
335 write_frame(0);
336 for (int iter = 1; iter <= nsteps; iter++) {
337 exchange_ghost_cells();
338 update();
339 if (iter%wstep==0) write_frame(iter);
340 }
341 free(u);
342 free(u_new);
343 if (rank == 0)
344 free(buf);
345 $comm_destroy(MPI_COMM_WORLD);
346}
347
348void main_par() {
349 MPI_GCOMM_WORLD = $gcomm_create($root, NPROCS);
350 for (int i=0; i<NPROCS; i++) procs[i] = $spawn MPI_Process(i);
351 for (int i=0; i<NPROCS; i++) $wait(procs[i]);
352 $gcomm_destroy(MPI_GCOMM_WORLD);
353}
354
355void main() {
356 main_seq();
357 main_par();
358 for (int i=0; i<NX; i++)
359 $assert(output_seq[i]==output_par[i]);
360}
Note: See TracBrowser for help on using the repository browser.