source: CIVL/examples/messagePassing/diffusion_1d_comm.cvl@ ea8f7d1

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

added diffusion_1d without send/receive wrappers.

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

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