示例#1
0
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);
}