source: CIVL/examples/messagePassing/diffusion1d.cvl@ 20a83c7

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

Small improvement to diffusion1d.cvl, adding notes on io.

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

  • Property mode set to 100644
File size: 8.1 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 \
11 -inputNXB=6 diffusion1d_good.cvl
12 */
13#include <civlc.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <assert.h>
17#include "mpi.cvl"
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 WSTEP >= 1 && WSTEP <= NSTEPS;
37// $assume NX >= NPROCS;
38$assume 1 <= NPROCS && NPROCS <= NPROCSB;
39$assume 1 <= NSTEPS && NSTEPS <= NSTEPSB;
40
41// global variables:
42int output_seq[NX]; // final (color) result of sequential computation
43int output_par[NX]; // final (color) result of parallel computation
44CMPI_Gcomm MPI_GCOMM_WORLD; // the global communicator object
45
46/* Abstract function representing conversion from temperature to color */
47$abstract int colorOf(double x);
48
49/* Sequential algorithm: performs simulation storing result of final
50 * time step in output_seq */
51void run_seq() {
52 $scope seq_scope = $here;
53 int nx, nsteps, wstep;
54 double k, *u;
55
56 void init() {
57 int i;
58 int pos = 0; // file position
59
60 // in place of reading these from file:
61 nx = NX;
62 nsteps = NSTEPS;
63 wstep = WSTEP;
64 k = K;
65 printf("Diffusion1d (seq) with nx=%d, k=%f, nsteps=%d, wstep=%d\n",
66 nx, k, nsteps, wstep);
67 assert(nx>=2);
68 assert(k>0 && k<.5);
69 assert(nsteps >= 1);
70 assert(wstep >= 1 && wstep <=nsteps);
71 u = (double*)$malloc(seq_scope, nx*sizeof(double));
72 assert(u);
73 for (i = 0; i < nx; i++) u[i] = u_init[pos++];
74 }
75
76 void write_frame(int time) {
77 for (int i=0; i<nx; i++)
78 output_seq[i] = colorOf(u[i]);
79 }
80
81 void update() {
82 int i;
83 double u_new[nx];
84
85 for (i = 1; i < nx-1; i++)
86 u_new[i] = u[i] + k*(u[i+1] + u[i-1] -2*u[i]);
87 for (i = 1; i < nx-1; i++)
88 u[i] = u_new[i];
89 }
90
91 void _main() {
92 int iter;
93
94 init();
95 write_frame(0);
96 for (iter = 1; iter <= nsteps; iter++) {
97 update();
98 if (iter%wstep==0) write_frame(iter);
99 }
100 free(u);
101 }
102
103 _main();
104}
105
106/* MPI Process in parallel algorithm */
107void MPI_Process (int _rank) {
108 $scope proc_scope = $here; /* this scope */
109 MPI_Comm MPI_COMM_WORLD;
110
111 int nx = -1; /* number of discrete points including endpoints */
112 double k = -1; /* D*dt/(dx*dx) */
113 int nsteps = -1; /* number of time steps */
114 int wstep = -1; /* write frame every this many time steps */
115 double *u; /* temperature function */
116 double *u_new; /* temp. used to update u */
117
118 int nprocs; /* number of processes */
119 int rank; /* the rank of this process */
120 int left; /* rank of left neighbor */
121 int right; /* rank of right neighbor on torus */
122 int nxl; /* horizontal extent of one process */
123 int first; /* global index for local index 0 */
124 int start; /* first local index to update */
125 int stop; /* last local index to update */
126 double *buf; /* temp. buffer used on proc 0 only */
127
128 int firstForProc(int rank) {
129 return (rank*nx)/nprocs;
130 }
131
132 int countForProc(int rank) {
133 int a;
134 int b;
135
136 a = firstForProc(rank+1);
137 b = firstForProc(rank);
138 return a-b;
139 }
140
141 /* init: initializes global variables. */
142 void init() {
143 int i, j;
144 int pos = 0; // position in input file
145
146 MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
147 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
148 if (rank == 0) {
149 // in place of reading these from file:
150 nx = NX;
151 k = K;
152 nsteps = NSTEPS;
153 wstep = WSTEP;
154 printf("Diffusion1d (par) with nx=%d, k=%f, nsteps=%d, wstep=%d nprocs=%d\n",
155 nx, k, nsteps, wstep, nprocs);
156 }
157 MPI_Bcast(&nx, 1, MPI_INT, 0, MPI_COMM_WORLD);
158 MPI_Bcast(&k, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
159 MPI_Bcast(&nsteps, 1, MPI_INT, 0, MPI_COMM_WORLD);
160 MPI_Bcast(&wstep, 1, MPI_INT, 0, MPI_COMM_WORLD);
161 // assert(nx>=nprocs);
162 assert(k>0 && k<.5);
163 assert(nx>=2);
164 assert(nsteps>=1);
165 first = firstForProc(rank);
166 nxl = countForProc(rank);
167 if (first == 0 || nxl == 0)
168 left = MPI_PROC_NULL;
169 else
170 left = OWNER(first-1);
171 if (first+nxl >= nx || nxl == 0)
172 right = MPI_PROC_NULL;
173 else
174 right = OWNER(first+nxl);
175 u = (double*)$malloc(proc_scope, (nxl+2)*sizeof(double));
176 assert(u != NULL);
177 u_new = (double*)$malloc(proc_scope, (nxl+2)*sizeof(double));
178 assert(u_new != NULL);
179 if (rank == 0) {
180 buf = (double*)$malloc(proc_scope, (1+nx/nprocs)*sizeof(double));
181 for (i=1; i <= nxl; i++)
182 u[i] = u_init[pos++]; // instead of reading from file
183 for (i=1; i < nprocs; i++) {
184 int count_i = countForProc(i);
185
186 for (j=0; j<count_i; j++)
187 buf[j] = u_init[pos++];
188 MPI_Send(buf, count_i, MPI_DOUBLE, i, 0, MPI_COMM_WORLD);
189 }
190 }
191 else {
192 buf = NULL;
193 MPI_Recv(u+1, nxl, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
194 }
195 if (rank == OWNER(0)) {
196 start = 2;
197 }
198 else {
199 start = 1;
200 }
201 if (rank == OWNER(nx-1)) {
202 stop = nxl - 1;
203 }
204 else {
205 stop = nxl;
206 }
207 }
208
209 void write_frame(int time) {
210 if (rank != 0) {
211 MPI_Send(u+1, nxl, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
212 } else {
213 int source, i, j, count, global_index;
214 MPI_Status status;
215
216 global_index = 0;
217 for (source = 0; source < nprocs; source++) {
218 if (source != 0) {
219 MPI_Recv(buf, 1+nx/nprocs, MPI_DOUBLE, source, 0,
220 MPI_COMM_WORLD, &status);
221 MPI_Get_count(&status, MPI_DOUBLE, &count);
222 } else {
223 for (i = 1; i <= nxl; i++) buf[i-1] = u[i];
224 count = nxl;
225 }
226 for (i = 0; i < count; i++) {
227 output_par[global_index] = colorOf(buf[i]);
228 global_index++;
229 }
230 }
231 }
232 }
233
234 /* exchange_ghost_cells: updates ghost cells using MPI communication */
235 void exchange_ghost_cells() {
236 MPI_Sendrecv(&u[1], 1, MPI_DOUBLE, left, 0,
237 &u[nxl+1], 1, MPI_DOUBLE, right, 0,
238 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
239 MPI_Sendrecv(&u[nxl], 1, MPI_DOUBLE, right, 0,
240 &u[0], 1, MPI_DOUBLE, left, 0,
241 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
242 }
243
244 /* update: updates u. Uses ghost cells. Purely local operation. */
245 void update() {
246 int i;
247
248 for (i = start; i <= stop; i++)
249 u_new[i] = u[i] + k*(u[i+1] + u[i-1] - 2*u[i]);
250 for (i = start; i <= stop; i++)
251 u[i] = u_new[i];
252 }
253
254 void _main() {
255 int iter;
256
257 MPI_Init();
258 MPI_COMM_WORLD = MPI_Comm_create(proc_scope, MPI_GCOMM_WORLD, _rank);
259 init();
260 write_frame(0);
261 for (iter = 1; iter <= nsteps; iter++) {
262 exchange_ghost_cells();
263 update();
264 if (iter%wstep==0) write_frame(iter);
265 }
266 MPI_Finalize();
267 MPI_Comm_destroy(MPI_COMM_WORLD);
268 free(u);
269 free(u_new);
270 if (rank == 0)
271 free(buf);
272 }
273
274 _main();
275}
276
277void run_par() {
278 $proc procs[NPROCS]; // the MPI processes
279
280 MPI_GCOMM_WORLD = CMPI_Gcomm_create($root, NPROCS);
281 for (int i=0; i<NPROCS; i++) procs[i] = $spawn MPI_Process(i);
282 for (int i=0; i<NPROCS; i++) $wait(procs[i]);
283 CMPI_Gcomm_destroy(MPI_GCOMM_WORLD);
284}
285
286void main() {
287 for (int i=0; i<NX; i++) ;
288 for (int i=0; i<NSTEPS; i++) ;
289 for (int i=0; i<WSTEP; i++) ;
290 for (int i=0; i<NPROCS; i++) ;
291
292 for (int i=0; i<NX; i++) u_init[i] = i;
293
294 run_seq();
295 run_par();
296 for (int i=0; i<NX; i++) {
297 printf("output[%d] = %d\n", i, output_seq[i]);
298 $assert(output_seq[i]==output_par[i]);
299 }
300}
Note: See TracBrowser for help on using the repository browser.