int Zoltan_RIB_inertial2d( int Tflops_Special, /* Use Tflops_Special communication; should be 0 if called from serial_rib */ struct Dot_Struct *dotpt, /* graph data structure for weights */ int *dindx, /* index array into dotpt; if NULL, access dotpt directly */ int dotnum, /* number of vtxs in graph */ int wgtflag, /* are vertex weights being used? */ double cm[3], /* center of mass in each direction */ double evec[3], /* eigenvector */ double *value, /* array for value to sort on */ MPI_Comm comm, /* communicator for partition */ int proc, /* global proc number (Tflops_Special) */ int nproc, /* Number of procs in partition (Tflops_Special) */ int proclower /* Lowest numbered proc in partition (Tflops_Special)*/ ) { double tensor[2][2]; /* inertial tensor */ double xcm, ycm; /* center of mass in each direction */ double tmp1[3], tmp2[3]; /* temporary variables for MPI_Allreduces */ double xx, yy, xy; /* elements of inertial tensor */ double xdif, ydif; /* deviation from center of mass */ double eval, res; /* eigenvalue and error in eval calculation */ double wgt_sum; /* sum of all the vertex weights */ int i, j; /* loop counter */ double xcmt, ycmt, wgtt; /* temp for center of mass */ double xxt, yyt, xyt; /* temp for tensor */ int rank = 0; /* rank in partition (Tflops_Special) */ /* Compute center of mass and total mass. */ xcm = ycm = 0.0; if (wgtflag) { wgt_sum = 0.0; for (j = 0; j < dotnum; j++) { i = (dindx ? dindx[j] : j); wgt_sum += dotpt[i].Weight[0]; xcm += dotpt[i].Weight[0]*dotpt[i].X[0]; ycm += dotpt[i].Weight[0]*dotpt[i].X[1]; } } else { wgt_sum = dotnum; for (j = 0; j < dotnum; j++) { i = (dindx ? dindx[j] : j); xcm += dotpt[i].X[0]; ycm += dotpt[i].X[1]; } } /* Sum weights across processors */ if (Tflops_Special) { rank = proc - proclower; tmp1[0] = xcm; tmp1[1] = ycm; tmp1[2] = wgt_sum; Zoltan_RIB_reduce_double(tmp1, tmp2, 3, comm, nproc, rank, proc, 1); xcmt = tmp2[0]; ycmt = tmp2[1]; wgtt = tmp2[2]; } else { tmp1[0] = xcm; tmp1[1] = ycm; tmp1[2] = wgt_sum; MPI_Allreduce(tmp1, tmp2, 3, MPI_DOUBLE, MPI_SUM, comm); xcmt = tmp2[0]; ycmt = tmp2[1]; wgtt = tmp2[2]; } xcm = xcmt/wgtt; ycm = ycmt/wgtt; /* Generate 3 elements of Inertial tensor. */ xx = yy = xy = 0.0; if (wgtflag) for (j = 0; j < dotnum; j++) { i = (dindx ? dindx[j] : j); xdif = dotpt[i].X[0] - xcm; ydif = dotpt[i].X[1] - ycm; xx += dotpt[i].Weight[0]*xdif*xdif; yy += dotpt[i].Weight[0]*ydif*ydif; xy += dotpt[i].Weight[0]*xdif*ydif; } else for (j = 0; j < dotnum; j++) { i = (dindx ? dindx[j] : j); xdif = dotpt[i].X[0] - xcm; ydif = dotpt[i].X[1] - ycm; xx += xdif*xdif; yy += ydif*ydif; xy += xdif*ydif; } /* Sum tensor across processors */ if (Tflops_Special) { tmp1[0] = xx; tmp1[1] = yy; tmp1[2] = xy; Zoltan_RIB_reduce_double(tmp1, tmp2, 3, comm, nproc, rank, proc, 1); xxt = tmp2[0]; yyt = tmp2[1]; xyt = tmp2[2]; } else { tmp1[0] = xx; tmp1[1] = yy; tmp1[2] = xy; MPI_Allreduce(tmp1, tmp2, 3, MPI_DOUBLE, MPI_SUM, comm); xxt = tmp2[0]; yyt = tmp2[1]; xyt = tmp2[2]; } /* Compute eigenvector with maximum eigenvalue. */ tensor[0][0] = xxt; tensor[1][1] = yyt; tensor[1][0] = tensor[0][1] = xyt; evals2(tensor, &res, &eval); eigenvec2(tensor, eval, evec, &res); /* Calculate value to sort/split on for each cell. */ /* This is inner product with eigenvector. */ for (j = 0; j < dotnum; j++) { i = (dindx ? dindx[j] : j); value[j] = (dotpt[i].X[0] - xcm)*evec[0] + (dotpt[i].X[1] - ycm)*evec[1]; } cm[0] = xcm; cm[1] = ycm; /* zero unused third dimension */ cm[2] = evec[2] = 0.0; return(ZOLTAN_OK); }
void inertial2d ( struct vtx_data **graph, /* graph data structure for weights */ int nvtxs, /* number of vtxs in graph */ int cube_or_mesh, /* 0 => hypercube, d => d-dimensional mesh */ int nsets, /* number of sets to divide into */ float *x, float *y, /* x and y coordinates of vertices */ int *sets, /* set each vertex gets assigned to */ double *goal, /* desired set sizes */ int using_vwgts /* are vertex weights being used? */ ) { extern int DEBUG_INERTIAL; /* debug flag for inertial method */ extern double inertial_axis_time; /* time spent finding inertial axis */ extern double median_time; /* time spent computing medians */ double tensor[2][2]; /* inertial tensor */ double evec[2]; /* eigenvector of tensor */ double *value; /* values along selected direction to sort */ double xcm, ycm; /* center of mass in each direction */ double xx, yy, xy; /* elements of inertial tensor */ double xdif, ydif; /* deviation from center of mass */ double eval, res; /* eigenvalue and error in eval calculation */ double vwgt_sum; /* sum of all the vertex weights */ double time; /* timing parameters */ int *space; /* space required by median routine */ int i; /* loop counter */ double seconds(); void evals2(), eigenvec2(), rec_median_1(); /* Compute center of mass and total mass. */ time = seconds(); xcm = ycm = 0.0; if (using_vwgts) { vwgt_sum = 0.0; for (i = 1; i <= nvtxs; i++) { vwgt_sum += graph[i]->vwgt; xcm += graph[i]->vwgt * x[i]; ycm += graph[i]->vwgt * y[i]; } } else { vwgt_sum = nvtxs; for (i = 1; i <= nvtxs; i++) { xcm += x[i]; ycm += y[i]; } } xcm /= vwgt_sum; ycm /= vwgt_sum; /* Generate 3 elements of Inertial tensor. */ xx = yy = xy = 0.0; if (using_vwgts) { for (i = 1; i <= nvtxs; i++) { xdif = x[i] - xcm; ydif = y[i] - ycm; xx += graph[i]->vwgt * xdif * xdif; yy += graph[i]->vwgt * ydif * ydif; xy += graph[i]->vwgt * xdif * ydif; } } else { for (i = 1; i <= nvtxs; i++) { xdif = x[i] - xcm; ydif = y[i] - ycm; xx += xdif * xdif; yy += ydif * ydif; xy += xdif * ydif; } } /* Compute eigenvector with maximum eigenvalue. */ tensor[0][0] = xx; tensor[1][1] = yy; tensor[1][0] = tensor[0][1] = xy; evals2(tensor, &res, &eval); eigenvec2(tensor, eval, evec, &res); inertial_axis_time += seconds() - time; if (DEBUG_INERTIAL > 0) { printf("Principle Axis = (%g, %g), Eval=%g, Residual=%e\n", evec[0], evec[1], eval, res); } /* Allocate space for value array. */ value = smalloc((nvtxs + 1) * sizeof(double)); /* Calculate value to sort/split on for each cell. */ /* This is inner product with eigenvector. */ for (i = 1; i <= nvtxs; i++) { value[i] = (x[i] - xcm) * evec[0] + (y[i] - ycm) * evec[1]; } /* Now find the median value and partition based upon it. */ space = smalloc(nvtxs * sizeof(int)); time = seconds(); rec_median_1(graph, value, nvtxs, space, cube_or_mesh, nsets, goal, using_vwgts, sets, TRUE); median_time += seconds() - time; sfree(space); sfree(value); }