pairs* closest(point* P[],int size) { if(size <= 3) return bforce(P, size); int lvertical = (int) size/2; pairs* CL = closest(P,Y,lvertical); pairs* CR = closest(P+lvertical,Y+lvertical,size -lvertical); if(CL->dist < CR->dist) return CL; else return CR; }
// Main function int main(int argc, char **argv) { int i, ts, thisbody, otherbody; int bn; double vavgx, vavgy, vavgz, ax, ay, az, deltaf[3]; // Serial Timing Functions: See the timer.h include file in this directory double etime, etime0, etime1, cptime; int send_counts[8], recv_counts[8], send_offsets[8], recv_offsets[8]; int rank, size, type=99; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &size); // Get no. of processes MPI_Comm_rank(MPI_COMM_WORLD, &rank); // Which process am I? if(rank == 0){ // Read basic inputs scanf("%d\n",&N); scanf("%d\n",&K); scanf("%le\n",&dt); } // broadcast N, K, dt to all processes MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD); MPI_Bcast(&K, 1, MPI_INT, 0, MPI_COMM_WORLD); MPI_Bcast(&dt, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); dt2 = dt/2.; // Allocate arrays // times 8 to make sure it won't excced the boundary use. // since one body may be boundary body for 7 processes mass = calloc(N * 8, sizeof(double)); // mass[i] is mass of body i x = calloc(N * 8, sizeof(double)); // x[i] is x position of body i y = calloc(N * 8, sizeof(double)); // y[i] is y position of body i z = calloc(N * 8, sizeof(double)); // z[i] is z position of body i vx = calloc(N * 8, sizeof(double)); // vx[i] is x velocity of body i vy = calloc(N * 8, sizeof(double)); // vy[i] is y velocity of body i vz = calloc(N * 8, sizeof(double)); // vz[i] is z velocity of body i fx = calloc(N * 8, sizeof(double)); // fx[i] is x force on body i fy = calloc(N * 8, sizeof(double)); // fy[i] is y force on body i fz = calloc(N * 8, sizeof(double)); // fz[i] is z force on body i bmass = calloc(N * 8, sizeof(double)); // boundary body mass bx = calloc(N * 8, sizeof(double)); // boundary body x by = calloc(N * 8, sizeof(double)); // boundary body y bz = calloc(N * 8, sizeof(double)); // boundary body z buf = calloc(N * 8, sizeof(double)); // boundary body z if(rank == 0){ // Read initial conditions for (i=0; i<N; i++) scanf("%le\n",&mass[i]); for (i=0; i<N; i++) scanf("%le %le %le\n",&x[i],&y[i],&z[i]); for (i=0; i<N; i++) scanf("%le %le %le\n",&vx[i],&vy[i],&vz[i]); n = N; }else{ n = 0; } MPI_Barrier(MPI_COMM_WORLD); // Start Timer timing(&etime0,&cptime); // Timestamp Loop // loop phase for (ts=0; ts<K; ts++) { if (ts%128 == 0) intermediate_output(ts, rank); // Print output if necessary // partition bodies into 8 groups based on its coordination partition(n, send_offsets); for(i = 0; i < size - 1; i++){ send_counts[i] = send_offsets[i + 1] - send_offsets[i]; } send_counts[size - 1] = n - send_offsets[size - 1]; // alltoall number of bodies MPI_Alltoall(send_counts, 1, MPI_INT, recv_counts, 1, MPI_INT, MPI_COMM_WORLD); recv_offsets[0] = 0; for(i = 1; i < size; i++){ recv_offsets[i] = recv_offsets[i - 1] + recv_counts[i - 1]; } // n is not correct // update n n = recv_offsets[size - 1] + recv_counts[size - 1]; // alltoallv bodies MPI_Alltoallv(mass, send_counts, send_offsets, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, MPI_COMM_WORLD); swap(&mass, &buf); MPI_Alltoallv(x, send_counts, send_offsets, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, MPI_COMM_WORLD); swap(&x, &buf); MPI_Alltoallv(y, send_counts, send_offsets, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, MPI_COMM_WORLD); swap(&y, &buf); MPI_Alltoallv(z, send_counts, send_offsets, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, MPI_COMM_WORLD); swap(&z, &buf); MPI_Alltoallv(vx, send_counts, send_offsets, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, MPI_COMM_WORLD); swap(&vx, &buf); MPI_Alltoallv(vy, send_counts, send_offsets, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, MPI_COMM_WORLD); swap(&vy, &buf); MPI_Alltoallv(vz, send_counts, send_offsets, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, MPI_COMM_WORLD); swap(&vz, &buf); // extract boundary points extract(n, send_offsets, &bn); // alltoall number of boundary points for(i = 0; i < size - 1; i++){ send_counts[i] = send_offsets[i + 1] - send_offsets[i]; } send_counts[size - 1] = bn - send_offsets[size - 1]; // alltoall number of bodies MPI_Alltoall(send_counts, 1, MPI_INT, recv_counts, 1, MPI_INT, MPI_COMM_WORLD); recv_offsets[0] = 0; for(i = 1; i < size; i++){ recv_offsets[i] = recv_offsets[i - 1] + recv_counts[i - 1]; } bn = recv_offsets[size - 1] + recv_counts[size - 1]; // alltoallv boundary points mass MPI_Alltoallv(bmass, send_counts, send_offsets, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, MPI_COMM_WORLD); swap(&bmass, &buf); // alltoallv boundary points x MPI_Alltoallv(bx, send_counts, send_offsets, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, MPI_COMM_WORLD); swap(&bx, &buf); // alltoallv boundary points y MPI_Alltoallv(by, send_counts, send_offsets, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, MPI_COMM_WORLD); swap(&by, &buf); // alltoallv boundary points z MPI_Alltoallv(bz, send_counts, send_offsets, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, MPI_COMM_WORLD); swap(&bz, &buf); // Initialize forces on bodies for (thisbody=0; thisbody<n; thisbody++) { fx[thisbody] = 0.; fy[thisbody] = 0.; fz[thisbody] = 0.; } // Compute all pairwise interbody forces (Note that we take advantage of symmetry.) for (thisbody=0; thisbody<n; thisbody++) { for (otherbody=thisbody+1; otherbody<n; otherbody++) { force(thisbody, otherbody, deltaf); // This function computes the pairwise force of otherbody on thisbody fx[thisbody] += deltaf[0]; // Add x component of force to thisbody fy[thisbody] += deltaf[1]; // Add y component of force to thisbody fz[thisbody] += deltaf[2]; // Add z component of force to thisbody fx[otherbody] -= deltaf[0]; // Subtract x component of force from otherbody fy[otherbody] -= deltaf[1]; // Subtract y component of force from otherbody fz[otherbody] -= deltaf[2]; // Subtract z component of force from otherbody } } // Compute all pairwise boundary body forces (Note that we take advantage of symmetry.) for (thisbody=0; thisbody<n; thisbody++) { for (otherbody=0; otherbody<bn; otherbody++) { bforce(thisbody, otherbody, deltaf); // This function computes the pairwise force of otherbody on thisbody fx[thisbody] += deltaf[0]; // Add x component of force to thisbody fy[thisbody] += deltaf[1]; // Add y component of force to thisbody fz[thisbody] += deltaf[2]; // Add z component of force to thisbody } } // Now move the bodies (assumes constant acceleration during the timestep) for (thisbody=0; thisbody<n; thisbody++) { ax = fx[thisbody]/mass[thisbody]; // Compute x-direction acceleration of thisbody ay = fy[thisbody]/mass[thisbody]; // Compute y-direction acceleration of thisbody az = fz[thisbody]/mass[thisbody]; // Compute z-direction acceleration of thisbody vavgx = vx[thisbody] + dt2*ax; // Compute average x velocity of thisbody vavgy = vy[thisbody] + dt2*ay; // Compute average y velocity of thisbody vavgz = vz[thisbody] + dt2*az; // Compute average z velocity of thisbody x[thisbody] = x[thisbody] + dt*vavgx; // Compute new x position of thisbody y[thisbody] = y[thisbody] + dt*vavgy; // Compute new y position of thisbody z[thisbody] = z[thisbody] + dt*vavgz; // Compute new z position of thisbody vx[thisbody] += dt*ax; // Compute x velocity of thisbody at end of timestep vy[thisbody] += dt*ay; // Compute y velocity of thisbody at end of timestep vz[thisbody] += dt*az; // Compute z velocity of thisbody at end of timestep } } // gather results // gather numbers MPI_Gather(&n, 1, MPI_INT, recv_counts, 1, MPI_INT, 0, MPI_COMM_WORLD); recv_offsets[0] = 0; for(i = 1; i < size; i++){ recv_offsets[i] = recv_offsets[i - 1] + recv_counts[i - 1]; } // gatherv x MPI_Gatherv(x, n, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, 0, MPI_COMM_WORLD); swap(&x, &buf); // gatherv y MPI_Gatherv(y, n, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, 0, MPI_COMM_WORLD); swap(&y, &buf); // gatherv z MPI_Gatherv(z, n, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, 0, MPI_COMM_WORLD); swap(&z, &buf); // gatherv mass MPI_Gatherv(mass, n, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, 0, MPI_COMM_WORLD); swap(&mass, &buf); // gatherv vx MPI_Gatherv(vx, n, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, 0, MPI_COMM_WORLD); swap(&vx, &buf); // gatherv vy MPI_Gatherv(vy, n, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, 0, MPI_COMM_WORLD); swap(&vy, &buf); // gatherv vz MPI_Gatherv(vz, n, MPI_DOUBLE, buf, recv_counts, recv_offsets, MPI_DOUBLE, 0, MPI_COMM_WORLD); swap(&vz, &buf); if(rank == 0){ n = N; output(K); // Final output timing(&etime1, &cptime); etime = etime1 - etime0; printf ("\nTime for %d timesteps with %d bodies: %9.4f seconds\n", K, N, etime); } // Free arrays free(mass); free(x); free(y); free(z); free(vx); free(vy); free(vz); free(fx); free(fy); free(fz); free(bx); free(by); free(bz); free(bmass); free(buf); MPI_Finalize(); }