source: CIVL/examples/messagePassing/diffusion_1d.cvl@ a054a5b

1.23 2.0 main test-branch
Last change on this file since a054a5b was 767f15e, checked in by Ziqing Luo <ziqing@…>, 12 years ago

the latest diffusion_1d program

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

  • Property mode set to 100644
File size: 8.7 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 -inpuNPROCS=3 diffusion_1d.cvl
6 * Notice: Verify this program may take much long time and much large memory space.
7 **/
8
9#include<civlc.h>
10#include "mp_root.cvh"
11#define FROM_LEFT 1 /* mpi tag which means the source is send or receive
12 from left chunk*/
13#define FROM_RIGHT 2 /* mpi tag which means the source is send or receive
14 from right chunk*/
15#define REDUCE 3 /* reduce tag */
16#define Threshold 1 /* the threshold of difference */
17#define K 0.3 /* k = alpha^2 * dt/(dx^2) */
18#define ELENUM 7 /* the length of the array */
19#define RELEASE 0 /* sync signal */
20#define HOLD 1 /* sync signal */
21#define NSTEPS 2 /* time */
22
23int reduce_count = 0; /* used for sync */
24short __release = HOLD; /* used for sync */
25double globle_u[ELENUM]; /* used for store the whole array */
26double seq_u[ELENUM]; /* used for store the whole array in the sequential way */
27
28/* return the absolute double value */
29double doubleAbs(double v){
30 if(v < 0)
31 return -v;
32 else
33 return v;
34}
35
36/* return boundary values. Here we just use a constant value */
37double boundaryValues(int x){
38 return 4.0;
39}
40
41/* update the array using heat equation,
42 returns the max difference between the previous one and updated one*/
43double update(double * u, double * u_new, int start, int end){
44 int i;
45 int chunk_length = end - start + 1;
46
47 // chunk_length = (the length of u or u_new) - 2
48 for(i=1; i<chunk_length+1; i++)
49 u_new [i] = u[i] + K * (u[i-1] + u[i+1] - 2*u[i]);
50
51 // compute the difference between u and u_new
52 double max_diff = 0;
53 double diff;
54
55 for(i=1; i<chunk_length+1; i++){
56 diff = doubleAbs(u_new[i] - u[i]);
57 if(diff > max_diff)
58 max_diff = diff;
59 // update u
60 u[i] = u_new[i];
61 }
62 return max_diff;
63}
64
65/* Communicate with left chunk and right chunk,
66 send the first interior element to left chunk and receive for
67 the last interior element */
68void communicate(double * u, int left, int right, int start,
69 int end, int rank){
70 #include "mp_proc_diffusion.cvh"
71
72 int chunk_length = end - start + 1;
73 // the most left or right chunks just need to exchange with one side
74 if(left == -1 && right == -1)
75 return;
76 else if(left == -1){
77 send(&u[chunk_length], 1, right, FROM_LEFT, rank);
78 recv(&u[chunk_length + 1], 1, right, FROM_RIGHT, rank);
79 }
80 else if(right == -1){
81 send(&u[1], 1, left, FROM_RIGHT, rank);
82 recv(&u[0], 1, left, FROM_LEFT, rank);
83 }else{
84 send(&u[chunk_length], 1, right, FROM_LEFT, rank);
85 send(&u[1], 1, left, FROM_RIGHT, rank);
86 recv(&u[chunk_length + 1], 1, right, FROM_RIGHT, rank);
87 recv(&u[0], 1, left, FROM_LEFT, rank);
88 }
89}
90
91/* compute the value of start, end, left chunk and right chunk
92 return an array with those values in such order*/
93void chunkProperties(int length, int nprocs, int rank, int* results){
94 if(length < 3 || nprocs > (length - 2))
95 return -1;
96
97 int remainder = (length - 2) % nprocs;
98 int chunk_length =(length - 2) / nprocs;
99
100 int start = rank * chunk_length + 1;
101
102 // the last chunk takes the remainder
103 if(rank == nprocs - 1){
104 chunk_length = chunk_length + remainder;
105 }
106
107 int end = start + chunk_length - 1;
108
109 int left_chunk = rank - 1;
110 int right_chunk = rank + 1;
111 if(right_chunk >= nprocs)
112 right_chunk = -1;
113
114 results[0] = start;
115 results[1] = end;
116 results[2] = left_chunk;
117 results[3] = right_chunk;
118
119 }
120
121/* the numbers of elements in u and u_new are 2 more than chunk_length because of
122 ghost elements */
123int initChunk(double * u, double * u_new, int start, int end,
124 int left_chunk, int right_chunk){
125 int i;
126 int chunk_length = end - start + 1; // the number of interior elements
127
128 /* initiate interior array */
129 for(i=1; i< chunk_length+1; i++){
130 u[i] = 0;
131 u_new[i] = 0;
132 }
133
134 /* for the most left or right chunks, initiate the first ghost ele and
135 the last ghost ele */
136 if(left_chunk == -1){
137 u[0] = boundaryValues(0);
138 u_new[0] = boundaryValues(0);
139 }
140 if(right_chunk == -1){
141 i = chunk_length + 1;
142 u[i] = boundaryValues(i);
143 u_new[i] = boundaryValues(i);
144 }
145
146 return chunk_length;
147}
148
149/* combine all separate chunks from all processes */
150void combineU(int start, int end, double * u, int rank, double * whole_u){
151#include "mp_proc_diffusion.cvh"
152 double receive_whole_u[ELENUM];
153 whole_u[0] = boundaryValues(0);
154 whole_u[ELENUM - 1] = boundaryValues(ELENUM - 1);
155 int i = start;
156 int j = 1;
157 int k = 1;
158 for(; k<ELENUM - 1; k++){
159 whole_u[k] = 0;
160 }
161 for(; i < end+1; i++){
162 whole_u[i] = u[j];
163 j++;
164 }
165 if(rank != 0){
166 reduce_send(whole_u, ELENUM, 0, REDUCE, rank);
167 }else{
168 for(i = 1; i<NPROCS; i++){
169 reduce_recv(receive_whole_u, ELENUM, i, REDUCE, rank);
170 for(j = 1; j<ELENUM-1; j++){
171 whole_u[j] += receive_whole_u[j];
172 }
173 }
174 }
175}
176
177/* synchronization */
178void procsHold(int nprocs){
179 $atomic{
180 if(reduce_count < nprocs -1){
181 reduce_count++;
182 }else{
183 reduce_count++;
184 __release = RELEASE;
185 }
186 }
187 $when (__release == RELEASE);
188}
189/* synchronization */
190void procsRelease(){
191 $atomic{
192 if(reduce_count > 1){
193 reduce_count--;
194 }else{
195 reduce_count--;
196 __release = HOLD;
197 }
198 }
199 $when (__release == HOLD);
200}
201
202/* computing the solver in a sequential way*/
203void seqDiffusion1d(double * seq_u){
204 double diff,max_diff = 0.0;
205 double u[ELENUM], u_new[ELENUM];
206 int i;
207 int nsteps = NSTEPS;
208
209 //Initiate
210 u[0] = boundaryValues(0);
211 u_new[0] = boundaryValues(0);
212 u[ELENUM-1] = boundaryValues(ELENUM - 1);
213 u_new[ELENUM-1] = boundaryValues(ELENUM - 1);
214 for(i=1; i<ELENUM-1; i++){
215 u[i] = 0;
216 u_new[i] = 0;
217 }
218 //Jacobi Iteration
219 while(nsteps > 0){
220 //update
221 for(i=1; i<ELENUM-1; i++){
222 u_new[i] = u[i] + K * (u[i-1] + u[i+1] - 2*u[i]);
223 }
224 for(i=1; i<ELENUM-1; i++){
225 diff = doubleAbs(u_new[i] - u[i]);
226 if(diff > max_diff)
227 max_diff = diff;
228 // update u
229 u[i] = u_new[i];
230 }
231 //termination
232 if(max_diff*3 <= Threshold)
233 break;
234 else
235 max_diff = 0;
236 nsteps --;
237 }
238 for(i =0 ;i<ELENUM; i++){
239 seq_u[i] = u[i];
240 }
241}
242
243void MPI_Reduce(double * buf, int rank, int count){
244#include "mp_proc_diffusion.cvh"
245 int nprocs = NPROCS;
246 int i=0;
247 double receive_buf;
248
249 if(rank != 0){
250 reduce_send(buf, count, 0, REDUCE, rank);
251 reduce_recv(buf, count, 0, REDUCE, rank);
252 }
253 else{
254 for(i=1; i<nprocs; i++){
255 reduce_recv(&receive_buf, count, i, REDUCE, rank);
256 (*buf) += receive_buf;
257 }
258 for(i=1; i<nprocs; i++){
259 reduce_send(buf, count, i, REDUCE, rank);
260 }
261 }
262}
263
264void MPI_Process (int rank){
265
266 $when (__start);
267 double diff, myTotalDiff; /* the max difference between previous
268 function and updated function*/
269 double whole_u[ELENUM];
270 int nprocs; /* number of processes*/
271 int start, end; /* the index of the chunk*/
272 int left_chunk, right_chunk; /* the index of the left chunk
273 and right chunk*/
274 int chunk_length; /* number of elements in this chunk*/
275 int temp[4]; /*temp buffer for start, end, left_chunk and right_chunk */
276 int nsteps = NSTEPS;
277 nprocs = NPROCS;
278
279 chunkProperties(ELENUM, nprocs, rank, temp);
280 start = temp[0];
281 end = temp[1];
282 left_chunk = temp[2];
283 right_chunk = temp[3];
284 chunk_length = end - start + 1;
285 double u[chunk_length + 2];
286 double u_new[chunk_length + 2];
287
288 initChunk(u, u_new, start, end, left_chunk, right_chunk);
289 /* Jacobi Iterations*/
290 while(nsteps > 0){
291 communicate(u, left_chunk, right_chunk, start, end, rank);
292 diff = update(u, u_new, start, end);
293 MPI_Reduce(&diff,rank,1);
294 //accumulate diff
295// procsHold(nprocs);
296// total_diff += diff;
297// procsRelease();
298// procsHold(nprocs);
299// myTotalDiff = total_diff;
300// procsRelease();
301 if(diff <= Threshold){
302 break;
303 }
304 else{
305 diff = 0;
306 nsteps --;
307 }
308 }
309// procsHold(nprocs);
310 combineU(start,end,u,rank, whole_u);
311// procsRelease();
312 /* the process with rank 0 takes charge of comparing
313 the results of sequential way and MPI way */
314 if(rank == 0){
315 int i;
316
317 seqDiffusion1d(seq_u);
318 for(i=0; i<ELENUM; i++){
319 double test_dif = doubleAbs((seq_u[i] - whole_u[i]));
320 }
321 }
322}
Note: See TracBrowser for help on using the repository browser.