/* Computing the solver for heat equation in multithreads, then compare the * result with the solver got in a sequencial way. * * Command line example: * civl verify -inputNB=10 -inputK=0.3 -inputNSTEPS=5 -inputNX=10 diffusion_1d.c -showAmpleSet * This diffusion1d program computing the diffusion1d equation in parallel and then compare the result with * another result of diffution1d equation computed in sequential. **/ #include #include #define FROM_LEFT 1 /* mpi tag which means the source is send or receive from left u */ #define FROM_RIGHT 2 /* mpi tag which means the source is send or receive from right u */ #define REDUCE 3 /* reduce tag */ $input int NPROCS; $input int NPROCSB; $input double K; /* k = alpha^2 * dt/(dx^2) */ $input int NSTEPS; /* time */ $input int NSTEPSB; $input int NX; /* the length of the array */ $input int NXB; $input double initialU[NX]; $proc __procs[NPROCS]; _Bool __start = 0; $comm MPI_COMM_WORLD; $assume 0 < NPROCS && NPROCS <= NPROCSB; $assume 0 < NSTEPS && NSTEPS <= NSTEPSB; $assume 2 < NX && NX <= NXB; void MPI_Process (int rank); void send(void *buf, int count, int dest, int tag, int rank) { $message out = $message_pack(rank, dest, tag, buf, count*sizeof(double)); $comm_enqueue(&MPI_COMM_WORLD, out); } void recv(void *buf, int count, int source, int tag, int rank) { $message in = $comm_dequeue(&MPI_COMM_WORLD, source, rank, tag); $message_unpack(in, buf, count*sizeof(double)); } void init() { for (int i=0; i= nprocs) right_u = -1; results[0] = start; results[1] = end; results[2] = left_u; results[3] = right_u; return 1; } /* the numbers of elements in u and u_new are 2 more than u_length because of ghost elements */ int initU(double * u, double * u_new, int start, int end, int left_u, int right_u){ int i,j; int u_length = end - start + 1; // the number of interior elements /* initiate interior array */ j = start; for(i=1; i< u_length+1; i++){ u[i] = initialU[j]; u_new[i] = initialU[j]; j++; } /* for the most left or right Us, initiate the first ghost element and the last ghost element */ if(left_u == -1){ u[0] = initialU[0]; u_new[0] = initialU[0]; } if(right_u == -1){ i = u_length + 1; u[i] = initialU[NX-1]; u_new[i] = initialU[NX-1]; } return u_length; } /* gather separate results from all processes */ void combineU(int start, int end, double * u, int rank, double * whole_u, int nprocs){ double receive_whole_u[NX]; whole_u[0] = initialU[0]; whole_u[NX - 1] = initialU[NX-1]; int i = start; int j = 1; int k = 1; for(; k 0){ //update for(i=1; i (NX-2)){ nprocs = (NX - 2); if(rank >= (NX-2)){ return; } }else{ nprocs = NPROCS; } uProperties(NX,nprocs,rank,temp); start = temp[0]; end = temp[1]; left_u = temp[2]; right_u = temp[3]; u_length = end - start + 1; double u[u_length + 2]; double u_new[u_length + 2]; initU(u, u_new, start, end, left_u, right_u); /* Jacobi Iterations*/ while(nsteps > 0){ communicate(u, left_u, right_u, start, end, rank); update(u, u_new, start, end); nsteps --; } /* Gathering the result from every processes into whole_u and compare it with the result seq_u which got from sequential computing function */ combineU(start,end,u,rank, whole_u, nprocs); if(rank == 0){ seqDiffusion1d(seq_u); for(int i=0; i