source: CIVL/examples/messagePassing/diffusion_1d.cvl@ 6d88875

1.23 2.0 main test-branch
Last change on this file since 6d88875 was 13ac9574, checked in by Ziqing Luo <ziqing@…>, 12 years ago

add some comments

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

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