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

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

add $COMM_ANY_TAG supoort
new diffusion1d.cvl
printf("%p") supported

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

  • Property mode set to 100644
File size: 7.2 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 -inputNPROCSB=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 /* mpi tag which stands for reducing */
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$gcomm __MPI_COMM_WORLD;
27$assume 0 < NPROCS && NPROCS <= NPROCSB;
28$assume 0 < NSTEPS && NSTEPS <= NSTEPSB;
29$assume 2 < NX && NX <= NXB;
30
31void MPI_Process (int rank);
32
33void send(void *buf, int count, int dest, int tag, $comm comm) {
34 $message out = $message_pack(comm->place, dest, tag, buf, count*sizeof(double));
35 $comm_enqueue(comm, out);
36}
37
38void recv(void *buf, int count, int source, int tag, $comm comm) {
39 $message in = $comm_dequeue(comm, source, tag);
40 $message_unpack(in, buf, count*sizeof(double));
41}
42
43void init() {
44 __MPI_COMM_WORLD = $gcomm_create($root, NPROCS);
45 for (int i=0; i<NPROCS; i++)
46 __procs[i] = $spawn MPI_Process(i);
47}
48
49void finalize() {
50 for (int i=0; i<NPROCS; i++)
51 $wait(__procs[i]);
52}
53
54void main() {
55 init();
56 finalize();
57}
58
59/* update the array */
60void update(double * u, double * u_new, int start, int end){
61 int i;
62 int u_length = end - start + 1;
63 $atomic{
64 for(i=1; i<u_length+1; i++){
65 u_new[i] = u[i] + K * (u[i-1] + u[i+1] - 2*u[i]);
66 }
67 for(i=1; i<u_length+1; i++){
68 u[i] = u_new[i];
69 }
70 }
71}
72
73/* Communicate with left u and right u,
74 send the first interior element to left u and receive for
75 the last interior element */
76void communicate(double * u, int left, int right, int start,
77 int end, $comm comm){
78 int u_length = end - start + 1;
79 // the most left or right us just need to exchange with one side
80 if(left == -1 && right == -1)
81 return;
82 else if(left == -1){
83 send(&u[u_length], 1, right, FROM_LEFT, comm);
84 recv(&u[u_length + 1], 1, right, FROM_RIGHT, comm);
85 }
86 else if(right == -1){
87 send(&u[1], 1, left, FROM_RIGHT, comm);
88 recv(&u[0], 1, left, FROM_LEFT, comm);
89 }else{
90 send(&u[u_length], 1, right, FROM_LEFT, comm);
91 send(&u[1], 1, left, FROM_RIGHT, comm);
92 recv(&u[u_length + 1], 1, right, FROM_RIGHT, comm);
93 recv(&u[0], 1, left, FROM_LEFT, comm);
94 }
95}
96
97/* compute the value of start, end, left u and right u
98 return an array with those values in such order*/
99int uProperties(int length, int nprocs, int rank, int* results){
100 if(length < 3 )
101 return -1;
102 int remainder = (length - 2) % nprocs;
103 int u_length =(length - 2) / nprocs;
104 int start = rank * u_length + 1;
105 $atomic{
106 //the last u takes the remainder
107 if(rank == nprocs - 1){
108 u_length = u_length + remainder;
109 }
110
111 int end = start + u_length - 1;
112 int left_u = rank - 1;
113 int right_u = rank + 1;
114
115 if(right_u >= nprocs)
116 right_u = -1;
117 results[0] = start;
118 results[1] = end;
119 results[2] = left_u;
120 results[3] = right_u;
121 }
122 return 1;
123 }
124
125/* the numbers of elements in u and u_new are 2 more than u_length because of
126 ghost elements */
127int initU(double * u, double * u_new, int start, int end,
128 int left_u, int right_u){
129 int i,j;
130 int u_length = end - start + 1; // the number of interior elements
131
132 $atomic{
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 }
153 return u_length;
154}
155
156/* gather separate results from all processes */
157void combineU(int start, int end, double * u, $comm comm, double * whole_u, int nprocs){
158 double receive_whole_u[NX];
159 whole_u[0] = initialU[0];
160 whole_u[NX - 1] = initialU[NX-1];
161 int i = start;
162 int j = 1;
163 int k = 1;
164 int rank = $comm_place(comm);
165 for(; k<NX-1; k++){
166 whole_u[k] = 0;
167 }
168 for(; i < end+1; i++){
169 whole_u[i] = u[j];
170 j++;
171 }
172 if(rank != 0){
173 send(whole_u, NX, 0, REDUCE, comm);
174 }else{
175 for(i = 1; i<nprocs; i++){
176 recv(receive_whole_u, NX, i, REDUCE, comm);
177 for(j = 1; j<NX-1; j++){
178 whole_u[j] += receive_whole_u[j];
179 }
180 }
181 }
182}
183
184/* computing the solver in a sequential way*/
185void seqDiffusion1d(double * seq_u){
186 double u[NX], u_new[NX];
187 int i;
188 int nsteps = NSTEPS;
189
190 //Initiate
191 for(i=0; i<NX; i++){
192 u[i] = initialU[i];
193 u_new[i] = initialU[i];
194 }
195 //Jacobi Iteration
196 while(nsteps > 0){
197 //update
198 for(i=1; i<NX-1; i++){
199 u_new[i] = u[i] + K * (u[i-1] + u[i+1] - 2*u[i]);
200 }
201 for(i=1; i<NX-1; i++){
202 u[i] = u_new[i];
203 }
204 nsteps--;
205 }
206 for(i=0 ;i<NX; i++){
207 seq_u[i] = u[i];
208 }
209}
210
211void MPI_Process (int rank){
212 double whole_u[NX]; /* The array used for gather results from every processes */
213 double seq_u[NX]; /* The array used for store sequential computing results */
214 int nprocs; /* number of processes*/
215 int start, end; /* the index of the u*/
216 int left_u, right_u; /* the index of the left u
217 and right u*/
218 int u_length; /* number of elements in this u*/
219 int temp[4]; /*temp buffer for start, end, left_u and right_u */
220 int nsteps = NSTEPS;
221 double * u;
222 double * u_new;
223 $comm MPI_COMM_WORLD = $comm_create($here, __MPI_COMM_WORLD, rank);
224
225 if(NPROCS > (NX-2)){
226 nprocs = (NX - 2);
227 if(rank >= (NX-2)){
228 return;
229 }
230 }else{
231 nprocs = NPROCS;
232 }
233
234 uProperties(NX,nprocs,rank,temp);
235 start = temp[0];
236 end = temp[1];
237 left_u = temp[2];
238 right_u = temp[3];
239 u_length = end - start + 1;
240 u = (double*)$malloc($root, sizeof(double)*(u_length + 2));
241 u_new = (double*)$malloc($root, sizeof(double)*(u_length + 2));
242 initU(u, u_new, start, end, left_u, right_u);
243 /* Jacobi Iterations*/
244 while(nsteps > 0){
245 communicate(u, left_u, right_u, start, end, MPI_COMM_WORLD);
246 update(u, u_new, start, end);
247 nsteps--;
248 }
249 /* Gathering the result from every processes into whole_u and compare it with the result seq_u which got
250 from sequential computing function */
251 combineU(start, end, u, MPI_COMM_WORLD, whole_u, nprocs);
252 if(rank == 0){
253 seqDiffusion1d(seq_u);
254 for(int i=0; i<NX; i++){
255 $assert ((seq_u[i] == whole_u[i]), "i = %d\n", i);
256 }
257 }
258}
Note: See TracBrowser for help on using the repository browser.