/* 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 -inputNPROCSB=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 /* mpi tag which stands for reducing */ $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]; $gcomm __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, $comm comm) { $message out = $message_pack(comm->place, dest, tag, buf, count*sizeof(double)); $comm_enqueue(comm, out); } void recv(void *buf, int count, int source, int tag, $comm comm) { $message in = $comm_dequeue(comm, source, tag); $message_unpack(in, buf, count*sizeof(double)); } void init() { __MPI_COMM_WORLD = $gcomm_create($root, NPROCS); 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 $atomic{ /* 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, $comm comm, 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; int rank = $comm_place(comm); 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; u = (double*)$malloc($root, sizeof(double)*(u_length + 2)); u_new = (double*)$malloc($root, sizeof(double)*(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, MPI_COMM_WORLD); 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, MPI_COMM_WORLD, whole_u, nprocs); if(rank == 0){ seqDiffusion1d(seq_u); for(int i=0; i