int Zoltan_RCB_Build_Structure(ZZ *zz, int *num_obj, int *max_obj, int wgtflag, double overalloc, int use_ids) { /* * Function to build the geometry-based data structures for * Steve Plimpton's RCB implementation. */ char *yo = "Zoltan_RCB_Build_Structure"; RCB_STRUCT *rcb; /* Data structure for RCB. */ struct rcb_tree *treeptr; int i, ierr = 0; /* * Allocate an RCB data structure for this Zoltan structure. * If the previous data structure is still there, free the Dots and IDs first; * the other fields can be reused. */ if (zz->LB.Data_Structure == NULL) { rcb = (RCB_STRUCT *) ZOLTAN_MALLOC(sizeof(RCB_STRUCT)); if (rcb == NULL) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Insufficient memory."); return(ZOLTAN_MEMERR); } zz->LB.Data_Structure = (void *) rcb; rcb->Tree_Ptr = NULL; rcb->Box = NULL; rcb->Global_IDs = NULL; rcb->Local_IDs = NULL; rcb->Dots = NULL; Zoltan_Initialize_Transformation(&(rcb->Tran)); rcb->Tree_Ptr = (struct rcb_tree *) ZOLTAN_MALLOC(zz->LB.Num_Global_Parts * sizeof(struct rcb_tree)); rcb->Box = (struct rcb_box *) ZOLTAN_MALLOC(sizeof(struct rcb_box)); if (rcb->Tree_Ptr == NULL || rcb->Box == NULL) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Insufficient memory."); Zoltan_RCB_Free_Structure(zz); return(ZOLTAN_MEMERR); } /* initialize Tree_Ptr */ for (i = 0; i < zz->LB.Num_Global_Parts; i++) { treeptr = &(rcb->Tree_Ptr[i]); /* initialize dim to -1 to prevent use of cut */ treeptr->dim = -1; treeptr->cut = 0.0; treeptr->parent = treeptr->left_leaf = treeptr->right_leaf = 0; } } else { rcb = (RCB_STRUCT *) zz->LB.Data_Structure; ZOLTAN_FREE(&(rcb->Global_IDs)); ZOLTAN_FREE(&(rcb->Local_IDs)); ZOLTAN_FREE(&(rcb->Dots)); } ierr = Zoltan_RB_Build_Structure(zz, &(rcb->Global_IDs), &(rcb->Local_IDs), &(rcb->Dots), num_obj, max_obj, &(rcb->Num_Dim), wgtflag, overalloc, use_ids); if (ierr) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error returned from Zoltan_RB_Build_Structure."); Zoltan_RCB_Free_Structure(zz); return(ierr); } return(ZOLTAN_OK); }
int Zoltan_Get_Coordinates( ZZ *zz, int num_obj, /* Input: number of objects */ ZOLTAN_ID_PTR global_ids, /* Input: global IDs of objects */ ZOLTAN_ID_PTR local_ids, /* Input: local IDs of objects; may be NULL. */ int *num_dim, /* Output: dimension of coordinates */ double **coords /* Output: array of coordinates; malloc'ed by fn if NULL upon input. */ ) { char *yo = "Zoltan_Get_Coordinates"; int i,j,rc; int num_gid_entries = zz->Num_GID; int num_lid_entries = zz->Num_LID; int alloced_coords = 0; ZOLTAN_ID_PTR lid; /* Temporary pointers to local IDs; used to pass NULL to query functions when NUM_LID_ENTRIES == 0. */ double dist[3]; double im[3][3]; double deg_ratio; double x; int order[3]; int reduce_dimensions, d, axis_aligned; int target_dim; int ierr = ZOLTAN_OK; char msg[256]; ZZ_Transform *tran; ZOLTAN_TRACE_ENTER(zz, yo); /* Error check -- make sure needed callback functions are registered. */ if (zz->Get_Num_Geom == NULL || (zz->Get_Geom == NULL && zz->Get_Geom_Multi == NULL)) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Must register ZOLTAN_NUM_GEOM_FN and " "either ZOLTAN_GEOM_MULTI_FN or ZOLTAN_GEOM_FN"); goto End; } /* Get problem dimension. */ *num_dim = zz->Get_Num_Geom(zz->Get_Num_Geom_Data, &ierr); if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error returned from ZOLTAN_GET_NUM_GEOM_FN"); goto End; } if (*num_dim < 0 || *num_dim > 3) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Invalid dimension returned from ZOLTAN_NUM_GEOM_FN"); goto End; } /* Get coordinates for object; allocate memory if not already provided. */ if (*num_dim > 0 && num_obj > 0) { if (*coords == NULL) { alloced_coords = 1; *coords = (double *) ZOLTAN_MALLOC(num_obj * (*num_dim) * sizeof(double)); if (*coords == NULL) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Memory error"); goto End; } } if (zz->Get_Geom_Multi != NULL) { zz->Get_Geom_Multi(zz->Get_Geom_Multi_Data, zz->Num_GID, zz->Num_LID, num_obj, global_ids, local_ids, *num_dim, *coords, &ierr); if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error returned from ZOLTAN_GET_GEOM_MULTI_FN"); goto End; } } else { for (i = 0; i < num_obj; i++) { lid = (num_lid_entries ? &(local_ids[i*num_lid_entries]) : NULL); zz->Get_Geom(zz->Get_Geom_Data, num_gid_entries, num_lid_entries, global_ids + i*num_gid_entries, lid, (*coords) + i*(*num_dim), &ierr); if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error returned from ZOLTAN_GET_GEOM_FN"); goto End; } } } } /* * For RCB, RIB, and HSFC: if REDUCE_DIMENSIONS was selected, compute the * center of mass and inertial matrix of the coordinates. * * For 3D problems: If the geometry is "flat", transform the points so the * two primary directions lie along the X and Y coordinate axes and project * to the Z=0 plane. If in addition the geometry is "skinny", project to * the X axis. (This creates a 2D or 1D problem respectively.) * * For 2D problems: If the geometry is essentially a line, transform it's * primary direction to the X axis and project to the X axis, yielding a * 1D problem. * * Return these points to the partitioning algorithm, in effect partitioning * in only the 2 (or 1) significant dimensions. */ if (((*num_dim == 3) || (*num_dim == 2)) && ((zz->LB.Method==RCB) || (zz->LB.Method==RIB) || (zz->LB.Method==HSFC))){ Zoltan_Bind_Param(Reduce_Dim_Params, "KEEP_CUTS", (void *)&i); Zoltan_Bind_Param(Reduce_Dim_Params, "REDUCE_DIMENSIONS", (void *)&reduce_dimensions); Zoltan_Bind_Param(Reduce_Dim_Params, "DEGENERATE_RATIO", (void *)°_ratio); i = 0; reduce_dimensions = 0; deg_ratio = 10.0; Zoltan_Assign_Param_Vals(zz->Params, Reduce_Dim_Params, zz->Debug_Level, zz->Proc, zz->Debug_Proc); if (reduce_dimensions == 0){ goto End; } if (deg_ratio <= 1){ if (zz->Proc == 0){ ZOLTAN_PRINT_WARN(0, yo, "DEGENERATE_RATIO <= 1, setting it to 10.0"); } deg_ratio = 10.0; } if (zz->LB.Method == RCB){ tran = &(((RCB_STRUCT *)(zz->LB.Data_Structure))->Tran); } else if (zz->LB.Method == RIB){ tran = &(((RIB_STRUCT *)(zz->LB.Data_Structure))->Tran); } else{ tran = &(((HSFC_Data*)(zz->LB.Data_Structure))->tran); } d = *num_dim; if (tran->Target_Dim >= 0){ /* * On a previous load balancing call, we determined whether * or not the geometry was degenerate. If the geometry was * determined to be not degenerate, then we assume it is still * not degenerate, and we skip the degeneracy calculation. */ if (tran->Target_Dim > 0){ /* * The geometry *was* degenerate. We test the extent * of the geometry along the principal directions determined * last time to determine if it is still degenerate with that * orientation. If so, we transform the coordinates using the * same transformation we used last time. If not, we do the * entire degeneracy calculation again. */ if ((tran->Axis_Order[0] >= 0) && (tran->Axis_Order[1] >= 0) && (tran->Axis_Order[2] >= 0)){ axis_aligned = 1; } else{ axis_aligned = 0; } projected_distances(zz, *coords, num_obj, tran->CM, tran->Evecs, dist, d, axis_aligned, tran->Axis_Order); target_dim = get_target_dimension(dist, order, deg_ratio, d); if (target_dim > 0){ transform_coordinates(*coords, num_obj, d, tran); } else{ /* Set's Target_Dim to -1, flag to recompute degeneracy */ Zoltan_Initialize_Transformation(tran); } } } if (tran->Target_Dim < 0){ tran->Target_Dim = 0; /* * Get the center of mass and inertial matrix of coordinates. Ignore * vertex weights, we are only interested in geometry. Global operation. */ if (d == 2){ inertial_matrix2D(zz, *coords, num_obj, tran->CM, im); } else{ inertial_matrix3D(zz, *coords, num_obj, tran->CM, im); } /* * The inertial matrix is a 3x3 or 2x2 real symmetric matrix. Get its * three or two orthonormal eigenvectors. These usually indicate the * orientation of the geometry. */ rc = eigenvectors(im, tran->Evecs, d); if (rc){ if (zz->Proc == 0){ ZOLTAN_PRINT_WARN(0, yo, "REDUCE_DIMENSIONS calculation failed"); } goto End; } /* * Here we check to see if the eigenvectors are very close * to the coordinate axes. If so, we can more quickly * determine whether the geometry is degenerate, and also more * quickly transform the geometry to the lower dimensional * space. */ axis_aligned = 0; for (i=0; i<d; i++){ tran->Axis_Order[i] = -1; } for (j=0; j<d; j++){ for (i=0; i<d; i++){ x = fabs(tran->Evecs[i][j]); if (NEAR_ONE(x)){ tran->Axis_Order[j] = i; /* e'vector j is very close to i axis */ break; } } if (tran->Axis_Order[j] < 0){ break; } } if ((tran->Axis_Order[0] >= 0) && (tran->Axis_Order[1] >= 0) && (tran->Axis_Order[2] >= 0)){ axis_aligned = 1; } /* * Calculate the extent of the geometry along the three lines defined * by the direction of the eigenvectors through the center of mass. */ projected_distances(zz, *coords, num_obj, tran->CM, tran->Evecs, dist, d, axis_aligned, tran->Axis_Order); /* * Decide whether these distances indicate the geometry is * very flat in one or two directions. */ target_dim = get_target_dimension(dist, order, deg_ratio, d); if (target_dim > 0){ /* * Yes, geometry is degenerate */ if ((zz->Debug_Level > 0) && (zz->Proc == 0)){ if (d == 2){ sprintf(msg, "Geometry (~%lf x %lf), exceeds %lf to 1.0 ratio", dist[order[0]], dist[order[1]], deg_ratio); } else{ sprintf(msg, "Geometry (~%lf x %lf x %lf), exceeds %lf to 1.0 ratio", dist[order[0]], dist[order[1]], dist[order[2]], deg_ratio); } ZOLTAN_PRINT_INFO(zz->Proc, yo, msg); sprintf(msg, "We'll treat it as %d dimensional",target_dim); ZOLTAN_PRINT_INFO(zz->Proc, yo, msg); } if (axis_aligned){ /* ** Create new geometry, transforming the primary direction ** to the X-axis, and the secondary to the Y-axis. */ tran->Permutation[0] = tran->Axis_Order[order[0]]; if (target_dim == 2){ tran->Permutation[1] = tran->Axis_Order[order[1]]; } } else{ /* * Reorder the eigenvectors (they're the columns of evecs) from * longest projected distance to shorted projected distance. Compute * the transpose (the inverse) of the matrix. This will transform * the geometry to align along the X-Y plane, or along the X axis. */ for (i=0; i< target_dim; i++){ tran->Transformation[i][2] = 0.0; for (j=0; j<d; j++){ tran->Transformation[i][j] = tran->Evecs[j][order[i]]; } } for (i=target_dim; i< 3; i++){ for (j=0; j<3; j++){ tran->Transformation[i][j] = 0.0; } } } tran->Target_Dim = target_dim; transform_coordinates(*coords, num_obj, d, tran); } /* If geometry is very flat */ } /* If REDUCE_DIMENSIONS is true */ } /* If 2-D or 3-D rcb, rib or hsfc */ End: if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error found; no coordinates returned."); if (alloced_coords) ZOLTAN_FREE(coords); } ZOLTAN_TRACE_EXIT(zz, yo); return ierr; }
int Zoltan_RIB_Build_Structure(ZZ *zz, int *num_obj, int *max_obj, int wgtflag, double overalloc, int use_ids, int gen_tree) { /* Function to build the geometry-based data structures for RIB method. */ char *yo = "Zoltan_RIB_Build_Structure"; RIB_STRUCT *rib; /* Data structure for RIB. */ struct rib_tree *treeptr; int i, ierr = 0; /* Allocate an RIB data structure for this Zoltan structure. If the previous data structure is still there, free the Dots and IDs first; the other fields can be reused. */ if (zz->LB.Data_Structure == NULL) { rib = (RIB_STRUCT *) ZOLTAN_MALLOC(sizeof(RIB_STRUCT)); if (rib == NULL) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Insufficient memory."); return(ZOLTAN_MEMERR); } zz->LB.Data_Structure = (void *) rib; rib->Tree_Ptr = NULL; rib->Global_IDs = NULL; rib->Local_IDs = NULL; Zoltan_Initialize_Transformation(&(rib->Tran)); if (gen_tree) { rib->Tree_Ptr = (struct rib_tree *) ZOLTAN_CALLOC(zz->LB.Num_Global_Parts, sizeof(struct rib_tree)); if (rib->Tree_Ptr == NULL) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Insufficient memory."); Zoltan_RIB_Free_Structure(zz); return(ZOLTAN_MEMERR); } /* initialize Tree_Ptr */ for (i = 0; i < zz->LB.Num_Global_Parts; i++) { treeptr = &(rib->Tree_Ptr[i]); treeptr->cm[0] = treeptr->cm[1] = treeptr->cm[2] = 0.0; treeptr->ev[0] = treeptr->ev[1] = treeptr->ev[2] = 0.0; treeptr->cut = 0.0; treeptr->parent = treeptr->left_leaf = treeptr->right_leaf = 0; } } } else { rib = (RIB_STRUCT *) zz->LB.Data_Structure; ZOLTAN_FREE(&(rib->Global_IDs)); ZOLTAN_FREE(&(rib->Local_IDs)); ZOLTAN_FREE(&(rib->Dots)); } ierr = Zoltan_RB_Build_Structure(zz, &(rib->Global_IDs), &(rib->Local_IDs), &(rib->Dots), num_obj, max_obj, &(rib->Num_Geom), wgtflag, overalloc, use_ids, 0); if (ierr) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Error returned from Zoltan_RB_Build_Structure."); Zoltan_RIB_Free_Structure(zz); return(ierr); } return(ZOLTAN_OK); }