source: CIVL/examples/messagePassing/diffusion1d_old.cvl@ 325d439

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

Moved diffusion1d around

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

  • Property mode set to 100644
File size: 9.6 KB
RevLine 
[dd57b13]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:
[58c0342]9
10 civl verify -inputNPROCSB=3 -inputNSTEPSB=3 -inputWSTEP=1 \
11 -inputNXB=6 diffusion1d.cvl
12
[dd57b13]13 */
[58c0342]14#include<civlc.h>
15#include<stdio.h>
16#include<stdlib.h>
17#include<assert.h>
[dd57b13]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;
[58c0342]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
[dd57b13]44
45// global variables:
46int output_seq[NX]; // final (color) result of sequential computation
47int output_par[NX]; // final (color) result of parallel computation
[58c0342]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}
[dd57b13]134
135/* Abstract function representing conversion from temperature to color */
[65ec6a4]136$abstract int colorOf(double x);
[dd57b13]137
138/* Sequential algorithm: performs simulation storing result of final
139 * time step in output_seq */
[58c0342]140void main_seq() {
[dd57b13]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;
[58c0342]154 printf("Diffusion1d with nx=%d, k=%f, nsteps=%d, wstep=%d\n",
[dd57b13]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
[58c0342]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);
[dd57b13]186 }
[58c0342]187 free(u);
[dd57b13]188}
189
190/* MPI Process in parallel algorithm */
[58c0342]191void MPI_Process (int rank) {
[dd57b13]192 $scope proc_scope = $here; /* this scope */
[58c0342]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 */
[dd57b13]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
[58c0342]223
224 nprocs = NPROCS;
[dd57b13]225 if (rank == 0) {
226 // in place of reading these from file:
227 nx = NX;
228 k = K;
229 nsteps = NSTEPS;
230 wstep = WSTEP;
[58c0342]231 printf("Diffusion1d with nx=%d, k=%f, nsteps=%d, wstep=%d nprocs=%d\n",
[dd57b13]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);
[58c0342]238 assert(nx>=nprocs);
[dd57b13]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++) {
[58c0342]261 for (j=0; j<countForProc(i); j++)
[dd57b13]262 buf[j] = u_init[pos++];
[58c0342]263 MPI_Send(buf, countForProc(i), MPI_DOUBLE, i, 0, MPI_COMM_WORLD);
[dd57b13]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++)
[58c0342]324 u_new[i] = u[i] + k*(u[i+1] + u[i-1] -2*u[i]);
[dd57b13]325 for (i = start; i <= stop; i++)
326 u[i] = u_new[i];
327 }
328
[58c0342]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);
[dd57b13]336 }
[58c0342]337 free(u);
338 free(u_new);
339 if (rank == 0)
340 free(buf);
341 $comm_destroy(MPI_COMM_WORLD);
[dd57b13]342}
343
[58c0342]344void main_par() {
345 MPI_GCOMM_WORLD = $gcomm_create($root, NPROCS);
[dd57b13]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]);
[58c0342]348 $gcomm_destroy(MPI_GCOMM_WORLD);
[dd57b13]349}
350
351void main() {
[58c0342]352 main_seq();
353 main_par();
354 for (int i=0; i<NX; i++)
[dd57b13]355 $assert(output_seq[i]==output_par[i]);
356}
Note: See TracBrowser for help on using the repository browser.