source: CIVL/examples/messagePassing/diffusion1d.cvl@ 912b60d

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

Adding source file diffusion1d_spec.c
Creating new comparison model for diffusion1d that will be very close
to source.
Running into bug right now with abstract function.
Checking in little abstract function example which works fine.

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

  • Property mode set to 100644
File size: 9.6 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);
137
138/* Sequential algorithm: performs simulation storing result of final
139 * time step in output_seq */
140void main_seq() {
141 $scope seq_scope = $here;
142 int nx, nsteps, wstep;
143 double k, *u;
144
145 void init() {
146 int i;
147 int pos = 0; // file position
148
149 // in place of reading these from file:
150 nx = NX;
151 nsteps = NSTEPS;
152 wstep = WSTEP;
153 k = K;
154 printf("Diffusion1d with nx=%d, k=%f, nsteps=%d, wstep=%d\n",
155 nx, k, nsteps, wstep);
156 assert(nx>=2);
157 assert(k>0 && k<.5);
158 assert(nsteps >= 1);
159 assert(wstep >= 1 && wstep <=nsteps);
160 u = (double*)$malloc(seq_scope, nx*sizeof(double));
161 assert(u);
162 for (i = 0; i < nx; i++) u[i] = u_init[pos++];
163 }
164
165 void write_frame(int time) {
166 for (int i=0; i<nx; i++)
167 output_seq[i] = colorOf(u[i]);
168 }
169
170 void update() {
171 int i;
172 double u_new[nx];
173
174 for (i = 1; i < nx-1; i++)
175 u_new[i] = u[i] + k*(u[i+1] + u[i-1] -2*u[i]);
176 for (i = 1; i < nx-1; i++)
177 u[i] = u_new[i];
178 }
179
180 // main body starts here:
181 init();
182 write_frame(0);
183 for (int iter = 1; iter <= nsteps; iter++) {
184 update();
185 if (iter%wstep==0) write_frame(iter);
186 }
187 free(u);
188}
189
190/* MPI Process in parallel algorithm */
191void MPI_Process (int rank) {
192 $scope proc_scope = $here; /* this scope */
193 int nx, nsteps, wstep, nprocs;
194 double k;
195 $comm MPI_COMM_WORLD; /* the MPI communicator */
196 double *u; /* temperature function */
197 double *u_new; /* temp. used to update u */
198 int left; /* rank of left neighbor */
199 int right; /* rank of right neighbor on torus */
200 int nxl; /* horizontal extent of one process */
201 int first; /* global index for local index 0 */
202 int start; /* first local index to update */
203 int stop; /* last local index to update */
204 double *buf; /* temp. buffer used on proc 0 only */
205
206 int firstForProc(int rank) {
207 return (rank*nx)/nprocs;
208 }
209
210 int countForProc(int rank) {
211 int a;
212 int b;
213
214 a = firstForProc(rank+1);
215 b = firstForProc(rank);
216 return a-b;
217 }
218
219 /* init: initializes global variables. */
220 void init() {
221 int i, j;
222 int pos = 0; // position in input file
223
224 nprocs = NPROCS;
225 if (rank == 0) {
226 // in place of reading these from file:
227 nx = NX;
228 k = K;
229 nsteps = NSTEPS;
230 wstep = WSTEP;
231 printf("Diffusion1d with nx=%d, k=%f, nsteps=%d, wstep=%d nprocs=%d\n",
232 nx, k, nsteps, wstep, nprocs);
233 }
234 MPI_Bcast(&nx, 1, MPI_INT, 0, MPI_COMM_WORLD);
235 MPI_Bcast(&k, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
236 MPI_Bcast(&nsteps, 1, MPI_INT, 0, MPI_COMM_WORLD);
237 MPI_Bcast(&wstep, 1, MPI_INT, 0, MPI_COMM_WORLD);
238 assert(nx>=nprocs);
239 assert(k>0 && k<.5);
240 assert(nx>=2);
241 assert(nsteps>=1);
242 first = firstForProc(rank);
243 nxl = countForProc(rank);
244 if (first == 0 || nxl == 0)
245 left = MPI_PROC_NULL;
246 else
247 left = OWNER(first-1);
248 if (first+nxl >= nx || nxl == 0)
249 right = MPI_PROC_NULL;
250 else
251 right = OWNER(first+nxl);
252 u = (double*)$malloc(proc_scope, (nxl+2)*sizeof(double));
253 assert(u != NULL);
254 u_new = (double*)$malloc(proc_scope, (nxl+2)*sizeof(double));
255 assert(u_new != NULL);
256 if (rank == 0) {
257 buf = (double*)$malloc(proc_scope, (1+nx/nprocs)*sizeof(double));
258 for (i=1; i <= nxl; i++)
259 u[i] = u_init[pos++]; // instead of reading from file
260 for (i=1; i < nprocs; i++) {
261 for (j=0; j<countForProc(i); j++)
262 buf[j] = u_init[pos++];
263 MPI_Send(buf, countForProc(i), MPI_DOUBLE, i, 0, MPI_COMM_WORLD);
264 }
265 }
266 else {
267 buf = NULL;
268 MPI_Recv(u+1, nxl, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
269 }
270 if (rank == OWNER(0)) {
271 start = 2;
272 }
273 else {
274 start = 1;
275 }
276 if (rank == OWNER(nx-1)) {
277 stop = nxl - 1;
278 }
279 else {
280 stop = nxl;
281 }
282 }
283
284 void write_frame(int time) {
285 if (rank != 0) {
286 MPI_Send(u+1, nxl, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
287 } else {
288 int source, i, j, count, global_index;
289 MPI_Status status;
290
291 global_index = 0;
292 for (source = 0; source < nprocs; source++) {
293 if (source != 0) {
294 MPI_Recv(buf, 1+nx/nprocs, MPI_DOUBLE, source, 0,
295 MPI_COMM_WORLD, &status);
296 MPI_Get_count(&status, MPI_DOUBLE, &count);
297 } else {
298 for (i = 1; i <= nxl; i++) buf[i-1] = u[i];
299 count = nxl;
300 }
301 for (i = 0; i < count; i++) {
302 output_par[global_index] = colorOf(buf[i]);
303 global_index++;
304 }
305 }
306 }
307 }
308
309 /* exchange_ghost_cells: updates ghost cells using MPI communication */
310 void exchange_ghost_cells() {
311 MPI_Sendrecv(&u[1], 1, MPI_DOUBLE, left, 0,
312 &u[nxl+1], 1, MPI_DOUBLE, right, 0,
313 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
314 MPI_Sendrecv(&u[nxl], 1, MPI_DOUBLE, right, 0,
315 &u[0], 1, MPI_DOUBLE, left, 0,
316 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
317 }
318
319 /* update: updates u. Uses ghost cells. Purely local operation. */
320 void update() {
321 int i;
322
323 for (i = start; i <= stop; i++)
324 u_new[i] = u[i] + k*(u[i+1] + u[i-1] -2*u[i]);
325 for (i = start; i <= stop; i++)
326 u[i] = u_new[i];
327 }
328
329 // body of MPI Process procedure starts here:
330 MPI_COMM_WORLD = $comm_create($here, MPI_GCOMM_WORLD, rank);
331 write_frame(0);
332 for (int iter = 1; iter <= nsteps; iter++) {
333 exchange_ghost_cells();
334 update();
335 if (iter%wstep==0) write_frame(iter);
336 }
337 free(u);
338 free(u_new);
339 if (rank == 0)
340 free(buf);
341 $comm_destroy(MPI_COMM_WORLD);
342}
343
344void main_par() {
345 MPI_GCOMM_WORLD = $gcomm_create($root, NPROCS);
346 for (int i=0; i<NPROCS; i++) procs[i] = $spawn MPI_Process(i);
347 for (int i=0; i<NPROCS; i++) $wait(procs[i]);
348 $gcomm_destroy(MPI_GCOMM_WORLD);
349}
350
351void main() {
352 main_seq();
353 main_par();
354 for (int i=0; i<NX; i++)
355 $assert(output_seq[i]==output_par[i]);
356}
Note: See TracBrowser for help on using the repository browser.