source: CIVL/examples/compare/diffusion1d/diffusion1d_par_revision.c@ 397ae5f

main test-branch
Last change on this file since 397ae5f was ea777aa, checked in by Alex Wilton <awilton@…>, 3 years ago

Moved examples, include, build_default.properties, common.xml, and README out from dev.civl.com into the root of the repo.

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

  • Property mode set to 100644
File size: 9.1 KB
RevLine 
[3ff27cf]1#ifdef _CIVL
2#include <civlc.cvh>
3#endif
[0966332]4/* FEVS: A Functional Equivalence Verification Suite for High-Performance
5 * Scientific Computing
6 *
7 * Copyright (C) 2009-2010, Stephen F. Siegel, Timothy K. Zirkel,
8 * University of Delaware
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 3 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 * 02110-1301 USA.
24 */
25
26
27/*
28 * diffusion1d.c: parallel 1d-diffusion simulation.
29 */
30#include <string.h>
31#include <stdlib.h>
32#include <stdio.h>
33#include <assert.h>
34#include <math.h>
35#include <mpi.h>
36#define OWNER(index) ((nprocs*(index+1)-1)/nx)
37#pragma CIVL $input int NX;
38/* Upper bound for NX */
39#pragma CIVL $input int NXB;
40#pragma CIVL $input double K;
41#pragma CIVL $input int NSTEPS;
42/* Upper bound for NSTEPS */
43#pragma CIVL $input int NSTEPSB;
44#pragma CIVL $input int WSTEP;
45#pragma CIVL $output double u_output[NX];
[3ff27cf]46#pragma CIVL $assume(2 < NX && NX <= NXB);
47#pragma CIVL $assume(0 < NSTEPS && NSTEPS <= NSTEPSB);
[0966332]48
49/* Parameters: These are defined at the beginning of the input file:
50 *
51 * nx = number of points in x direction, including endpoints
52 * k = D*dt/(dx*dx)
53 * nsteps = number of time steps
54 * wstep = write frame every this many steps
55 *
56 * Compiling with the flag -DDEBUG will also cause the data to be written
57 * to a sequence of plain text files.
58 */
59
60/* Global variables */
61
62int nx = -1; /* number of discrete points including endpoints */
63double k = -1; /* D*dt/(dx*dx) */
64int nsteps = -1; /* number of time steps */
65int wstep = -1; /* write frame every this many time steps */
66// Initialize pointers with NULL so that these
67// pointers can be checked if it's malloced already.
68double *u = NULL; /* temperature function */
69double *u_new = NULL; /* temp. used to update u */
70
71int nprocs; /* number of processes */
72int rank; /* the rank of this process */
73int left; /* rank of left neighbor */
74int right; /* rank of right neighbor on torus */
75int nxl; /* horizontal extent of one process */
76int first; /* global index for local index 0 */
77int start; /* first local index to update */
78int stop; /* last local index to update */
79double *buf; /* temp. buffer used on proc 0 only */
80
81int firstForProc(int rank) {
82 return (rank*nx)/nprocs;
83}
84
85int countForProc(int rank) {
86 int a;
87 int b;
88
89 a = firstForProc(rank+1);
90 b = firstForProc(rank);
91 return a-b;
92}
93
94// Added a argument of File pointer so that file can be closed before the
95// program exit.
96void quit(FILE * file) {
97 printf("Input file must have format:\n\n");
98 printf("nx = <INTEGER>\n");
99 printf("k = <DOUBLE>\n");
100 printf("nsteps = <INTEGER>\n");
101 printf("wstep = <INTEGER>\n");
102 printf("<DOUBLE> <DOUBLE> ...\n\n");
103 printf("where there are nx doubles at the end.\n");
104 fflush(stdout);
105 // Missing free(u) and fclose(file) probably is a bug
106 if(u != NULL)
107 free(u);
108 fclose(file);
109 // Following statements should be added in $exit() or added by CIVL automatically
110 exit(1);
111}
112
113void readint(FILE *file, char *keyword, int *ptr) {
114 char buf[101];
115 int value;
116 int returnval;
117
118 returnval = fscanf(file, "%100s", buf);
119 if (returnval != 1) quit(file);
120 // fscanf can only make the output argument symbolic, so the
121 // following comparison will always enable 2 transitions.
122 // Trivially, for verification of the computing results of sequential program,
123 // we can ignore the transition of executing "quit()". For concurrent programs,
124 // ,especially for mpi programs, any one of processes terminated exceptionally
125 // will make the some rest processes go into a dead lock (e.g.MPI_Recv forever).
[3ff27cf]126#pragma CIVL $assume(strcmp(keyword, buf) == 0);
[0966332]127 if (strcmp(keyword, buf) != 0) quit(file);
128 returnval = fscanf(file, "%10s", buf);
129 if (returnval != 1) quit(file);
[3ff27cf]130#pragma CIVL $assume(strcmp("=", buf) == 0);
[0966332]131 if (strcmp("=", buf) != 0) quit(file);
132 returnval = fscanf(file, "%d", ptr);
133 if (returnval != 1) quit(file);
134}
135
136void readdouble(FILE *file, char *keyword, double *ptr) {
137 char buf[101];
138 int value;
139 int returnval;
140
141 returnval = fscanf(file, "%100s", buf);
142 if (returnval != 1) quit(file);
[3ff27cf]143#pragma CIVL $assume(strcmp(keyword, buf) == 0);
[0966332]144 if (strcmp(keyword, buf) != 0) quit(file);
145 returnval = fscanf(file, "%10s", buf);
146 if (returnval != 1) quit(file);
[3ff27cf]147#pragma CIVL $assume(strcmp("=", buf) == 0);
[0966332]148 if (strcmp("=", buf) != 0) quit(file);
149 returnval = fscanf(file, "%lf", ptr);
150 if (returnval != 1) quit(file);
151}
152
153/* init: initializes global variables. */
154void init(char* infilename) {
155 char keyword[101];
156 FILE *infile = fopen(infilename, "r");
157 int i, j;
158
159 MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
160 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
161 if (rank == 0) {
162 assert(infile);
163 readint(infile, "nx", &nx);
164 readdouble(infile, "k", &k);
165 readint(infile, "nsteps", &nsteps);
166 readint(infile, "wstep", &wstep);
[3ff27cf]167#pragma CIVL $assume(nx == NX);
168#pragma CIVL $assume(nsteps == NSTEPS);
169#pragma CIVL $assume(wstep == WSTEP);
170#pragma CIVL $assume(0.0 < k && k < 0.5);
[0966332]171 printf("Diffusion1d with nx=%d, k=%f, nsteps=%d, wstep=%d nprocs=%d\n",
172 nx, k, nsteps, wstep, nprocs);
173 }
174 MPI_Bcast(&nx, 1, MPI_INT, 0, MPI_COMM_WORLD);
175 MPI_Bcast(&k, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
176 MPI_Bcast(&nsteps, 1, MPI_INT, 0, MPI_COMM_WORLD);
177 MPI_Bcast(&wstep, 1, MPI_INT, 0, MPI_COMM_WORLD);
178
179 assert(k>0 && k<.5);
180 assert(nx>=2);
181 assert(nsteps>=1);
182
183 // nxl: number actual points (incl. end-points)
184 // nxl+2: size of array (incl. ghost cells)
185 first = firstForProc(rank);
186 nxl = countForProc(rank);
187 if (first == 0 || nxl == 0) left = MPI_PROC_NULL; else left = OWNER(first-1);
188 if (first+nxl >= nx || nxl == 0) right = MPI_PROC_NULL; else right = OWNER(first+nxl);
189
190 u = (double*)malloc((nxl+2)*sizeof(double));
191 assert(u!=NULL);
192 u_new = (double*)malloc((nxl+2)*sizeof(double));
193 assert(u_new);
194 if (rank == 0) {
195 buf = (double*)malloc((1+nx/nprocs)*sizeof(double));
196 for (i=1; i <= nxl; i++){
197 if (fscanf(infile, "%lf", u+i) != 1) quit(infile);
198 }
199 for (i=1; i < nprocs; i++){
200 for (j=0; j<countForProc(i); j++){
201 if (fscanf(infile, "%lf", buf+j) != 1) quit(infile);
202 }
203 /* Side-effsect removal */
204 int count4proc = countForProc(i);
205 MPI_Send(buf, count4proc, MPI_DOUBLE, i, 0, MPI_COMM_WORLD);
206 }
207 }
208 else {
209 MPI_Recv(u+1, nxl, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
210 }
211 if (rank == OWNER(0)) {
212 start = 2;
213 }
214 else {
215 start = 1;
216 }
217 if (rank == OWNER(nx-1)) {
218 stop = nxl - 1;
219 }
220 else {
221 stop = nxl;
222 }
223 if (rank == 0) {
224 /* Catch a real bug of this program here :
225 Re-malloc on one pointer without free for
226 the previous one. */
227 free(buf);
228 buf = (double*)malloc((1+nx/nprocs)*sizeof(double));
229 assert(buf);
230 } else {
231 buf = NULL;
232 }
233 // Missing "fclose()" here.
234 fclose(infile);
235}
236
237// write_plain() is re-written because of not support sprintf() currently.
238void write_plain(int time) {
239 if (rank != 0) {
240 MPI_Send(u+1, nxl, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
241 } else {
242 int source, count, i;
243 MPI_Status status;
244
245 for (source = 0; source < nprocs; source++) {
246 if (source != 0) {
247 MPI_Recv(buf, 1+nx/nprocs, MPI_DOUBLE, source, 0, MPI_COMM_WORLD,
248 &status);
249 MPI_Get_count(&status, MPI_DOUBLE, &count);
250 } else {
251 for (i = 1; i <= nxl; i++) buf[i-1] = u[i];
252 count = nxl;
253 }
254 for (i = 0; i < count; i++) {
[46fedf0]255 int firstIdx = firstForProc(source);
256#pragma CIVL u_output[firstIdx + i] = buf[i];
[0966332]257 }
258 }
259 }
260}
261
262/* exchange_ghost_cells: updates ghost cells using MPI communication */
263void exchange_ghost_cells() {
264 MPI_Sendrecv(&u[1], 1, MPI_DOUBLE, left, 0,
265 &u[nxl+1], 1, MPI_DOUBLE, right, 0,
266 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
267 MPI_Sendrecv(&u[nxl], 1, MPI_DOUBLE, right, 0,
268 &u[0], 1, MPI_DOUBLE, left, 0,
269 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
270}
271
272/* update: updates u. Uses ghost cells. Purely local operation. */
273void update() {
274 int i;
275
276 for (i = start; i <= stop; i++)
277 u_new[i] = u[i] + k*(u[i+1] + u[i-1] -2*u[i]);
278 for (i = start; i <= stop; i++)
279 u[i] = u_new[i];
280}
281
282/* main: executes simulation, creates one output file for each time
283 * step */
284int main(int argc,char *argv[]) {
285 int iter;
286
287 MPI_Init(&argc, &argv);
[3ff27cf]288#pragma CIVL $assume((argc == 2));
[0966332]289 assert(argc==2);
290 init(argv[1]);
291 write_plain(0);
292 for (iter = 1; iter <= nsteps; iter++) {
293 exchange_ghost_cells();
294 update();
295 if (iter%wstep==0) write_plain(iter);
296 }
297 MPI_Finalize();
298 free(u);
299 free(u_new);
300 if (rank == 0) {
301 free(buf);
302 }
303
[46fedf0]304 return 0;
[0966332]305}
Note: See TracBrowser for help on using the repository browser.