source: CIVL/examples/translation/mpi/wave1d.c@ c816cf9

1.23 2.0 acw/focus-triggers main test-branch
Last change on this file since c816cf9 was b88607e, checked in by Ziqing Luo <ziqing@…>, 12 years ago

changed Makefile and modifies waved1d with comments from Dr.Siegel

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

  • Property mode set to 100644
File size: 7.2 KB
Line 
1/* wave1d.c: parallel 1d-wave equation solver with constant boundary.
2 * To execute: mpicc wave1d.c ; mpiexec -n 4 ./a.out
3 * Or replace "4" with however many procs you want to use.
4 * To verify: civl verify wave1d.c
5 */
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <assert.h>
10#include <math.h>
11#include <mpi.h>
12
13#define SQR(x) ((x)*(x))
14#define OWNER(index) ((nprocs*(index+1)-1)/nx)
15
16/* MPI message tag */
17#define FROMLEFT 1
18#define FROMRIGHT 2
19#define DATAPASS 3
20
21/* Input parameters */
22#ifdef _CIVL
23
24$input int NXB = 5;
25$input int nx; /* number of discrete points including endpoints */
26$assume 2 <= nx && nx <= NXB; /* setting bounds */
27$input double c; /* physical constant to do with string */
28$assume c > 0.0;
29$input int NSTEPSB = 5;
30$input int nsteps; /* number of iterations */
31$assume 0 < nsteps && nsteps <= NSTEPSB;
32$input int wstep = 1;
33$input int _NPROCS_LOWER_BOUND = 1;
34$input int _NPROCS_UPPER_BOUND = 4;
35double oracle[nsteps][nx]; /* array stores the results of sequential run in every step */
36$input double u_init[nx]; /* arbitrary input data */
37
38#else
39
40int nx, height_init, width_init;
41int nsteps, wstep;
42double c;
43double * u_init;
44
45#endif
46
47/* Global varibales */
48double *u_prev, *u_curr, *u_next;
49double k;
50int nprocs, nxl, rank;
51int first; /* the first index of cells in global array */
52int left, right; /* left neighbor and right neighbor */
53
54/* Returns the global index of the first cell owned
55 * by the process with given rank */
56int firstForProc(int rank) {
57 return (rank*nx)/nprocs;
58}
59
60/* Returns the number of cells
61 the given process owns */
62int countForProc(int rank) {
63 int a = firstForProc(rank);
64 int b = firstForProc(rank + 1);
65
66 return b - a;
67}
68
69#ifndef _CIVL
70
71/* Initialize data array for running in MPI */
72void init() {
73 int i;
74 double e = exp(1.0);
75
76 for(i = 0; i < nx; i++) {
77 if(i == 1 || i >= width_init)
78 u_init[i] = 0.0;
79 else
80 u_init[i] = height_init * e *
81 exp(-1.0/(1-SQR(2.0*(i-width_init/2.0)/width_init)));
82 }
83}
84
85#endif
86
87/* Update cells owned by processes */
88void update() {
89 int i;
90 double *tmp;
91
92 for (i = 1; i < nxl + 1; i++){
93 u_next[i] = 2.0*u_curr[i] - u_prev[i] +
94 k*(u_curr[i+1] + u_curr[i-1] -2.0*u_curr[i]);
95 }
96 //cycle pointers
97 tmp = u_prev;
98 u_prev = u_curr;
99 u_curr = u_next;
100 u_next = tmp;
101}
102
103/* Initialization function, initializes all parameters and data array
104 process 0 is responsible run in sequential for computing data for
105 comparison */
106void initialization() {
107 int i, j;
108
109#ifndef _CIVL
110
111 nx = 50;
112 c = 0.3;
113 height_init = 10;
114 width_init = 10;
115 nsteps = 500;
116 wstep = 5;
117 u_init = (double *)malloc(nx * sizeof(double));
118 init();
119
120#endif
121
122 printf("Wave1d with nx=%d, c=%f, nsteps=%d, wstep=%d\n", nx, c, nsteps, wstep);
123 assert(nx >= 2);
124 assert(c > 0);
125 assert(nsteps >= 1);
126 assert(wstep >= 1 && wstep <= nsteps);
127 k = c * c;
128
129#ifdef _CIVL
130
131 // If in CIVL verification mode and rank is 0,
132 // do a sequential run and store result in "oracle"
133 // for comparison later
134 if(rank == 0) {
135 double *seq_u_curr, *seq_u_prev, *seq_u_next;
136 double * tmp;
137
138 seq_u_prev = (double *)malloc((nx + 2) * sizeof(double));
139 assert(seq_u_prev);
140 seq_u_curr = (double *)malloc((nx + 2) * sizeof(double));
141 assert(seq_u_curr);
142 seq_u_next = (double *)malloc((nx + 2) * sizeof(double));
143 assert(seq_u_next);
144 //Initialize seq_u_curr and seq_u_prev
145 memcpy(&seq_u_curr[1], u_init, sizeof(double) * nx);
146 memcpy(&seq_u_prev[1], u_init, sizeof(double) * nx);
147 // run in sequential.
148 // wirte data in time 0.
149 for(i = 0; i < nx; i++)
150 oracle[0][i] = seq_u_curr[i + 1];
151 for(i = 1; i < nsteps; i++){
152 // exchange between head cell and tail cell.
153 seq_u_curr[0] = seq_u_curr[nx];
154 seq_u_curr[nx+1] = seq_u_curr[1];
155 // update
156 for (j = 1; j < nx + 1; j++){
157 seq_u_next[j] = 2.0*seq_u_curr[j] - seq_u_prev[j] +
158 k*(seq_u_curr[j+1] + seq_u_curr[j-1] -2.0*seq_u_curr[j]);
159 }
160 tmp = seq_u_prev;
161 seq_u_prev = seq_u_curr;
162 seq_u_curr = seq_u_next;
163 seq_u_next = tmp;
164 for(j = 0; j < nx; j++)
165 oracle[i][j] = seq_u_curr[j + 1];
166 }
167 free(seq_u_prev);
168 free(seq_u_curr);
169 free(seq_u_next);
170 }
171
172#endif
173
174 nxl = countForProc(rank);
175 first = firstForProc(rank);
176 u_prev = (double *)malloc((nxl + 2) * sizeof(double));
177 assert(u_prev);
178 u_curr = (double *)malloc((nxl + 2) * sizeof(double));
179 assert(u_curr);
180 u_next = (double *)malloc((nxl + 2) * sizeof(double));
181 assert(u_next);
182 // skip processes which are allocated no cells
183 if(first != 0)
184 left = OWNER(first - 1);
185 else
186 left = OWNER(nx-1);
187 if(first + nxl < nx)
188 right = OWNER(first + nxl);
189 else
190 right = OWNER(0);
191}
192
193/* Print out the value of data cells;
194 Do comparison in CIVL mode */
195void printData (int time, int first, int length, double * buf) {
196 int i;
197
198 for(i = 0; i < length; i++){
199 printf("u_curr[%d]=%8.8f ", first + i, buf[i]);
200#ifdef _CIVL
201
202 $assert (oracle[time][first + i] == buf[i]): \
203 "Error: disagreement at time %d position %d: saw %lf, expected %lf", \
204 time, first + i, buf[i], oracle[time][first + i];
205
206#endif
207 if(i%2 == 0) printf("\n");
208 }
209}
210
211/* receives data from other processes and wirte frames */
212void write_frame (int time) {
213 if(rank == 0) {
214 double buf[nx + 2];
215 MPI_Status status;
216
217 printf("======= Time %d =======\n", time);
218 printData(time, first, nxl, &u_curr[1]);
219 for(int i=1; i < nprocs; i++) {
220 int displ = firstForProc(i);
221 int count;
222
223 MPI_Recv(buf, nx, MPI_DOUBLE, i, DATAPASS, MPI_COMM_WORLD, &status);
224 MPI_Get_count(&status, MPI_DOUBLE, &count);
225 printData(time, displ, count, buf);
226 }
227 printf("\n");
228 } else
229 MPI_Send(&u_curr[1], nxl, MPI_DOUBLE, 0, DATAPASS, MPI_COMM_WORLD);
230}
231
232/* Exchanging ghost cells */
233void exchange(){
234 MPI_Sendrecv(&u_curr[1], 1, MPI_DOUBLE, left, FROMRIGHT, &u_curr[nxl+1], 1, MPI_DOUBLE,
235 right, FROMRIGHT, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
236 MPI_Sendrecv(&u_curr[nxl], 1, MPI_DOUBLE, right, FROMLEFT, &u_curr[0], 1,
237 MPI_DOUBLE, left, FROMLEFT, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
238}
239
240int main(int argc, char * argv[]) {
241 int iter;
242
243 // elaborate nx to concrete value...
244 for(int i=0; i<nx; i++);
245 MPI_Init(&argc, &argv);
246 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
247 MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
248 initialization();
249 if(rank == 0) {
250 // Send every process their cells
251 for(int i=1; i < nprocs; i++) {
252 int first = firstForProc(i);
253 int count = countForProc(i);
254
255 MPI_Send(&u_init[first], count, MPI_DOUBLE, i, DATAPASS, MPI_COMM_WORLD);
256 }
257 memcpy(&u_prev[1], u_init, sizeof(double) * nxl);
258 memcpy(&u_curr[1], u_init, sizeof(double) * nxl);
259 } else {
260 MPI_Recv(&u_curr[1], nxl, MPI_DOUBLE, 0, DATAPASS, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
261 memcpy(&u_prev[1], &u_curr[1], sizeof(double) * nxl);
262 }
263 for(iter = 0; iter < nsteps; iter++) {
264 if(iter % wstep == 0)
265 write_frame(iter);
266 if(nxl != 0){
267 exchange();
268 update();
269 }
270 }
271 free(u_curr);
272 free(u_prev);
273 free(u_next);
274 MPI_Finalize();
275 return 0;
276}
Note: See TracBrowser for help on using the repository browser.