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

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

diffusion example (not the final version, just commit for run on Nikolai)

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

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