mirror of
https://github.com/PhasicFlow/phasicFlow.git
synced 2025-07-28 03:27:05 +00:00
1159 lines
38 KiB
C
1159 lines
38 KiB
C
/*
|
|
* @HEADER
|
|
*
|
|
* ***********************************************************************
|
|
*
|
|
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
|
|
* Copyright 2012 Sandia Corporation
|
|
*
|
|
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
|
|
* the U.S. Government retains certain rights in this software.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the Corporation nor the names of the
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* Questions? Contact Karen Devine kddevin@sandia.gov
|
|
* Erik Boman egboman@sandia.gov
|
|
*
|
|
* ***********************************************************************
|
|
*
|
|
* @HEADER
|
|
*/
|
|
|
|
|
|
#ifdef __cplusplus
|
|
/* if C++, define the rest of this header file as extern C */
|
|
extern "C" {
|
|
#endif
|
|
|
|
|
|
#include <ctype.h>
|
|
#include "zz_const.h"
|
|
#include "zz_util_const.h"
|
|
#include "all_allo_const.h"
|
|
#include "params_const.h"
|
|
#include "order_const.h"
|
|
#include "third_library.h"
|
|
#include "graph.h"
|
|
#include "graph_util.h"
|
|
|
|
/********** parameters structure used by both ParMetis and Jostle **********/
|
|
static PARAM_VARS Graph_params[] = {
|
|
{ "CHECK_GRAPH", NULL, "INT", 0 },
|
|
{ "SCATTER_GRAPH", NULL, "INT", 0 },
|
|
{ "FINAL_OUTPUT", NULL, "INT", 0 },
|
|
{ "USE_TIMERS", NULL, "INT", 0 },
|
|
{ "ADD_OBJ_WEIGHT", NULL, "STRING", 0},
|
|
{ NULL, NULL, NULL, 0 } };
|
|
|
|
/* Extern function prototypes. Should be in a separate header file? */
|
|
extern int Zoltan_Compare_Ints(const void *key, const void *arg);
|
|
|
|
|
|
/* Auxiliary function prototypes. */
|
|
static int Zoltan_Preprocess_Add_Weight (ZZ*, ZOLTAN_Third_Graph * gr,
|
|
ZOLTAN_Third_Part * prt,
|
|
char * add_obj_weight);
|
|
|
|
|
|
static int Zoltan_Preprocess_Scale_Weights(ZOLTAN_Third_Graph *, float *,
|
|
weighttype**, int, int, int, ZZ*,
|
|
char *, indextype);
|
|
static int Zoltan_Preprocess_Extract_Geom(ZZ *zz,
|
|
ZOLTAN_ID_PTR *global_ids,
|
|
ZOLTAN_ID_PTR *local_ids,
|
|
ZOLTAN_Third_Graph *gr,
|
|
ZOLTAN_Third_Geom *geo);
|
|
static int Zoltan_Preprocess_Extract_Vsize(ZZ *zz,
|
|
ZOLTAN_ID_PTR *global_ids,
|
|
ZOLTAN_ID_PTR *local_ids,
|
|
ZOLTAN_Third_Graph *gr,
|
|
ZOLTAN_Third_Vsize *vsp);
|
|
static int Zoltan_Preprocess_Scatter_Graph(ZZ *zz,
|
|
ZOLTAN_Third_Graph *gr,
|
|
ZOLTAN_Third_Part *prt,
|
|
ZOLTAN_Third_Geom *geo,
|
|
ZOLTAN_Third_Vsize *vsp);
|
|
static int scale_round_weights(float *, weighttype *, int, int,
|
|
int, weighttype, int, MPI_Comm);
|
|
static int Zoltan_LB_Add_Part_Sizes_Weight(ZZ *, int, int, realtype *, realtype **);
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
static int
|
|
give_proc (indextype vertex, const indextype *vtxdist, int numProc, int *myproc);
|
|
|
|
/**
|
|
* This function fills data structures in order to call a third party
|
|
* library like ParMetis or Scotch
|
|
**/
|
|
|
|
int Zoltan_Preprocess_Graph(
|
|
ZZ *zz, /* Zoltan structure */
|
|
ZOLTAN_ID_PTR *global_ids,
|
|
ZOLTAN_ID_PTR *local_ids,
|
|
ZOLTAN_Third_Graph *gr, /* Graph for third part libs */
|
|
ZOLTAN_Third_Geom *geo,
|
|
ZOLTAN_Third_Part *prt,
|
|
ZOLTAN_Third_Vsize *vsp
|
|
)
|
|
{
|
|
static char *yo = "Zoltan_Preprocess_Graph";
|
|
ZOLTAN_GNO_TYPE tmp_gno;
|
|
ZOLTAN_GNO_TYPE *gno_ptr1=NULL, *gno_ptr2=NULL;
|
|
int *int_ptr=NULL;
|
|
|
|
int ierr;
|
|
float *float_vwgt=NULL, *float_ewgts=NULL;
|
|
char msg[256];
|
|
ZG *graph = &(gr->graph);
|
|
int i, j, local;
|
|
int *input_part = NULL;
|
|
ZOLTAN_GNO_TYPE *sum, nobj;
|
|
MPI_Datatype zoltan_gno_mpi_type;
|
|
|
|
char add_obj_weight[MAX_PARAM_STRING_LEN];
|
|
|
|
ZOLTAN_TRACE_ENTER(zz, yo);
|
|
|
|
zoltan_gno_mpi_type = Zoltan_mpi_gno_type();
|
|
|
|
if (zz->Debug_Level > 0 && zz->Debug_Proc == zz->Proc){
|
|
printf("Third party library real type is %lu-byte real number\n",
|
|
(unsigned long) (sizeof(realtype)));
|
|
printf("Third party library index type is %lu-byte integer\n",
|
|
(unsigned long) (sizeof(indextype)));
|
|
#ifdef TPL_INTEGRAL_WEIGHT
|
|
printf("Third party library weight type is %lu-byte integer\n",
|
|
(unsigned long) (sizeof(weighttype)));
|
|
#else
|
|
printf("Third party library weight type is %lu-byte floating point value\n",
|
|
(unsigned long) (sizeof(weighttype)));
|
|
#endif
|
|
|
|
#if __parmetis__ + __metis__ + __ptscotch__ + __scotch__ > 1
|
|
printf("Zoltan was compiled with support for: ");
|
|
#if __parmetis__ == 1
|
|
printf("ParMetis ");
|
|
#endif
|
|
#if __metis__ == 1
|
|
printf("Metis ");
|
|
#endif
|
|
#if __scotch__ == 1
|
|
printf("Scotch ");
|
|
#endif
|
|
#if __ptscotch__ == 1
|
|
printf("PT-Scotch ");
|
|
#endif
|
|
printf("\n");
|
|
#endif
|
|
|
|
fflush(stdout);
|
|
}
|
|
|
|
/* Initialize all local pointers to NULL. This is necessary
|
|
* because we free all non-NULL pointers upon errors.
|
|
*/
|
|
gr->xadj = NULL;
|
|
gr->vtxdist = gr->adjncy = NULL;
|
|
gr->vwgt = gr->ewgts = NULL;
|
|
float_vwgt = float_ewgts = NULL;
|
|
|
|
if (gr->obj_wgt_dim >= 0) {
|
|
/* Check weight dimensions */
|
|
if (zz->Obj_Weight_Dim<0){
|
|
sprintf(msg, "Object weight dimension is %d, "
|
|
"but should be >= 0. Using Obj_Weight_Dim = 0.",
|
|
zz->Obj_Weight_Dim);
|
|
ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
|
|
gr->obj_wgt_dim = 0;
|
|
}
|
|
else {
|
|
gr->obj_wgt_dim = zz->Obj_Weight_Dim;
|
|
}
|
|
}
|
|
else
|
|
gr->obj_wgt_dim = 0;
|
|
if (gr->edge_wgt_dim >= 0) {
|
|
if (zz->Edge_Weight_Dim<0){
|
|
sprintf(msg, "Edge weight dimension is %d, "
|
|
"but should be >= 0. Using Edge_Weight_Dim = 0.",
|
|
zz->Edge_Weight_Dim);
|
|
ZOLTAN_PRINT_WARN(zz->Proc, yo, msg);
|
|
gr->edge_wgt_dim = 0;
|
|
}
|
|
else if (zz->Edge_Weight_Dim>1){
|
|
ZOLTAN_PRINT_WARN(zz->Proc, yo, "This method does not support "
|
|
"multidimensional edge weights. Using Edge_Weight_Dim = 1.");
|
|
gr->edge_wgt_dim = 1;
|
|
}
|
|
else {
|
|
gr->edge_wgt_dim = zz->Edge_Weight_Dim;
|
|
}
|
|
}
|
|
else
|
|
gr->edge_wgt_dim = 0;
|
|
|
|
/* Default graph type is GLOBAL. */
|
|
|
|
/* Get parameter options shared by ParMetis and Jostle */
|
|
gr->check_graph = 1; /* default */
|
|
gr->scatter = 1; /* default */
|
|
gr->final_output = 0;
|
|
strcpy(add_obj_weight, "NONE"); /* default */
|
|
Zoltan_Bind_Param(Graph_params, "CHECK_GRAPH", (void *) &gr->check_graph);
|
|
Zoltan_Bind_Param(Graph_params, "SCATTER_GRAPH", (void *) &gr->scatter);
|
|
Zoltan_Bind_Param(Graph_params, "FINAL_OUTPUT", (void *) &gr->final_output);
|
|
Zoltan_Bind_Param(Graph_params, "ADD_OBJ_WEIGHT", (void *) add_obj_weight);
|
|
Zoltan_Assign_Param_Vals(zz->Params, Graph_params, zz->Debug_Level, zz->Proc,
|
|
zz->Debug_Proc);
|
|
|
|
/* Build Graph for third party library data structures, or just get vtxdist.*/
|
|
|
|
if (gr->get_data) {
|
|
ZOLTAN_FREE(&float_vwgt);
|
|
ZOLTAN_FREE(global_ids);
|
|
ZOLTAN_FREE(local_ids);
|
|
local = IS_LOCAL_GRAPH(gr->graph_type);
|
|
|
|
ierr = Zoltan_ZG_Build (zz, graph, local, 0,0,NULL,NULL); /* Normal graph */
|
|
CHECK_IERR;
|
|
|
|
ierr = Zoltan_ZG_Export (zz, graph,
|
|
&tmp_gno, &gr->num_obj, &gr->obj_wgt_dim, &gr->edge_wgt_dim,
|
|
&gno_ptr1, &int_ptr, &gno_ptr2, /* vtxdist, xadj, adjncy */
|
|
&gr->adjproc,
|
|
&float_ewgts, NULL);
|
|
|
|
ierr = Zoltan_Check_TPL_Data_Sizes(zz, gr->num_obj);
|
|
CHECK_IERR;
|
|
|
|
FIELD_DO_NOT_FREE_WHEN_DONE(graph->mtx.delete_flag, FIELD_PINWGT); /* its pointer is in float_ewgts */
|
|
|
|
if (sizeof(indextype) != sizeof(int)){
|
|
|
|
/* Zoltan uses data type int , third party library uses indextype */
|
|
|
|
j = gr->num_obj + 1;
|
|
gr->xadj = (indextype *)ZOLTAN_MALLOC(sizeof(indextype) * j);
|
|
if (!gr->xadj)
|
|
ZOLTAN_PARMETIS_ERROR(ZOLTAN_MEMERR, "Out of memory.");
|
|
|
|
for (i=0; i < j; i++)
|
|
gr->xadj[i] = (indextype)int_ptr[i];
|
|
|
|
}
|
|
else{
|
|
gr->xadj = (indextype *)int_ptr;
|
|
FIELD_DO_NOT_FREE_WHEN_DONE(graph->mtx.delete_flag, FIELD_YSTART);
|
|
}
|
|
|
|
if (sizeof(indextype) != sizeof(ZOLTAN_GNO_TYPE)){
|
|
|
|
/* Zoltan uses data type ZOLTAN_GNO_TYPE, third party library uses indextype */
|
|
|
|
j = zz->Num_Proc + 1;
|
|
gr->vtxdist = (indextype *)ZOLTAN_MALLOC(sizeof(indextype) * j);
|
|
if (!gr->vtxdist)
|
|
ZOLTAN_PARMETIS_ERROR(ZOLTAN_MEMERR, "Out of memory.");
|
|
|
|
for (i=0; i < j; i++)
|
|
gr->vtxdist[i] = (indextype)gno_ptr1[i];
|
|
|
|
|
|
|
|
j = (int)gr->xadj[gr->num_obj];
|
|
gr->adjncy = (indextype *)ZOLTAN_MALLOC(sizeof(indextype) * (j+1));
|
|
/* KDD 10/7/14 ParMETIS 4 doesn't like NULL adjncy array
|
|
when j (number of adjacencies) is 0; force non-NULL */
|
|
if ((j+1) && !gr->adjncy)
|
|
ZOLTAN_PARMETIS_ERROR(ZOLTAN_MEMERR, "Out of memory.");
|
|
|
|
for (i=0; i < j; i++)
|
|
gr->adjncy[i] = (indextype)gno_ptr2[i];
|
|
|
|
}
|
|
else{
|
|
gr->vtxdist = (indextype *)gno_ptr1;
|
|
FIELD_DO_NOT_FREE_WHEN_DONE(graph->mtx.delete_flag, FIELD_DIST_Y);
|
|
|
|
if (gr->xadj[gr->num_obj] > 0) {
|
|
gr->adjncy = (indextype *)gno_ptr2;
|
|
FIELD_DO_NOT_FREE_WHEN_DONE(graph->mtx.delete_flag, FIELD_PINGNO);
|
|
}
|
|
else {
|
|
gr->adjncy = (indextype *)ZOLTAN_MALLOC(sizeof(indextype));
|
|
/* KDD 7/2/16 ParMETIS 4 doesn't like NULL adjncy array
|
|
when number of adjacencies is 0; force non-NULL */
|
|
}
|
|
}
|
|
|
|
/* Find info about the graph according to the distribution */
|
|
|
|
/* Confusing: Here global_ids is set to point in to graph->mtx.mtx.yGID but below ... */
|
|
|
|
if (prt){
|
|
|
|
input_part = NULL;
|
|
|
|
ierr = Zoltan_ZG_Vertex_Info(zz, graph, global_ids, local_ids, &float_vwgt, (int **)&input_part);
|
|
|
|
if (sizeof(indextype) != sizeof(int)){
|
|
|
|
/* Zoltan query function gets int data type, but TPL structures store indextype */
|
|
|
|
prt->input_part = (indextype *) ZOLTAN_MALLOC(sizeof(indextype) * gr->num_obj);
|
|
if (gr->num_obj > 0 && !prt->input_part)
|
|
ZOLTAN_PARMETIS_ERROR(ZOLTAN_MEMERR, "Out of memory.");
|
|
|
|
for (i=0; i < gr->num_obj; i++){
|
|
prt->input_part[i] = (indextype)input_part[i];
|
|
}
|
|
ZOLTAN_FREE(&input_part);
|
|
}
|
|
else{
|
|
prt->input_part = (indextype *)input_part;
|
|
}
|
|
}
|
|
else{
|
|
ierr = Zoltan_ZG_Vertex_Info(zz, graph, global_ids, local_ids, &float_vwgt, NULL);
|
|
}
|
|
|
|
FIELD_DO_NOT_FREE_WHEN_DONE(graph->mtx.delete_flag, FIELD_YGID);
|
|
|
|
if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN){
|
|
ZOLTAN_PARMETIS_ERROR(ierr, "Zoltan_Preprocess_Graph returned error.");
|
|
}
|
|
}
|
|
else{ /* Only geometry */
|
|
|
|
/* Confusing: Here global_ids will point to memory allocated by Zoltan_Get_Obj_List */
|
|
|
|
input_part = NULL;
|
|
|
|
ierr = Zoltan_Get_Obj_List(zz, &gr->num_obj, global_ids, local_ids,
|
|
gr->obj_wgt_dim, &float_vwgt, &input_part);
|
|
CHECK_IERR;
|
|
|
|
ierr = Zoltan_Check_TPL_Data_Sizes(zz, gr->num_obj);
|
|
CHECK_IERR;
|
|
|
|
if (prt) {
|
|
if (sizeof(indextype) != sizeof(int)){
|
|
/* Zoltan query function gets int data type, but TPL structures store indextype */
|
|
prt->input_part = (indextype *) ZOLTAN_MALLOC(gr->num_obj*sizeof(indextype));
|
|
if (gr->num_obj > 0 && prt->input_part == NULL)
|
|
ZOLTAN_PARMETIS_ERROR(ZOLTAN_MEMERR, "Out of memory.");
|
|
|
|
for (i=0; i < gr->num_obj; i++){
|
|
prt->input_part[i] = (indextype)input_part[i];
|
|
}
|
|
ZOLTAN_FREE(&input_part);
|
|
}
|
|
else{
|
|
prt->input_part = (indextype *)input_part;
|
|
}
|
|
}
|
|
else if (input_part) { /* Ordering, dont need part */
|
|
ZOLTAN_FREE(&input_part);
|
|
}
|
|
if (ierr){
|
|
/* Return error */
|
|
ZOLTAN_PARMETIS_ERROR(ierr, "Get_Obj_List returned error.");
|
|
}
|
|
|
|
/* No graph but still needs vtxdist*/
|
|
gr->vtxdist = (indextype*) ZOLTAN_MALLOC ((zz->Num_Proc+1)*sizeof(indextype));
|
|
if (gr->vtxdist == NULL)
|
|
ZOLTAN_PARMETIS_ERROR(ZOLTAN_MEMERR, "Out of memory.");
|
|
|
|
gr->vtxdist[0] = 0;
|
|
|
|
sum = (ZOLTAN_GNO_TYPE *)ZOLTAN_MALLOC(sizeof(ZOLTAN_GNO_TYPE) * zz->Num_Proc);
|
|
nobj = (ZOLTAN_GNO_TYPE )gr->num_obj;
|
|
MPI_Allgather(&nobj, 1, zoltan_gno_mpi_type, sum, 1, zoltan_gno_mpi_type, zz->Communicator);
|
|
|
|
for (i=1 ; i <= zz->Num_Proc ; ++i) {
|
|
gr->vtxdist[i] = (gr->vtxdist[i-1] + (indextype)sum[i-1]);
|
|
}
|
|
ZOLTAN_FREE(&sum);
|
|
}
|
|
|
|
if (prt) {
|
|
prt->part_sizes = prt->input_part_sizes;
|
|
/* ParMETIS needs prt->part to be allocated, even when num_obj=0. */
|
|
/* See Zoltan bug 4299. */
|
|
prt->part = (indextype *)ZOLTAN_MALLOC((gr->num_obj+1) * sizeof(indextype));
|
|
if (!prt->part) {
|
|
/* Not enough memory */
|
|
ZOLTAN_PARMETIS_ERROR(ZOLTAN_MEMERR, "Out of memory.");
|
|
}
|
|
if (gr->num_obj >0) {
|
|
memcpy (prt->part, prt->input_part, (gr->num_obj) * sizeof(indextype));
|
|
}
|
|
else {
|
|
prt->input_part = NULL;
|
|
}
|
|
}
|
|
|
|
/* Convert from float. */
|
|
|
|
/* Get vertex weights if needed */
|
|
if (gr->obj_wgt_dim){
|
|
ierr = Zoltan_Preprocess_Scale_Weights (gr, float_vwgt, &gr->vwgt,
|
|
gr->num_obj, gr->obj_wgt_dim, 1, zz,
|
|
"vertex", gr->vtxdist[zz->Proc]);
|
|
if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN){
|
|
/* Return error code */
|
|
ZOLTAN_PARMETIS_ERROR(ierr, "Error in scaling of weights.");
|
|
}
|
|
ZOLTAN_FREE(&float_vwgt);
|
|
}
|
|
|
|
if (strcasecmp(add_obj_weight, "NONE")){
|
|
if (Zoltan_Preprocess_Add_Weight(zz, gr, prt, add_obj_weight) != ZOLTAN_OK)
|
|
ZOLTAN_PARMETIS_ERROR(ierr, "Error in adding vertex weights.");
|
|
}
|
|
|
|
/* Get edge weights if needed */
|
|
if (gr->get_data)
|
|
gr->num_edges = (int)gr->xadj[gr->num_obj];
|
|
else {
|
|
gr->num_edges = 0;
|
|
gr->edge_wgt_dim = 0;
|
|
}
|
|
|
|
if (gr->edge_wgt_dim){
|
|
ierr = Zoltan_Preprocess_Scale_Weights(gr, float_ewgts, &gr->ewgts,
|
|
gr->num_edges, gr->edge_wgt_dim, 1,zz,
|
|
"edge", 0);
|
|
if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN){
|
|
/* Return error code */
|
|
ZOLTAN_PARMETIS_ERROR(ierr, "Error in scaling of weights.");
|
|
}
|
|
if (!gr->final_output) {
|
|
ZOLTAN_FREE(&float_ewgts);
|
|
}
|
|
else
|
|
gr->float_ewgts = float_ewgts;
|
|
}
|
|
else {
|
|
ZOLTAN_FREE(&float_ewgts);
|
|
}
|
|
|
|
if (geo){
|
|
ierr = Zoltan_Preprocess_Extract_Geom (zz, global_ids, local_ids, gr, geo);
|
|
if (ierr) {
|
|
ZOLTAN_PARMETIS_ERROR(ZOLTAN_FATAL,
|
|
"Error returned from Zoltan_Preprocess_Extract_Geom");
|
|
}
|
|
}
|
|
|
|
|
|
if (vsp) {
|
|
ierr = Zoltan_Preprocess_Extract_Vsize (zz, global_ids, local_ids, gr, vsp);
|
|
if (ierr) {
|
|
ZOLTAN_PARMETIS_ERROR(ZOLTAN_FATAL,
|
|
"Error returned from Zoltan_Preprocess_Extract_Vsize");
|
|
}
|
|
}
|
|
|
|
/* Scatter graph?
|
|
* If data distribution is highly imbalanced, it is better to
|
|
* redistribute the graph data structure before calling ParMetis.
|
|
* After partitioning, the results must be mapped back.
|
|
*/
|
|
if (gr->scatter < gr->scatter_min) gr->scatter = gr->scatter_min;
|
|
|
|
if (gr->scatter>0) {
|
|
ierr = Zoltan_Preprocess_Scatter_Graph (zz, gr, prt, geo, vsp);
|
|
if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN) {
|
|
ZOLTAN_PARMETIS_ERROR(ZOLTAN_FATAL,
|
|
"Error returned from Zoltan_Preprocess_Scatter_Graph");
|
|
}
|
|
}
|
|
|
|
|
|
/* Verify that graph is correct */
|
|
if (gr->get_data){
|
|
int flag;
|
|
|
|
if (zz->Debug_Level >= ZOLTAN_DEBUG_ALL)
|
|
flag = 2; /* Maximum output level */
|
|
else if (zz->Debug_Level >= ZOLTAN_DEBUG_TRACE_SINGLE)
|
|
flag = 1; /* Medium output level */
|
|
else
|
|
flag = 0; /* No output */
|
|
|
|
ierr = Zoltan_Verify_Graph(zz->Communicator, gr->vtxdist, gr->xadj,
|
|
gr->adjncy, gr->vwgt, gr->ewgts, gr->obj_wgt_dim,
|
|
gr->edge_wgt_dim, gr->graph_type, gr->check_graph,
|
|
flag);
|
|
}
|
|
|
|
End:
|
|
|
|
ZOLTAN_TRACE_EXIT(zz, yo);
|
|
|
|
return (ierr);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
static int
|
|
Zoltan_Preprocess_Add_Weight (ZZ *zz,
|
|
ZOLTAN_Third_Graph * gr,
|
|
ZOLTAN_Third_Part * prt,
|
|
char * add_obj_weight)
|
|
{
|
|
static char * yo = "Zoltan_Preprocess_Add_Weight";
|
|
/* Add a vertex weight? */
|
|
int add_type = 0;
|
|
weighttype *vwgt_new;
|
|
int ierr = ZOLTAN_OK;
|
|
int i,j;
|
|
|
|
if ((!strcasecmp(add_obj_weight, "UNIT")) ||
|
|
(!strcasecmp(add_obj_weight, "VERTICES"))){
|
|
add_type = 1;
|
|
}
|
|
else if ((!strcasecmp(add_obj_weight, "VERTEX DEGREE")) ||
|
|
(!strcasecmp(add_obj_weight, "PINS")) ||
|
|
(!strcasecmp(add_obj_weight, "NONZEROS"))){
|
|
add_type = 2;
|
|
}
|
|
else {
|
|
ZOLTAN_PRINT_WARN(zz->Proc,yo, "Invalid parameter value for ADD_OBJ_WEIGHT");
|
|
ierr = ZOLTAN_WARN;
|
|
add_type = 0;
|
|
}
|
|
if (add_type){
|
|
vwgt_new = (weighttype *)ZOLTAN_MALLOC((gr->obj_wgt_dim+1)*gr->num_obj
|
|
* sizeof(weighttype));
|
|
if (prt != NULL) {
|
|
/* update part_sizes array */
|
|
ierr = Zoltan_LB_Add_Part_Sizes_Weight(zz,
|
|
(gr->obj_wgt_dim ? gr->obj_wgt_dim : 1),
|
|
gr->obj_wgt_dim+1,
|
|
prt->input_part_sizes, &prt->part_sizes);
|
|
}
|
|
/* Add implicit weights in new array */
|
|
for (i=0; i<gr->num_obj; i++){
|
|
/* First copy old weights */
|
|
for (j=0; j<gr->obj_wgt_dim; j++){
|
|
vwgt_new[i*(gr->obj_wgt_dim+1)+j] = gr->vwgt[i*gr->obj_wgt_dim+j];
|
|
}
|
|
if (add_type==1)
|
|
/* unit weight */
|
|
vwgt_new[i*(gr->obj_wgt_dim+1)+gr->obj_wgt_dim] = 1;
|
|
else if (add_type==2)
|
|
/* weight is vertex degree (EBEB should we add +1?) */
|
|
/* vwgt_new[i*(gr->obj_wgt_dim+1)+gr->obj_wgt_dim] = 10*(gr->xadj[i+1] -gr->xadj[i]) + 1; */
|
|
vwgt_new[i*(gr->obj_wgt_dim+1)+gr->obj_wgt_dim] =
|
|
gr->xadj[i+1] - gr->xadj[i];
|
|
}
|
|
/* Use new vwgt array */
|
|
if (gr->vwgt) ZOLTAN_FREE(&gr->vwgt);
|
|
gr->vwgt = vwgt_new;
|
|
gr->obj_wgt_dim += 1;
|
|
}
|
|
|
|
return (ierr);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
static int Zoltan_Preprocess_Scale_Weights(
|
|
ZOLTAN_Third_Graph *gr,
|
|
float *flt_wgt,
|
|
weighttype** rnd_wgt,
|
|
int number,
|
|
int ndim,
|
|
int mode,
|
|
ZZ* zz,
|
|
char * name,
|
|
indextype offset
|
|
)
|
|
{
|
|
static char * yo = "Zoltan_Preprocess_Scale_Weights";
|
|
int ierr = ZOLTAN_OK;
|
|
int i99;
|
|
int k;
|
|
char msg[256];
|
|
|
|
if (ndim == 0)
|
|
return ierr;
|
|
|
|
if (zz->Debug_Level >= ZOLTAN_DEBUG_ALL){
|
|
for (i99=0; i99 < (number <3 ? number : 3); i99++){
|
|
for (k=0; k<gr->obj_wgt_dim; k++)
|
|
sprintf(msg+10*k, "%.9f ", flt_wgt[i99*gr->obj_wgt_dim+k]);
|
|
printf("[%1d] Debug: before scaling weights for %s " TPL_IDX_SPEC
|
|
" = %s\n", zz->Proc, name, offset+i99, msg);
|
|
}
|
|
}
|
|
|
|
*rnd_wgt = (weighttype *)ZOLTAN_MALLOC(ndim * number * sizeof(weighttype));
|
|
if ((number >0 ) && (*rnd_wgt == NULL)){
|
|
/* Not enough memory */
|
|
ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Out of memory.");
|
|
}
|
|
|
|
ierr = scale_round_weights(flt_wgt, *rnd_wgt, number, ndim, mode,
|
|
MAX_WGT_SUM, zz->Debug_Level,
|
|
zz->Communicator);
|
|
|
|
if (ierr != ZOLTAN_OK && ierr != ZOLTAN_WARN){
|
|
ZOLTAN_FREE(rnd_wgt);
|
|
/* Return error code */
|
|
ZOLTAN_THIRD_ERROR(ierr, "Error in scaling of weights.");
|
|
}
|
|
|
|
if (zz->Debug_Level >= ZOLTAN_DEBUG_ALL){
|
|
for (i99=0; i99 < (number < 3 ? number : 3); i99++){
|
|
for (k=0; k<gr->obj_wgt_dim; k++)
|
|
sprintf(msg+10*k, TPL_WGT_SPEC " ", (*rnd_wgt)[i99*gr->obj_wgt_dim+k]);
|
|
printf("[%1d] Debug: scaled weights for %s " TPL_IDX_SPEC " = %s\n",
|
|
zz->Proc, name, offset+i99, msg);
|
|
}
|
|
}
|
|
|
|
return (ierr);
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
static int
|
|
Zoltan_Preprocess_Extract_Geom (ZZ *zz,
|
|
ZOLTAN_ID_PTR *global_ids,
|
|
ZOLTAN_ID_PTR *local_ids,
|
|
ZOLTAN_Third_Graph *gr,
|
|
ZOLTAN_Third_Geom *geo)
|
|
{
|
|
static char * yo = "Zoltan_Preprocess_Extract_Geom";
|
|
int ierr;
|
|
double *geom_vec;
|
|
int i;
|
|
|
|
geom_vec = NULL;
|
|
/* Get coordinate information */
|
|
ierr = Zoltan_Get_Coordinates(zz, gr->num_obj, *global_ids, *local_ids,
|
|
&geo->ndims, &geom_vec);
|
|
if (ierr) {
|
|
ZOLTAN_THIRD_ERROR(ZOLTAN_FATAL,
|
|
"Error returned from Zoltan_Get_Coordinates");
|
|
}
|
|
if (sizeof(realtype) != sizeof(double)) {
|
|
/* Convert geometry info from double to float for ParMETIS */
|
|
if (gr->num_obj && geo->ndims) {
|
|
geo->xyz = (realtype *) ZOLTAN_MALLOC(gr->num_obj*geo->ndims*sizeof(realtype));
|
|
if (geo->xyz == NULL) {
|
|
ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Memory error.");
|
|
}
|
|
for (i = 0; i < gr->num_obj * geo->ndims; i++)
|
|
geo->xyz[i] = (realtype) geom_vec[i];
|
|
ZOLTAN_FREE(&geom_vec);
|
|
}
|
|
}
|
|
else
|
|
geo->xyz = (realtype *)geom_vec;
|
|
|
|
return ierr;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
static int
|
|
Zoltan_Preprocess_Extract_Vsize (ZZ *zz,
|
|
ZOLTAN_ID_PTR *global_ids,
|
|
ZOLTAN_ID_PTR *local_ids,
|
|
ZOLTAN_Third_Graph *gr,
|
|
ZOLTAN_Third_Vsize *vsp)
|
|
{
|
|
static char * yo = "Zoltan_Preprocess_Extract_Vsize";
|
|
int num_gid_entries = zz->Num_GID;
|
|
int num_lid_entries = zz->Num_LID;
|
|
int ierr= ZOLTAN_OK;
|
|
int i;
|
|
int *buf = NULL;
|
|
|
|
if (gr->obj_wgt_dim)
|
|
vsp->vsize_malloc = 0;
|
|
|
|
if (!vsp->vsize) { /* If not already allocated */
|
|
if (vsp->vsize_malloc)
|
|
vsp->vsize = (indextype *) malloc(gr->num_obj*sizeof(indextype));
|
|
else
|
|
vsp->vsize = (indextype *) ZOLTAN_MALLOC(gr->num_obj*sizeof(indextype));
|
|
}
|
|
vsp->vsizeBACKUP = (indextype *) ZOLTAN_MALLOC(gr->num_obj*sizeof(indextype));
|
|
if (gr->num_obj && !vsp->vsize){
|
|
/* Not enough space */
|
|
ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Out of memory.");
|
|
}
|
|
|
|
if (zz->Get_Obj_Size_Multi) {
|
|
|
|
if (sizeof(indextype) != sizeof(int) ){
|
|
buf = (int *)ZOLTAN_MALLOC(sizeof(int) * gr->num_obj);
|
|
if (gr->num_obj && !buf){
|
|
ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Out of memory.");
|
|
}
|
|
}
|
|
else {
|
|
buf = (int *)vsp->vsize;
|
|
}
|
|
|
|
zz->Get_Obj_Size_Multi(zz->Get_Obj_Size_Multi_Data,
|
|
num_gid_entries, num_lid_entries, gr->num_obj,
|
|
*global_ids, *local_ids, buf, &ierr);
|
|
|
|
if (sizeof(indextype) != sizeof(int) ){
|
|
for (i=0; i < gr->num_obj; i++){
|
|
vsp->vsize[i] = (indextype)buf[i];
|
|
}
|
|
ZOLTAN_FREE(&buf);
|
|
}
|
|
|
|
}
|
|
else if (zz->Get_Obj_Size) {
|
|
ZOLTAN_ID_PTR lid;
|
|
for (i=0; i<gr->num_obj; i++){
|
|
lid = (num_lid_entries ? &((*local_ids)[i*num_lid_entries]) : NULL);
|
|
vsp->vsize[i] = (indextype)zz->Get_Obj_Size(zz->Get_Obj_Size_Data,
|
|
num_gid_entries, num_lid_entries,
|
|
&((*global_ids)[i*num_gid_entries]),
|
|
lid, &ierr);
|
|
}
|
|
}
|
|
else {
|
|
/* Assume uniform sizes if no Obj_Size callbacks are registered. */
|
|
for (i = 0; i < gr->num_obj; i++)
|
|
vsp->vsize[i] = 1;
|
|
}
|
|
memcpy(vsp->vsizeBACKUP, vsp->vsize, sizeof(indextype)*gr->num_obj);
|
|
return (ierr);
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
static int
|
|
Zoltan_Preprocess_Scatter_Graph (ZZ *zz,
|
|
ZOLTAN_Third_Graph *gr,
|
|
ZOLTAN_Third_Part *prt,
|
|
ZOLTAN_Third_Geom *geo,
|
|
ZOLTAN_Third_Vsize *vsp)
|
|
{
|
|
static char * yo = "Zoltan_Preprocess_Scatter_Graph";
|
|
int ierr = ZOLTAN_OK;
|
|
int tmp;
|
|
int procid;
|
|
int i;
|
|
|
|
if ((gr->scatter>0) && (gr->scatter<3)){
|
|
int j;
|
|
/* Decide if the data imbalance is so bad that we should scatter the graph. */
|
|
/* scatter==1: Scatter if all the objects are on a single processor. */
|
|
/* scatter==2: Scatter if any processor has no objects. */
|
|
gr->num_obj_orig = gr->num_obj; /* Save value for later. */
|
|
if (gr->num_obj==0)
|
|
j = 1;
|
|
else
|
|
j = 0;
|
|
MPI_Allreduce(&j, &tmp, 1, MPI_INT, MPI_SUM, zz->Communicator);
|
|
if (gr->scatter == 1){
|
|
if (tmp < zz->Num_Proc-1)
|
|
gr->scatter = 0;
|
|
}
|
|
else if (gr->scatter==2){
|
|
if (tmp == 0)
|
|
gr->scatter = 0;
|
|
}
|
|
}
|
|
|
|
/* We need to make sure we don't scatter the graph
|
|
* if graph_type = LOCAL_GRAPH, i.e. METIS is used.
|
|
*/
|
|
if (gr->scatter && (IS_LOCAL_GRAPH(gr->graph_type))){
|
|
gr->scatter = 0;
|
|
ZOLTAN_PRINT_WARN(zz->Proc, yo, "Setting scatter_graph=0 since the graph"
|
|
" is local on each proc");
|
|
ierr = ZOLTAN_WARN;
|
|
}
|
|
|
|
if (gr->scatter){
|
|
|
|
if (geo)
|
|
ierr = Zoltan_Scatter_Graph(&gr->vtxdist, &gr->xadj, &gr->adjncy,
|
|
&gr->vwgt, (vsp ? &vsp->vsize : NULL),
|
|
&gr->ewgts, &geo->xyz, geo->ndims,
|
|
gr->obj_wgt_dim, zz, &gr->comm_plan);
|
|
else {
|
|
realtype* xyz = NULL;
|
|
ierr = Zoltan_Scatter_Graph(&gr->vtxdist, &gr->xadj, &gr->adjncy,
|
|
&gr->vwgt, (vsp ? &vsp->vsize : NULL),
|
|
&gr->ewgts, &xyz, 0,
|
|
gr->obj_wgt_dim, zz, &gr->comm_plan);
|
|
}
|
|
if ((ierr == ZOLTAN_FATAL) || (ierr == ZOLTAN_MEMERR)){
|
|
ZOLTAN_THIRD_ERROR(ierr, "Zoltan_Scatter_Graph returned error.");
|
|
}
|
|
gr->num_obj = gr->vtxdist[zz->Proc+1]-gr->vtxdist[zz->Proc];
|
|
|
|
/* Construct the adjproc array */
|
|
ZOLTAN_FREE(&gr->adjproc);
|
|
gr->adjproc = (int *) ZOLTAN_MALLOC(gr->xadj[gr->num_obj] * sizeof(int));
|
|
for (i = 0, procid=zz->Proc ; i < gr->xadj[gr->num_obj] ; ++ i) {
|
|
gr->adjproc[i] = give_proc (gr->adjncy[i], gr->vtxdist, zz->Num_Proc, &procid);
|
|
}
|
|
|
|
if (prt) {
|
|
prt->part_orig = prt->part;
|
|
prt->part = (indextype *) ZOLTAN_MALLOC((gr->num_obj+1) * sizeof(indextype));
|
|
Zoltan_Comm_Do(gr->comm_plan, TAG1, (char *) prt->part_orig, sizeof(indextype),
|
|
(char *) prt->part);
|
|
|
|
}
|
|
|
|
}
|
|
return ierr;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/*
|
|
* Scale and round float weights to weighttype
|
|
* subject to sum(weights) <= max_wgt_sum.
|
|
* Only scale if deemed necessary.
|
|
*
|
|
* mode == 0 : no scaling, just round to int
|
|
* mode == 1 : scale each weight dimension separately
|
|
* mode == 2 : use same scale factor for all weights
|
|
*
|
|
* Note that we use ceil() instead of round() to avoid
|
|
* rounding to zero weights.
|
|
*/
|
|
|
|
static int scale_round_weights(float *fwgts, weighttype *iwgts, int n, int dim,
|
|
int mode, weighttype max_wgt_sum, int debug_level, MPI_Comm comm)
|
|
{
|
|
int i, j, tmp, ierr, proc;
|
|
int *nonint, *nonint_local;
|
|
float *scale, *sum_wgt_local, *sum_wgt, *max_wgt_local, *max_wgt;
|
|
char msg[256];
|
|
static char *yo = "scale_round_weights";
|
|
|
|
ierr = ZOLTAN_OK;
|
|
MPI_Comm_rank(comm, &proc);
|
|
|
|
if (mode == 0) {
|
|
/* No scaling; just convert to int */
|
|
for (i=0; i<n*dim; i++){
|
|
iwgts[i] = (weighttype) ceil((double) fwgts[i]);
|
|
}
|
|
}
|
|
else{
|
|
/* Allocate local arrays */
|
|
nonint = (int *)ZOLTAN_MALLOC(dim*sizeof(int));
|
|
nonint_local = (int *)ZOLTAN_MALLOC(dim*sizeof(int));
|
|
scale = (float *)ZOLTAN_MALLOC(dim*sizeof(float));
|
|
sum_wgt = (float *)ZOLTAN_MALLOC(dim*sizeof(float));
|
|
sum_wgt_local = (float *)ZOLTAN_MALLOC(dim*sizeof(float));
|
|
max_wgt = (float *)ZOLTAN_MALLOC(dim*sizeof(float));
|
|
max_wgt_local = (float *)ZOLTAN_MALLOC(dim*sizeof(float));
|
|
if (!(nonint && nonint_local && scale && sum_wgt && sum_wgt_local
|
|
&& max_wgt && max_wgt_local)){
|
|
ZOLTAN_PRINT_ERROR(proc, yo, "Out of memory.");
|
|
ZOLTAN_FREE(&nonint);
|
|
ZOLTAN_FREE(&nonint_local);
|
|
ZOLTAN_FREE(&scale);
|
|
ZOLTAN_FREE(&sum_wgt);
|
|
ZOLTAN_FREE(&sum_wgt_local);
|
|
ZOLTAN_FREE(&max_wgt);
|
|
ZOLTAN_FREE(&max_wgt_local);
|
|
return ZOLTAN_MEMERR;
|
|
}
|
|
/* Initialize */
|
|
for (j=0; j<dim; j++){
|
|
nonint_local[j] = 0;
|
|
sum_wgt_local[j] = 0;
|
|
max_wgt_local[j] = 0;
|
|
}
|
|
|
|
/* Compute local sums of the weights */
|
|
/* Check if all weights are integers */
|
|
for (i=0; i<n; i++){
|
|
for (j=0; j<dim; j++){
|
|
if (!nonint_local[j]){
|
|
/* tmp = (int) roundf(fwgts[i*dim+j]); EB: Valid C99, but not C89 */
|
|
tmp = (int) floor((double) fwgts[i*dim+j] + .5); /* Nearest int */
|
|
if (fabs((double)tmp-fwgts[i*dim+j]) > INT_EPSILON){
|
|
nonint_local[j] = 1;
|
|
}
|
|
}
|
|
sum_wgt_local[j] += fwgts[i*dim+j];
|
|
if (fwgts[i*dim+j] > max_wgt_local[j])
|
|
max_wgt_local[j] = fwgts[i*dim+j];
|
|
}
|
|
}
|
|
/* Compute global sum of the weights */
|
|
MPI_Allreduce(nonint_local, nonint, dim,
|
|
MPI_INT, MPI_LOR, comm);
|
|
MPI_Allreduce(sum_wgt_local, sum_wgt, dim,
|
|
MPI_FLOAT, MPI_SUM, comm);
|
|
MPI_Allreduce(max_wgt_local, max_wgt, dim,
|
|
MPI_FLOAT, MPI_MAX, comm);
|
|
|
|
/* Calculate scale factor */
|
|
for (j=0; j<dim; j++){
|
|
scale[j] = 1.;
|
|
/* Scale unless all weights are integers (not all zero) */
|
|
if (nonint[j] || (max_wgt[j] <= INT_EPSILON) || (sum_wgt[j] > max_wgt_sum)){
|
|
if (sum_wgt[j] == 0){
|
|
ierr = ZOLTAN_WARN;
|
|
if (proc == 0){
|
|
sprintf(msg, "All weights are zero in component %1d", j);
|
|
ZOLTAN_PRINT_WARN(proc, yo, msg);
|
|
}
|
|
}
|
|
else /* sum_wgt[j] != 0 */
|
|
scale[j] = max_wgt_sum/sum_wgt[j];
|
|
}
|
|
}
|
|
|
|
/* If mode==2, let the scale factor be the same for all weights */
|
|
if (mode==2){
|
|
for (j=1; j<dim; j++){
|
|
if (scale[j]<scale[0])
|
|
scale[0] = scale[j];
|
|
}
|
|
for (j=1; j<dim; j++){
|
|
scale[j] = scale[0];
|
|
}
|
|
}
|
|
|
|
if ((debug_level >= ZOLTAN_DEBUG_ALL) && (proc==0)){
|
|
printf("ZOLTAN DEBUG in %s: scaling weights with scale factors = ", yo);
|
|
for (j=0; j<dim; j++)
|
|
printf("%f ", scale[j]);
|
|
printf("\n");
|
|
}
|
|
|
|
/* Convert weights to positive integers using the computed scale factor */
|
|
for (i=0; i<n; i++){
|
|
for (j=0; j<dim; j++){
|
|
iwgts[i*dim+j] = (weighttype) ceil((double) fwgts[i*dim+j]*scale[j]);
|
|
}
|
|
}
|
|
|
|
ZOLTAN_FREE(&nonint);
|
|
ZOLTAN_FREE(&nonint_local);
|
|
ZOLTAN_FREE(&scale);
|
|
ZOLTAN_FREE(&sum_wgt);
|
|
ZOLTAN_FREE(&sum_wgt_local);
|
|
ZOLTAN_FREE(&max_wgt);
|
|
ZOLTAN_FREE(&max_wgt_local);
|
|
}
|
|
return ierr;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
int Zoltan_Preprocess_Timer(ZZ *zz, int *use_timers)
|
|
{
|
|
static int timer_p = -1;
|
|
|
|
*use_timers = 0;
|
|
Zoltan_Bind_Param(Graph_params, "USE_TIMERS", (void *) use_timers);
|
|
if (*use_timers) {
|
|
if (timer_p < 0)
|
|
timer_p = Zoltan_Timer_Init(zz->ZTime, 1, "ThirdLibrary");
|
|
ZOLTAN_TIMER_START(zz->ZTime, timer_p, zz->Communicator);
|
|
}
|
|
|
|
return (timer_p);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
void Zoltan_Third_DisplayTime(ZZ* zz, double* times)
|
|
{
|
|
if (zz->Proc == zz->Debug_Proc) printf("\nZOLTAN timing statistics:\n");
|
|
Zoltan_Print_Stats(zz->Communicator, zz->Debug_Proc, times[1]-times[0],
|
|
" Partitioner Pre-processing time ");
|
|
Zoltan_Print_Stats(zz->Communicator, zz->Debug_Proc, times[2]-times[1],
|
|
" Partitioner Library time ");
|
|
Zoltan_Print_Stats(zz->Communicator, zz->Debug_Proc, times[4]-times[3],
|
|
" Partitioner Post-processing time ");
|
|
Zoltan_Print_Stats(zz->Communicator, zz->Debug_Proc,
|
|
times[4]-times[3] + times[2] - times[0],
|
|
" Partitioner Total time ");
|
|
if (zz->Proc==zz->Debug_Proc) printf("\n");
|
|
}
|
|
|
|
/****************************************************************************/
|
|
static int give_proc(
|
|
indextype vertex,
|
|
const indextype *vtxdist,
|
|
int numProc,
|
|
int *myproc
|
|
)
|
|
{
|
|
int currentproc;
|
|
|
|
|
|
if ((((*myproc) >= 0) && (*myproc) < numProc) &&
|
|
(vertex >= vtxdist[*myproc]) && (vertex < vtxdist[*myproc+1])) {
|
|
return (*myproc);
|
|
}
|
|
|
|
/* Assume that vertices are balanced */
|
|
currentproc = (int)(vertex / (vtxdist[1]-vtxdist[0]));
|
|
|
|
if (currentproc >= numProc)
|
|
currentproc = numProc - 1;
|
|
|
|
if ((vertex < vtxdist[0])||( vertex >= vtxdist[numProc])) {
|
|
ZOLTAN_PRINT_WARN ((*myproc), "Symmetrize Graph problem (1)",
|
|
"Unknown vertex");
|
|
return (-1);
|
|
}
|
|
|
|
while (1) {
|
|
if (vertex >= vtxdist[currentproc + 1]) {
|
|
currentproc ++;
|
|
continue;
|
|
}
|
|
if (vertex < vtxdist[currentproc]) {
|
|
currentproc --;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
*myproc =currentproc;
|
|
return (currentproc);
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
int Zoltan_Third_Set_Param(
|
|
char *name, /* name of variable */
|
|
char *val) /* value of variable */
|
|
{
|
|
int index;
|
|
PARAM_UTYPE result;
|
|
|
|
return Zoltan_Check_Param(name, val, Graph_params, &result, &index);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
static int Zoltan_LB_Add_Part_Sizes_Weight(
|
|
ZZ *zz,
|
|
int old_part_dim, /* # of part-size entries per part in old_part_sizes */
|
|
int new_part_dim, /* # of part-size entries per part in new_part_sizes */
|
|
realtype *old_part_sizes, /* Array of part sizes before adding an entry */
|
|
realtype **new_part_sizes /* Array of part sizes after adding an entry */
|
|
)
|
|
{
|
|
/* Function to add one entry per part to part_sizes array. Returns a new
|
|
* array with the added entry.
|
|
* The added entry for a part is set by default to the zeroth part_sizes entry
|
|
* for the part.
|
|
* This function is invoked when parameter ADD_OBJ_WEIGHT is used.
|
|
*/
|
|
realtype *part_sizes; /* New part_sizes array */
|
|
int i, j;
|
|
int ierr = ZOLTAN_OK;
|
|
|
|
if (old_part_dim < 1) {
|
|
ierr = ZOLTAN_FATAL;
|
|
goto End;
|
|
}
|
|
|
|
/* new_part_dim will equal old_part_dim if obj_weight_dim = 0
|
|
and add_obj_weight != NONE */
|
|
if (old_part_dim == new_part_dim) {
|
|
*new_part_sizes = old_part_sizes;
|
|
}
|
|
else { /* Need to enlarge part_sizes array */
|
|
*new_part_sizes = (realtype *) ZOLTAN_MALLOC(new_part_dim
|
|
* zz->LB.Num_Global_Parts
|
|
* sizeof(realtype));
|
|
if (!(*new_part_sizes)) {
|
|
ierr = ZOLTAN_MEMERR;
|
|
goto End;
|
|
}
|
|
part_sizes = *new_part_sizes;
|
|
|
|
for (i = 0; i < zz->LB.Num_Global_Parts; i++) {
|
|
/* Copy old_part_sizes info to new part_sizes array */
|
|
for (j = 0; j < old_part_dim; j++)
|
|
part_sizes[i*new_part_dim+j] = old_part_sizes[i*old_part_dim+j];
|
|
/* For the added weight, use zeroth entry of old_part_sizes for part. */
|
|
for (j = old_part_dim; j < new_part_dim; j++)
|
|
part_sizes[i*new_part_dim+j] = old_part_sizes[i*old_part_dim];
|
|
}
|
|
}
|
|
|
|
End:
|
|
return ierr;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
int Zoltan_Check_TPL_Data_Sizes(ZZ *zz, int local_num_obj)
|
|
{
|
|
/* Ensure that the global number of objects will fit in type indextype. */
|
|
int ierr = ZOLTAN_OK;
|
|
ZOLTAN_GNO_TYPE tmp_num_obj, global_num_obj;
|
|
MPI_Datatype mpignotype = Zoltan_mpi_gno_type();
|
|
int64_t maxindextype = (int64_t)(((uint64_t) 1<<((sizeof(indextype)<<3)-1))-1);
|
|
|
|
tmp_num_obj = local_num_obj;
|
|
MPI_Allreduce(&tmp_num_obj, &global_num_obj, 1, mpignotype,
|
|
MPI_SUM, zz->Communicator);
|
|
|
|
if (global_num_obj > maxindextype) {
|
|
char msg[500];
|
|
sprintf(msg, "Graph TPL is built with integer type that is too small for "
|
|
"the partitioning problem. Max number of objects supported is "
|
|
"2^%lu-1; global number of objects is " ZOLTAN_GNO_SPEC "\n",
|
|
((sizeof(indextype)<<3)-1), global_num_obj);
|
|
ZOLTAN_PRINT_ERROR(zz->Proc, "check_data_sizes", msg);
|
|
ierr = ZOLTAN_FATAL;
|
|
}
|
|
|
|
return ierr;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|