source: CIVL/examples/messagePassing/diffusion1d_good.cvl@ 70e7b0f

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

Separated out the point-to-point from the collective state by
creating a pair of comms for every MPI communicator.

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

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