source: CIVL/examples/mpi/diffusion1d.c@ 4e86cdd

1.23 2.0 main test-branch
Last change on this file since 4e86cdd was 3ff27cf, checked in by Manchun Zheng <zmanchun@…>, 11 years ago

updated examples since $assert/$assume has been changed to functions; fixed the model builder for the new side-effect remover.

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

  • Property mode set to 100644
File size: 6.0 KB
RevLine 
[3ff27cf]1#ifdef _CIVL
2#include <civlc.cvh>
3#endif
[f0f2c558]4/* diffusion1d.c: parallel 1d-diffusion solver with constant boundary.
5 * To execute: mpicc diffusion1d.c ; mpiexec -n 4 ./a.out
6 * Or replace "4" with however many procs you want to use.
7 * To verify: civl verify diffusion1d.c
8 */
9#include <stdlib.h>
10#include <stdio.h>
11#include <assert.h>
12#include <mpi.h>
13#define OWNER(index) ((nprocs*(index+1)-1)/nx)
14
15#ifdef _CIVL
16
17$input int NXB = 5; // upper bound on nx
18$input int nx; // global number of points excl. boundary
[3ff27cf]19$assume(1<=nx && nx<=NXB);
[f0f2c558]20$input double U_INIT[nx+2]; // initial values for temperature incl. boundary
21$input double k; // the constant D*dt/(dx*dx)
[3ff27cf]22$assume(k>0 && k<.5);
[f0f2c558]23$input int NSTEPS_BOUND=5; // upper bound on nsteps
24$input int nsteps; // number of time steps
[3ff27cf]25$assume(1<=nsteps && nsteps<=NSTEPS_BOUND);
[f0f2c558]26$input int wstep; // write frame every this many time steps
[3ff27cf]27$assume(1<=wstep && wstep<=nsteps);
[f0f2c558]28double oracle[nsteps][nx+2]; // solution computed sequentially, proc 0 only
29int _NPROCS_LOWER_BOUND = 1;
30int _NPROCS_UPPER_BOUND = 3;
31
32#else
33
34int nx;
35double k;
36int nsteps;
37int wstep;
38
39#endif
40
41/* Global variables */
42
43double lbound; /* left fixed boundary value */
44double rbound; /* right fixed boundary value */
45double *u; /* temperature function, local */
46double *u_new; /* second copy of temperature function, local */
47int nprocs; /* number of processes */
48int rank; /* the rank of this process */
49int left; /* rank of left neighbor */
50int right; /* rank of right neighbor on torus */
51int nxl; /* horizontal extent of one process */
52int first; /* global index for local index 0 */
53double *buf; /* temp. buffer used on proc 0 only */
54int print_pos; /* number of cells printed on current line */
55int time=0; /* current time step */
56
57
58/* Returns the global index of the first cell owned
59 * by the process with given rank */
60int firstForProc(int rank) {
61 return (rank*nx)/nprocs;
62}
63
64/* Returns the number of cells owned by the process
65 * of the given rank (excluding ghosts) */
66int countForProc(int rank) {
67 int a = firstForProc(rank+1);
68 int b = firstForProc(rank);
69
70 return a-b;
71}
72
73/* Initializes the global variables.
74 * Precondition: the configuration parameters have
75 * already been set. */
76void init_globals() {
77 MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
78 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
79 // nxl: number actual points (incl. end-points)
80 // nxl+2: size of array (incl. ghost cells)
81 first = firstForProc(rank);
82 nxl = countForProc(rank);
83 left = first==0 || nxl==0 ? MPI_PROC_NULL : OWNER(first-1);
84 right = first+nxl >= nx || nxl == 0 ? MPI_PROC_NULL : OWNER(first+nxl);
85 u = (double*)malloc((nxl+2)*sizeof(double));
86 assert(u);
87 u_new = (double*)malloc((nxl+2)*sizeof(double));
88 assert(u_new);
89 if (rank == 0)
90 buf = (double*)malloc((1+nx/nprocs)*sizeof(double));
91}
92
93void initialize() {
94#ifdef _CIVL
95 //elaborate nx to concrete value...
96 for (int i=0; i<nx; i++);
97 // initialize globals and u...
98 init_globals();
99 lbound = U_INIT[0];
100 rbound = U_INIT[nx+1];
101 for (int i=1; i<=nxl; i++)
102 u[i] = U_INIT[first+i];
103 if (rank == 0) {
104 // compute the oracle...
105 for (int i=0; i<nx+2; i++)
106 oracle[0][i]=U_INIT[i];
107 for (int t=1; t<nsteps; t++) {
108 oracle[t][0] = lbound;
109 for (int i=1; i<=nx; i++)
110 oracle[t][i] = oracle[t-1][i] +
111 k*(oracle[t-1][i+1] + oracle[t-1][i-1]
112 - 2*oracle[t-1][i]);
113 oracle[t][nx+1] = rbound;
114 }
115 }
116#else
117 nx = 10;
118 k = 0.2;
119 nsteps = 20;
120 wstep = 2;
121 lbound = rbound = 0.0;
122 init_globals();
123 for (int i=1; i<=nxl; i++)
124 u[i]=100.0;
125#endif
126 if (nx>=1 && rank == OWNER(0))
127 u[0] = u_new[0] = lbound;
128 if (nx>=1 && rank == OWNER(nx-1))
129 u[nxl+1] = u_new[nxl+1] = rbound;
130 //if (rank == 0)
131 //printf("nx=%d, k=%lf, nsteps=%d, wstep=%d, nprocs=%d\n",
132 // nx, k, nsteps, wstep, nprocs);
133}
134
135/* Prints header for time step. Called by proc 0 only */
136void print_time_header() {
137 //printf("======= Time %d =======\n", time);
138 print_pos = 0;
139}
140
141/* Prints one cell. Called by proc 0 only. */
142void print_cell(double value) {
143 //printf("%7.2f\n", value);
[3ff27cf]144#pragma CIVL $assert(value == oracle[time][print_pos], \
[f0f2c558]145 "Error: disagreement at time %d position %d: saw %lf, expected %lf", \
[3ff27cf]146 time, print_pos, value, oracle[time][print_pos]);
[f0f2c558]147 print_pos++;
148}
149
150/* Prints the current values of u. */
151void write_frame() {
152 if (rank != 0) {
153 MPI_Send(u+1, nxl, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
154 } else {
155 print_time_header();
156 print_cell(lbound); // left boundary
157 for (int source = 0; source < nprocs; source++) {
158 int count;
159
160 if (source != 0) {
161 MPI_Status status;
162
163 MPI_Recv(buf, 1+nx/nprocs, MPI_DOUBLE, source, 0, MPI_COMM_WORLD,
164 &status);
165 MPI_Get_count(&status, MPI_DOUBLE, &count);
166 } else {
167 for (int i = 1; i <= nxl; i++)
168 buf[i-1] = u[i];
169 count = nxl;
170 }
171 for (int i = 0; i < count; i++)
172 print_cell(buf[i]);
173 }
174 print_cell(rbound); // right boundary
175 //printf("\n");
176 }
177}
178
179/* exchange_ghost_cells: updates ghost cells using MPI communication */
180void exchange_ghost_cells() {
181 MPI_Sendrecv(&u[1], 1, MPI_DOUBLE, left, 0,
182 &u[nxl+1], 1, MPI_DOUBLE, right, 0,
183 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
184 MPI_Sendrecv(&u[nxl], 1, MPI_DOUBLE, right, 0,
185 &u[0], 1, MPI_DOUBLE, left, 0,
186 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
187}
188
189/* Updates u_new using u, then swaps u and u_new.
190 * Reads the ghost cells in u. Purely local operation. */
191void update() {
192 for (int i = 1; i <= nxl; i++)
193 u_new[i] = u[i] + k*(u[i+1] + u[i-1] - 2*u[i]);
194 double * tmp = u_new; u_new=u; u=tmp;
195}
196
197/* Executes the simulation. */
198int main(int argc, char *argv[]) {
199 MPI_Init(&argc, &argv);
200 initialize();
201 write_frame();
202 printf("nx = %d", nx);
203 for (time=1; time < nsteps; time++) {
204 exchange_ghost_cells();
205 update();
206 if (time%wstep==0)
207 write_frame();
208 }
209 MPI_Finalize();
210 free(u);
211 free(u_new);
212 if (rank == 0)
213 free(buf);
214 return 0;
215}
Note: See TracBrowser for help on using the repository browser.