source: CIVL/examples/messagePassing/diffusion1d_par.cvl@ a8ca3d3

1.23 2.0 main test-branch
Last change on this file since a8ca3d3 was 0b9a80a, checked in by Manchun Zheng <zmanchun@…>, 12 years ago

implemented $scopeof expression; removed unused examples; cleaned up library executors and enablers.

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

  • Property mode set to 100644
File size: 6.9 KB
Line 
1/* Computing the solver for heat equation in multithreads, then compare the
2 * result with the solver got in a sequencial way.
3 *
4 * Command line example:
5 * civl verify -inputNB=10 -inputK=0.3 -inputNSTEPS=5 -inputNX=10 diffusion_1d.c -showAmpleSet
6 * This diffusion1d program computing the diffusion1d equation in parallel and then compare the result with
7 * another result of diffution1d equation computed in sequential.
8 **/
9
10#include<civlc.h>
11#include<stdio.h>
12#define FROM_LEFT 1 /* mpi tag which means the source is send or receive
13 from left u */
14#define FROM_RIGHT 2 /* mpi tag which means the source is send or receive
15 from right u */
16#define REDUCE 3 /* reduce tag */
17$input int NPROCS;
18$input int NPROCSB;
19$input double K; /* k = alpha^2 * dt/(dx^2) */
20$input int NSTEPS; /* time */
21$input int NSTEPSB;
22$input int NX; /* the length of the array */
23$input int NXB;
24$input double initialU[NX];
25$proc __procs[NPROCS];
26_Bool __start = 0;
27$comm MPI_COMM_WORLD;
28$assume 0 < NPROCS && NPROCS <= NPROCSB;
29$assume 0 < NSTEPS && NSTEPS <= NSTEPSB;
30$assume 2 < NX && NX <= NXB;
31
32void MPI_Process (int rank);
33
34void send(void *buf, int count, int dest, int tag, int rank) {
35 $message out = $message_pack(rank, dest, tag, buf, count*sizeof(double));
36 $comm_enqueue(&MPI_COMM_WORLD, out);
37}
38
39void recv(void *buf, int count, int source, int tag, int rank) {
40 $message in = $comm_dequeue(&MPI_COMM_WORLD, source, rank, tag);
41 $message_unpack(in, buf, count*sizeof(double));
42}
43
44void init() {
45 for (int i=0; i<NPROCS; i++)
46 __procs[i] = $spawn MPI_Process(i);
47 MPI_COMM_WORLD = $comm_create(NPROCS, __procs);
48 __start=1;
49}
50
51void finalize() {
52 for (int i=0; i<NPROCS; i++)
53 $wait __procs[i];
54}
55
56void main() {
57 init();
58 finalize();
59}
60
61/* update the array */
62void update(double * u, double * u_new, int start, int end){
63 int i;
64 int u_length = end - start + 1;
65
66 for(i=1; i<u_length+1; i++){
67 u_new[i] = u[i] + K * (u[i-1] + u[i+1] - 2*u[i]);
68 }
69 for(i=1; i<u_length+1; i++){
70 u[i] = u_new[i];
71 }
72}
73
74/* Communicate with left u and right u,
75 send the first interior element to left u and receive for
76 the last interior element */
77void communicate(double * u, int left, int right, int start,
78 int end, int rank){
79 int u_length = end - start + 1;
80 // the most left or right us just need to exchange with one side
81 if(left == -1 && right == -1)
82 return;
83 else if(left == -1){
84 send(&u[u_length], 1, right, FROM_LEFT, rank);
85 recv(&u[u_length + 1], 1, right, FROM_RIGHT, rank);
86 }
87 else if(right == -1){
88 send(&u[1], 1, left, FROM_RIGHT, rank);
89 recv(&u[0], 1, left, FROM_LEFT, rank);
90 }else{
91 send(&u[u_length], 1, right, FROM_LEFT, rank);
92 send(&u[1], 1, left, FROM_RIGHT, rank);
93 recv(&u[u_length + 1], 1, right, FROM_RIGHT, rank);
94 recv(&u[0], 1, left, FROM_LEFT, rank);
95 }
96}
97
98/* compute the value of start, end, left u and right u
99 return an array with those values in such order*/
100int uProperties(int length, int nprocs, int rank, int* results){
101 if(length < 3 )
102 return -1;
103 int remainder = (length - 2) % nprocs;
104 int u_length =(length - 2) / nprocs;
105 int start = rank * u_length + 1;
106
107 //the last u takes the remainder
108 if(rank == nprocs - 1){
109 u_length = u_length + remainder;
110 }
111
112 int end = start + u_length - 1;
113 int left_u = rank - 1;
114 int right_u = rank + 1;
115
116 if(right_u >= nprocs)
117 right_u = -1;
118 results[0] = start;
119 results[1] = end;
120 results[2] = left_u;
121 results[3] = right_u;
122 return 1;
123
124 }
125
126/* the numbers of elements in u and u_new are 2 more than u_length because of
127 ghost elements */
128int initU(double * u, double * u_new, int start, int end,
129 int left_u, int right_u){
130 int i,j;
131 int u_length = end - start + 1; // the number of interior elements
132
133 /* initiate interior array */
134 j = start;
135 for(i=1; i< u_length+1; i++){
136 u[i] = initialU[j];
137 u_new[i] = initialU[j];
138 j++;
139 }
140
141 /* for the most left or right Us, initiate the first ghost element and
142 the last ghost element */
143 if(left_u == -1){
144 u[0] = initialU[0];
145 u_new[0] = initialU[0];
146 }
147 if(right_u == -1){
148 i = u_length + 1;
149 u[i] = initialU[NX-1];
150 u_new[i] = initialU[NX-1];
151 }
152 return u_length;
153}
154
155/* gather separate results from all processes */
156void combineU(int start, int end, double * u, int rank, double * whole_u, int nprocs){
157 double receive_whole_u[NX];
158 whole_u[0] = initialU[0];
159 whole_u[NX - 1] = initialU[NX-1];
160 int i = start;
161 int j = 1;
162 int k = 1;
163 for(; k<NX-1; k++){
164 whole_u[k] = 0;
165 }
166 for(; i < end+1; i++){
167 whole_u[i] = u[j];
168 j++;
169 }
170 if(rank != 0){
171 send(whole_u, NX, 0, REDUCE, rank);
172 }else{
173 for(i = 1; i<nprocs; i++){
174 recv(receive_whole_u, NX, i, REDUCE, rank);
175 for(j = 1; j<NX-1; j++){
176 whole_u[j] += receive_whole_u[j];
177 }
178 }
179 }
180}
181
182/* computing the solver in a sequential way*/
183void seqDiffusion1d(double * seq_u){
184 double u[NX], u_new[NX];
185 int i;
186 int nsteps = NSTEPS;
187
188 //Initiate
189 for(i=0; i<NX; i++){
190 u[i] = initialU[i];
191 u_new[i] = initialU[i];
192 }
193 //Jacobi Iteration
194 while(nsteps > 0){
195 //update
196 for(i=1; i<NX-1; i++){
197 u_new[i] = u[i] + K * (u[i-1] + u[i+1] - 2*u[i]);
198 }
199 for(i=1; i<NX-1; i++){
200 u[i] = u_new[i];
201 }
202 nsteps--;
203 }
204 for(i=0 ;i<NX; i++){
205 seq_u[i] = u[i];
206 }
207}
208
209void MPI_Process (int rank){
210 $when (__start);
211 double whole_u[NX]; /* The array used for gather results from every processes */
212 double seq_u[NX]; /* The array used for store sequential computing results */
213 int nprocs; /* number of processes*/
214 int start, end; /* the index of the u*/
215 int left_u, right_u; /* the index of the left u
216 and right u*/
217 int u_length; /* number of elements in this u*/
218 int temp[4]; /*temp buffer for start, end, left_u and right_u */
219 int nsteps = NSTEPS;
220
221 if(NPROCS > (NX-2)){
222 nprocs = (NX - 2);
223 if(rank >= (NX-2)){
224 return;
225 }
226 }else{
227 nprocs = NPROCS;
228 }
229 uProperties(NX,nprocs,rank,temp);
230 start = temp[0];
231 end = temp[1];
232 left_u = temp[2];
233 right_u = temp[3];
234 u_length = end - start + 1;
235 double u[u_length + 2];
236 double u_new[u_length + 2];
237 initU(u, u_new, start, end, left_u, right_u);
238 /* Jacobi Iterations*/
239 while(nsteps > 0){
240 communicate(u, left_u, right_u, start, end, rank);
241 update(u, u_new, start, end);
242 nsteps --;
243 }
244 /* Gathering the result from every processes into whole_u and compare it with the result seq_u which got
245 from sequential computing function */
246 combineU(start,end,u,rank, whole_u, nprocs);
247 if(rank == 0){
248 seqDiffusion1d(seq_u);
249 for(int i=0; i<NX; i++){
250 $assert ((seq_u[i] == whole_u[i]), "i = %d\n", i);
251 }
252 }
253}
Note: See TracBrowser for help on using the repository browser.