Esempio n. 1
0
void setCpGridZoltanGraphFunctions(Zoltan_Struct *zz, const Dune::CpGrid& grid,
                                   bool pretendNull)
{
    Dune::CpGrid *gridPointer = const_cast<Dune::CpGrid*>(&grid);
    if ( pretendNull )
    {
        Zoltan_Set_Num_Obj_Fn(zz, getNullNumCells, gridPointer);
        Zoltan_Set_Obj_List_Fn(zz, getNullVertexList, gridPointer);
        Zoltan_Set_Num_Edges_Multi_Fn(zz, getNullNumEdgesList, gridPointer);
        Zoltan_Set_Edge_List_Multi_Fn(zz, getNullEdgeList, gridPointer);
    }
    else
    {
        Zoltan_Set_Num_Obj_Fn(zz, getCpGridNumCells, gridPointer);
        Zoltan_Set_Obj_List_Fn(zz, getCpGridVertexList, gridPointer);
        Zoltan_Set_Num_Edges_Multi_Fn(zz, getCpGridNumEdgesList, gridPointer);
        Zoltan_Set_Edge_List_Multi_Fn(zz, getCpGridEdgeList, gridPointer);
    }
}
Esempio n. 2
0
void setCpGridZoltanGraphFunctions(Zoltan_Struct *zz,
                                   const CombinedGridWellGraph& graph,
                                   bool pretendNull)
{
    Dune::CpGrid *gridPointer = const_cast<Dune::CpGrid*>(&graph.getGrid());
    if ( pretendNull )
    {
        Zoltan_Set_Num_Obj_Fn(zz, getNullNumCells, gridPointer);
        Zoltan_Set_Obj_List_Fn(zz, getNullVertexList, gridPointer);
        Zoltan_Set_Num_Edges_Multi_Fn(zz, getNullNumEdgesList, gridPointer);
        Zoltan_Set_Edge_List_Multi_Fn(zz, getNullEdgeList, gridPointer);
    }
    else
    {
        CombinedGridWellGraph* graphPointer = const_cast<CombinedGridWellGraph*>(&graph);
        Zoltan_Set_Num_Obj_Fn(zz, getCpGridNumCells, gridPointer);
        Zoltan_Set_Obj_List_Fn(zz, getCpGridVertexList, gridPointer);
        Zoltan_Set_Num_Edges_Multi_Fn(zz, getCpGridWellsNumEdgesList, graphPointer);
        Zoltan_Set_Edge_List_Multi_Fn(zz, getCpGridWellsEdgeList, graphPointer);
    }
}
Esempio n. 3
0
int main(int argc, char *argv[])
{
    int rc, i, ngids, maxcol, ncolors;
    float ver;
    struct Zoltan_Struct *zz=NULL;
#ifdef ZOLTANV31
    int numGidEntries, numLidEntries;
#else
    ZOLTAN_GRAPH_EVAL graph;
#endif
    int *color;
    ZOLTAN_ID_PTR gid_list;
    UZData guz, *uz=&guz;
    int msg_tag = 9999;
    int nlvtx, next, maxdeg=0;
    double times[9]={0.,0.,0.,0.,0.,0.,0.,0.}; /* Used for timing measurements */
    double gtimes[9]={0.,0.,0.,0.,0.,0.,0.,0.}; /* Used for timing measurements */
    
    /******************************************************************
     ** Initialize MPI and Zoltan
     ******************************************************************/

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &uz->myRank);
    MPI_Comm_size(MPI_COMM_WORLD, &uz->numProcs);

    MPI_Barrier(MPI_COMM_WORLD);
    times[0] = u_wseconds();
    
    rc = Zoltan_Initialize(argc, argv, &ver);
    if (rc != ZOLTAN_OK){
        fprintf(stderr, "Sorry Zoltan initialize failed...\n");
        goto End;
    }
    zz = Zoltan_Create(MPI_COMM_WORLD);

    if (argc<3 && !uz->myRank) {
        fprintf(stderr, "usage: %s [meshR] [meshC] [X-point stencil] [procR] [procC] [ws-beta] [<ZoltanParam>=<Val>] ...\n\n", argv[0]);
        fprintf(stderr, "ws-beta: is the probablity of adding an edge to a vertex to generate Watts-Strogatz graphs\n");
        fprintf(stderr, "Valid values for Stencil are 5, 7 and 9\n");
        fprintf(stderr, "Zoltan Coloring Parameters and values are\n");
        fprintf(stderr, "\tDISTANCE        : 1 or 2\n");
        fprintf(stderr, "\tSUPERSTEP_SIZE  : suggested >= 100\n"); 
        fprintf(stderr, "\tCOMM_PATTERN    : S or A\n");
        fprintf(stderr, "\tCOLOR_ORDER     : I, B, U\n");
        fprintf(stderr, "\tCOLORING_METHOD : F (for now)\n");
        fprintf(stderr, "\n");
    }

    uz->procR = uz->procC = 0;
    uz->meshR = uz->meshC = 1024;
    uz->stencil = 9;

    if (argc>1)
        uz->meshR = atoi(argv[1]);
    if (argc>2)
        uz->meshC = atoi(argv[2]);
    if (argc>3)
        uz->stencil = atoi(argv[3]);
    if (uz->stencil!=5 && uz->stencil!=7 && uz->stencil!=9) {
        fprintf(stderr, "\t invalid stencil value. Valid values are 5, 7 and 9. Assumed 9.\n");
        uz->stencil = 9;
    }
    --uz->stencil;

    if (argc>4)
        uz->procR = atoi(argv[4]);
    if (argc>5)
        uz->procC = atoi(argv[5]);
    if (uz->procR <= 0 || uz->procC <= 0)
        computeProcMesh(uz);
    
    if (uz->procR*uz->procC!=uz->numProcs) {
        fprintf(stderr, "#Procs=%d but requested %dx%d Proc Mesh Partitioning...\n", uz->numProcs, uz->procR, uz->procC);
        goto End;
    }

    if (argc>6)
        uz->beta = atof(argv[6]);
    else
        uz->beta = 0.0;
    
    /* compute which part of mesh I will compute */
    uz->myR = uz->myRank / uz->procC;
    uz->myC = uz->myRank % uz->procC;

    uz->_sr = uz->myR * (uz->meshR / uz->procR);
    uz->_er = (uz->myR+1) * (uz->meshR / uz->procR);
    if (uz->_er>uz->meshR)
        uz->_er = uz->meshR;
    uz->_sc = uz->myC * (uz->meshC / uz->procC);
    uz->_ec = (uz->myC+1) * (uz->meshC / uz->procC);
    if (uz->_ec>uz->meshC)
        uz->_ec = uz->meshC;


    if ( (uz->meshR % uz->procR) !=0 || (uz->meshC % uz->procC)!=0) {
        printf("Mesh dimensions are not divisible with proc mesh.\nRequested mesh is %dx%d and proc mesh is %d x %d\n", uz->meshR, uz->meshC, uz->procR, uz->procC);
        exit(1);
    }
    nlvtx= (uz->_er-uz->_sr) * (uz->_ec-uz->_sc);

    if (uz->myRank==0)
        printf("Running %s on %d x %d processor mesh, generating %d-point %d x %d mesh with beta=%.3lf\n", argv[0], uz->procR, uz->procC, uz->stencil+1, uz->meshR, uz->meshC, uz->beta);

    times[1] = u_wseconds();    
    uz->numredge = 0;
    uz->redgeto = NULL;
    if (uz->beta>0) { /* create random edges for WS graph */
        int ngvtx=uz->meshC*uz->meshR, trsh=(int) (uz->beta*100.0);
        int ierr=0;
        int *edges=NULL, *redges=NULL, *proclist=NULL, nedge;
        ZOLTAN_COMM_OBJ *plan;
            
        uz->redgeto = (int *) malloc(nlvtx*sizeof(int));
        for (i=0; i<nlvtx; ++i) {
            int rv = Zoltan_Rand_InRange(NULL, 100);
            if ( rv < trsh) {
                if ((uz->redgeto[i] = Zoltan_Rand_InRange(NULL,  ngvtx))==gIDfLID(i)) /* is it a self edge */
                    uz->redgeto[i] = -1;
                else 
                    ++uz->numredge;
            } else
                uz->redgeto[i] = -1;
        }

        edges = (int *) malloc(sizeof(int)*2*uz->numredge);
        proclist = (int *) malloc(sizeof(int)*uz->numredge);
        next = 0;
        for (i=0; i<nlvtx; ++i)
            if (uz->redgeto[i]>0) {
                edges[2*next] = uz->redgeto[i];
                edges[2*next+1] = gIDfLID(i);
                proclist[next] = pIDfGID(uz->redgeto[i]);
                ++next;
            }

        ierr = Zoltan_Comm_Create(&plan, uz->numredge, proclist, MPI_COMM_WORLD,
                                  msg_tag, &nedge);
        
        redges = (int *) malloc(sizeof(int)*2*nedge);
        
        --msg_tag;
        ierr |= Zoltan_Comm_Do(plan, msg_tag, (char *) edges, 2*sizeof(int),
                               (char *) redges);
        ierr |= Zoltan_Comm_Destroy(&plan);
        free(proclist);
        free(edges);
                
        if (ierr) {
            printf("error while communicating edges!\n");
            exit(1);
        }
        xadj = (int *) calloc(1+nlvtx, sizeof(int));
        adj = (int *) malloc(sizeof(int)*nedge);
        for (i=0; i<nedge; ++i)  {
            if (redges[2*i] < gID(uz->_sr, uz->_sc) || redges[2*i] >= gID(uz->_er, uz->_ec)) {
                printf("[%d/%d] received gid=%d doesn't blong to processor range [%d, %d) should go to proc %d\n", uz->myRank, uz->numProcs, redges[2*i],  gID(uz->_sr, uz->_sc), gID(uz->_er, uz->_ec), pIDfGID(redges[2*i]));
            }
                
            ++xadj[lIDfGID(redges[2*i])];
        }
        xadj[nlvtx] = nedge;
        maxdeg = xadj[0];
        for (i=1; i<nlvtx; ++i) {
            maxdeg = xadj[i]>maxdeg ? xadj[i] : maxdeg;
            xadj[i] += xadj[i-1];
        }
        
        for (i=0; i<nedge; ++i) {
            int u = lIDfGID(redges[2*i]);
            int v = redges[2*i+1];
            adj[--xadj[u]] = v;
        }
        free(redges);                    
    }
    maxdeg += uz->stencil+1;
    adjTemp = (int *) malloc(sizeof(int)*2*maxdeg);
    times[2] = u_wseconds();
    
    /*
      printf("My rank %d/%d at proc-mesh loc (%d, %d) generating [%d, %d) x [%d, %d) + %d random edges TotEdge=%d\n", uz->myRank, uz->numProcs, uz->myR, uz->myC, uz->_sr, uz->_er, uz->_sc, uz->_ec, uz->numredge, xadj[nlvtx]);  */
    printStats("Number of Vertices  ", nlvtx, uz->myRank, uz->numProcs);
    if (xadj)
        printStats("Number of Rand Edges", xadj[nlvtx], uz->myRank, uz->numProcs);

    
    /* General parameters */
#ifndef ZOLTANV31
    Zoltan_Set_Param(zz, "GRAPH_BUILD_TYPE", "FAST_NO_DUP");
#endif

    /* General parameters */
    Zoltan_Set_Param(zz, "DEBUG_LEVEL", "3");
    Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1"); 
    Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
    Zoltan_Set_Param(zz, "OBJ_WEIGHT_DIM", "0");


    /* coloring parameters */
    Zoltan_Set_Param(zz, "SUPERSTEP_SIZE", "500"); /* let's make S=500 default */
    for (i=7; i<argc; ++i) {
        char param[256], *eq;

        if (!uz->myRank)
            printf("processing argv[%d]='%s'\n", i, argv[i]);
        strncpy(param, argv[i], sizeof(param));
        eq = strchr(param, '=');
        if (!eq) {
            fprintf(stderr, "invalid argument '%s', Zoltan Paramters should be in the format <ZoltanParam>=<Val>\n", param);
            goto End;
        }
        *eq = 0;
        Zoltan_Set_Param(zz, param, eq+1);
    }


#if 0    
    /* Graph parameters */
    Zoltan_Set_Param(zz, "CHECK_GRAPH", "2");
#endif

    /* set call backs */
    Zoltan_Set_Num_Obj_Fn(zz, get_number_of_objects, uz);
    Zoltan_Set_Obj_List_Fn(zz, get_object_list, uz);
    Zoltan_Set_Num_Edges_Multi_Fn(zz, get_num_edges_list, uz);
    Zoltan_Set_Edge_List_Multi_Fn(zz, get_edge_list, uz);

#if 0    
#ifndef ZOLTANV31
    Zoltan_LB_Eval_Graph(zz, 0, &graph);

    if (!uz->myRank) {
        printf("EdgeCut   Min=%8.0f  Max=%8.0f  Sum=%8.0f\n", graph.cuts[EVAL_GLOBAL_MIN], graph.cuts[EVAL_GLOBAL_MAX], graph.cuts[EVAL_GLOBAL_SUM]);
        printf("#Vertices Min=%8.0f  Max=%8.0f  Sum=%8.0f imbal=%.2f\n", graph.nobj[EVAL_GLOBAL_MIN], graph.nobj[EVAL_GLOBAL_MAX], graph.nobj[EVAL_GLOBAL_SUM], graph.obj_imbalance);        
    }
#endif
#endif

    /* now color */
    ngids = get_number_of_objects(uz, &rc);

    gid_list = (ZOLTAN_ID_PTR) malloc(sizeof(ZOLTAN_ID_TYPE) * ngids);
#ifndef ZOLTANV31
    next = 0;
    for (i=uz->_sr; i<uz->_er; ++i) {
        int j;
        for (j=uz->_sc; j<uz->_ec; ++j) {
            gid_list[next++] = i*uz->meshC + j;
        }
    }    
#endif
    color = (int *) malloc(sizeof(int) * ngids);    

    MPI_Barrier(MPI_COMM_WORLD);
    times[3] = u_wseconds();    
#ifdef ZOLTANV31
    rc = Zoltan_Color(zz, /* input (all remaining fields are output) */
                      &numGidEntries,  /* Number of integers used for a global ID */
                      &numLidEntries,  /* Number of integers used for a local ID */
                      ngids,           /* #objects to color in this proc */
                      gid_list,        /* global ids of colored vertices */
                      NULL,            /* we ignore local ids */
                      color);          /* result color */    
#else    
    rc = Zoltan_Color(zz, /* input (all remaining fields are output) */
                      1,  /* Number of integers used for a global ID */
                      ngids,           /* #objects to color in this proc */
                      gid_list,        /* global ids of colored vertices */
                      color);          /* result color */
#endif
    MPI_Barrier(MPI_COMM_WORLD);
    times[4] = u_wseconds();
    MPI_Reduce(times, gtimes, 5, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD);


    if (rc != ZOLTAN_OK) 
        fprintf(stderr, "Zoltan_Color failed with return code %d...\n", rc);

    for (maxcol=i=0; i<ngids; ++i)
        if (color[i] > maxcol)
            maxcol = color[i];
    MPI_Reduce(&maxcol, &ncolors, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
    if (uz->myRank==0) {
        struct rusage usage;
                
        printf("%s setup             Proc-0: %8.2lf   Max: %8.2lf\n", argv[0], times[1]-times[0], gtimes[1]-gtimes[0]);
        printf("%s gen rand edges    Proc-0: %8.2lf   Max: %8.2lf\n", argv[0], times[2]-times[1], gtimes[2]-gtimes[1]);
        printf("%s set gids          Proc-0: %8.2lf   Max: %8.2lf\n", argv[0], times[3]-times[2], gtimes[3]-gtimes[2]);
        printf("%s Zoltan_Color call Proc-0: %8.2lf   Max: %8.2lf\n", argv[0], times[4]-times[3], gtimes[4]-gtimes[3]);
        printf("%s Coloring Time    : %.2lf   # Colors used : %d\n", argv[0], gtimes[4]-gtimes[0], ncolors);
        getrusage(RUSAGE_SELF, &usage);
        printf("%s maxrss=%ld minflt=%ld majflt=%ld nswap=%ld\n", argv[0], usage.ru_maxrss, usage.ru_minflt, usage.ru_majflt, usage.ru_nswap);                
    }
    
#ifdef _DEBUG
    saveColor(argv[0], uz, (int *) gid_list, color, ngids);
#endif

    /******************************************************************
     ** Clean up
     ******************************************************************/

    if (gid_list)
        free(gid_list);
    if (color)
        free(color);
    if (xadj)
        free(xadj);
    if (adj)
        free(adj);
    if (adjTemp)
        free(adjTemp);
    if (uz->redgeto)
        free(uz->redgeto);

End:    
    Zoltan_Destroy(&zz);
    MPI_Finalize();

    return 0;
}
Esempio n. 4
0
int main(int argc, char *argv[])
{
  int i, rc;
  float ver;
  struct Zoltan_Struct *zz;
  int changes, numGidEntries, numLidEntries, numImport, numExport;
  int myRank, numProcs;
  ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids, exportLocalGids;
  int *importProcs, *importToPart, *exportProcs, *exportToPart;
  int *parts;
  FILE *fp;
  GRAPH_DATA myGraph;

  /******************************************************************
  ** Initialize MPI and Zoltan
  ******************************************************************/

  MPI_Init(&argc, &argv);
  MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
  MPI_Comm_size(MPI_COMM_WORLD, &numProcs);

  rc = Zoltan_Initialize(argc, argv, &ver);

  if (rc != ZOLTAN_OK){
    printf("sorry...\n");
    MPI_Finalize();
    exit(0);
  }

  /******************************************************************
  ** Read graph from input file and distribute it 
  ******************************************************************/

  fp = fopen(fname, "r");
  if (!fp){
    if (myRank == 0) fprintf(stderr,"ERROR: Can not open %s\n",fname);
    MPI_Finalize();
    exit(1);
  }
  fclose(fp);

  read_input_file(myRank, numProcs, fname, &myGraph);

  /******************************************************************
  ** Create a Zoltan library structure for this instance of load
  ** balancing.  Set the parameters and query functions that will
  ** govern the library's calculation.  See the Zoltan User's
  ** Guide for the definition of these and many other parameters.
  ******************************************************************/

  zz = Zoltan_Create(MPI_COMM_WORLD);

  /* General parameters */

/*
  Zoltan_Set_Param(zz, "DEBUG_LEVEL", "0");
  Zoltan_Set_Param(zz, "LB_METHOD", "GRAPH");
  Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1"); 
  Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
  Zoltan_Set_Param(zz, "OBJ_WEIGHT_DIM", "0");
  Zoltan_Set_Param(zz, "RETURN_LISTS", "ALL");
*/

     Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1"); 
     Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
     Zoltan_Set_Param(zz,"LB_METHOD","GRAPH");
#ifdef HAVE_PARMETIS
     Zoltan_Set_Param(zz,"GRAPH_PACKAGE","PARMETIS");
#else
  #ifdef HAVE_SCOTCH
     Zoltan_Set_Param(zz,"GRAPH_PACKAGE","SCOTCH");
  #endif
#endif
     Zoltan_Set_Param(zz,"EDGE_WEIGHT_DIM","1");
     Zoltan_Set_Param(zz, "OBJ_WEIGHT_DIM", "0");
     Zoltan_Set_Param(zz,"LB_APPROACH","REPARTITION");
     Zoltan_Set_Param(zz,"GRAPH_SYMMETRIZE","TRANSPOSE");
     Zoltan_Set_Param(zz,"GRAPH_SYM_WEIGHT","ADD");

  /* Graph parameters */

  Zoltan_Set_Param(zz, "CHECK_GRAPH", "2"); 
  Zoltan_Set_Param(zz, "PHG_EDGE_SIZE_THRESHOLD", ".35");  /* 0-remove all, 1-remove none */

  /* Query functions - defined in simpleQueries.h */

  Zoltan_Set_Num_Obj_Fn(zz, get_number_of_vertices, &myGraph);
  Zoltan_Set_Obj_List_Fn(zz, get_vertex_list, &myGraph);
  Zoltan_Set_Num_Edges_Multi_Fn(zz, get_num_edges_list, &myGraph);
  Zoltan_Set_Edge_List_Multi_Fn(zz, get_edge_list, &myGraph);

  /******************************************************************
  ** Zoltan can now partition the simple graph.
  ** In this simple example, we assume the number of partitions is
  ** equal to the number of processes.  Process rank 0 will own
  ** partition 0, process rank 1 will own partition 1, and so on.
  ******************************************************************/

  rc = Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
        &changes,        /* 1 if partitioning was changed, 0 otherwise */ 
        &numGidEntries,  /* Number of integers used for a global ID */
        &numLidEntries,  /* Number of integers used for a local ID */
        &numImport,      /* Number of vertices to be sent to me */
        &importGlobalGids,  /* Global IDs of vertices to be sent to me */
        &importLocalGids,   /* Local IDs of vertices to be sent to me */
        &importProcs,    /* Process rank for source of each incoming vertex */
        &importToPart,   /* New partition for each incoming vertex */
        &numExport,      /* Number of vertices I must send to other processes*/
        &exportGlobalGids,  /* Global IDs of the vertices I must send */
        &exportLocalGids,   /* Local IDs of the vertices I must send */
        &exportProcs,    /* Process to which I send each of the vertices */
        &exportToPart);  /* Partition to which each vertex will belong */

  if (rc != ZOLTAN_OK){
    printf("sorry...\n");
    MPI_Finalize();
    Zoltan_Destroy(&zz);
    exit(0);
  }

  /******************************************************************
  ** Visualize the graph partitioning before and after calling Zoltan.
  ******************************************************************/

  parts = (int *)malloc(sizeof(int) * myGraph.numMyVertices);

  for (i=0; i < myGraph.numMyVertices; i++){
    parts[i] = myRank;
  }

  if (myRank== 0){
    printf("\nGraph partition before calling Zoltan\n");
  }

  showGraphPartitions(myRank, myGraph.numMyVertices, myGraph.vertexGID, parts, numProcs);

  for (i=0; i < numExport; i++){
    parts[exportLocalGids[i]] = exportToPart[i];
  }

  if (myRank == 0){
    printf("Graph partition after calling Zoltan\n");
  }

  showGraphPartitions(myRank, myGraph.numMyVertices, myGraph.vertexGID, parts, numProcs);

  free(parts);

  /******************************************************************
  ** Free the arrays allocated by Zoltan_LB_Partition, and free
  ** the storage allocated for the Zoltan structure.
  ******************************************************************/

  Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids, 
                      &importProcs, &importToPart);
  Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids, 
                      &exportProcs, &exportToPart);

  Zoltan_Destroy(&zz);

  /**********************
  ** all done ***********
  **********************/

  MPI_Finalize();

  if (myGraph.numMyVertices > 0){
    free(myGraph.vertexGID);
    free(myGraph.nborIndex);
    if (myGraph.numAllNbors > 0){
      free(myGraph.nborGID);
      free(myGraph.nborProc);
    }
  }

  return 0;
}
Esempio n. 5
0
int Zoltan_Set_Fn(ZZ *zz, ZOLTAN_FN_TYPE fn_type, ZOLTAN_VOID_FN *fn,
  void *data)
{
/*
 *  Function to initialize a given LB interface function.
 *  Input:
 *    zz                --  Pointer to a Zoltan structure.
 *    fn_type           --  Enum type indicating the function to be set.
 *    fn                --  Pointer to the function to be used in the
 *                          assignment.
 *    data              --  Pointer to data that the LB library will
 *                          pass as an argument to fn(). May be NULL.
 *  Output:
 *    zz                --  Appropriate field set to value in void *().
 */

char *yo = "Zoltan_Set_Fn";
char msg[256];
int ierr;

  switch (fn_type) {
  case ZOLTAN_PART_FN_TYPE:
    ierr = Zoltan_Set_Part_Fn(zz, 
                  (ZOLTAN_PART_FN *) fn, data);
    break;
  case ZOLTAN_PART_MULTI_FN_TYPE:
    ierr = Zoltan_Set_Part_Multi_Fn(zz, 
                  (ZOLTAN_PART_MULTI_FN *) fn, data);
    break;
  case ZOLTAN_NUM_EDGES_FN_TYPE:
    ierr = Zoltan_Set_Num_Edges_Fn(zz, 
                  (ZOLTAN_NUM_EDGES_FN *) fn, data);
    break;
  case ZOLTAN_NUM_EDGES_MULTI_FN_TYPE:
    ierr = Zoltan_Set_Num_Edges_Multi_Fn(zz, 
                  (ZOLTAN_NUM_EDGES_MULTI_FN *) fn, data);
    break;
  case ZOLTAN_EDGE_LIST_FN_TYPE:
    ierr = Zoltan_Set_Edge_List_Fn(zz, 
                  (ZOLTAN_EDGE_LIST_FN *) fn, data);
    break;
  case ZOLTAN_EDGE_LIST_MULTI_FN_TYPE:
    ierr = Zoltan_Set_Edge_List_Multi_Fn(zz, 
                  (ZOLTAN_EDGE_LIST_MULTI_FN *) fn, data);
    break;
  case ZOLTAN_NUM_GEOM_FN_TYPE:
    ierr = Zoltan_Set_Num_Geom_Fn(zz, 
                  (ZOLTAN_NUM_GEOM_FN *) fn, data);
    break;
  case ZOLTAN_GEOM_MULTI_FN_TYPE:
    ierr = Zoltan_Set_Geom_Multi_Fn(zz, 
                  (ZOLTAN_GEOM_MULTI_FN *) fn, data);
    break;
  case ZOLTAN_GEOM_FN_TYPE:
    ierr = Zoltan_Set_Geom_Fn(zz, 
                  (ZOLTAN_GEOM_FN *) fn, data);
    break;
  case ZOLTAN_NUM_OBJ_FN_TYPE:
    ierr = Zoltan_Set_Num_Obj_Fn(zz, 
                  (ZOLTAN_NUM_OBJ_FN *) fn, data);
    break;
  case ZOLTAN_OBJ_LIST_FN_TYPE:
    ierr = Zoltan_Set_Obj_List_Fn(zz, 
                  (ZOLTAN_OBJ_LIST_FN *) fn, data);
    break;
  case ZOLTAN_FIRST_OBJ_FN_TYPE:
    ierr = Zoltan_Set_First_Obj_Fn(zz, 
                  (ZOLTAN_FIRST_OBJ_FN *) fn, data);
    break;
  case ZOLTAN_NEXT_OBJ_FN_TYPE:
    ierr = Zoltan_Set_Next_Obj_Fn(zz, 
                  (ZOLTAN_NEXT_OBJ_FN *) fn, data);
    break;
  case ZOLTAN_NUM_BORDER_OBJ_FN_TYPE:
    ierr = Zoltan_Set_Num_Border_Obj_Fn(zz, 
                  (ZOLTAN_NUM_BORDER_OBJ_FN *) fn, data);
    break;
  case ZOLTAN_BORDER_OBJ_LIST_FN_TYPE:
    ierr = Zoltan_Set_Border_Obj_List_Fn(zz, 
                  (ZOLTAN_BORDER_OBJ_LIST_FN *) fn, data);
    break;
  case ZOLTAN_FIRST_BORDER_OBJ_FN_TYPE:
    ierr = Zoltan_Set_First_Border_Obj_Fn(zz, 
                  (ZOLTAN_FIRST_BORDER_OBJ_FN *) fn, data);
    break;
  case ZOLTAN_NEXT_BORDER_OBJ_FN_TYPE:
    ierr = Zoltan_Set_Next_Border_Obj_Fn(zz, 
                  (ZOLTAN_NEXT_BORDER_OBJ_FN *) fn, data);
    break;
  case ZOLTAN_PRE_MIGRATE_PP_FN_TYPE:
    ierr = Zoltan_Set_Pre_Migrate_PP_Fn(zz, 
                  (ZOLTAN_PRE_MIGRATE_PP_FN *) fn, data);
    break;
  case ZOLTAN_MID_MIGRATE_PP_FN_TYPE:
    ierr = Zoltan_Set_Mid_Migrate_PP_Fn(zz, 
                  (ZOLTAN_MID_MIGRATE_PP_FN *) fn, data);
    break;
  case ZOLTAN_POST_MIGRATE_PP_FN_TYPE:
    ierr = Zoltan_Set_Post_Migrate_PP_Fn(zz, 
                  (ZOLTAN_POST_MIGRATE_PP_FN *) fn, data);
    break;
  case ZOLTAN_PRE_MIGRATE_FN_TYPE:
    ierr = Zoltan_Set_Pre_Migrate_Fn(zz, 
                  (ZOLTAN_PRE_MIGRATE_FN *) fn, data);
    break;
  case ZOLTAN_MID_MIGRATE_FN_TYPE:
    ierr = Zoltan_Set_Mid_Migrate_Fn(zz, 
                  (ZOLTAN_MID_MIGRATE_FN *) fn, data);
    break;
  case ZOLTAN_POST_MIGRATE_FN_TYPE:
    ierr = Zoltan_Set_Post_Migrate_Fn(zz, 
                  (ZOLTAN_POST_MIGRATE_FN *) fn, data);
    break;
  case ZOLTAN_OBJ_SIZE_FN_TYPE:
    ierr = Zoltan_Set_Obj_Size_Fn(zz, 
                  (ZOLTAN_OBJ_SIZE_FN *) fn, data);
    break;
  case ZOLTAN_OBJ_SIZE_MULTI_FN_TYPE:
    ierr = Zoltan_Set_Obj_Size_Multi_Fn(zz, 
                  (ZOLTAN_OBJ_SIZE_MULTI_FN *) fn, data);
    break;
  case ZOLTAN_PACK_OBJ_FN_TYPE:
    ierr = Zoltan_Set_Pack_Obj_Fn(zz, 
                  (ZOLTAN_PACK_OBJ_FN *) fn, data);
    break;
  case ZOLTAN_PACK_OBJ_MULTI_FN_TYPE:
    ierr = Zoltan_Set_Pack_Obj_Multi_Fn(zz, 
                  (ZOLTAN_PACK_OBJ_MULTI_FN *) fn, data);
    break;
  case ZOLTAN_UNPACK_OBJ_FN_TYPE:
    ierr = Zoltan_Set_Unpack_Obj_Fn(zz, 
                  (ZOLTAN_UNPACK_OBJ_FN *) fn, data);
    break;
  case ZOLTAN_UNPACK_OBJ_MULTI_FN_TYPE:
    ierr = Zoltan_Set_Unpack_Obj_Multi_Fn(zz, 
                  (ZOLTAN_UNPACK_OBJ_MULTI_FN *) fn, data);
    break;
  case ZOLTAN_NUM_COARSE_OBJ_FN_TYPE:
    ierr = Zoltan_Set_Num_Coarse_Obj_Fn(zz, 
                  (ZOLTAN_NUM_COARSE_OBJ_FN *) fn, data);
    break;
  case ZOLTAN_COARSE_OBJ_LIST_FN_TYPE:
    ierr = Zoltan_Set_Coarse_Obj_List_Fn(zz, 
                  (ZOLTAN_COARSE_OBJ_LIST_FN *) fn, data);
    break;
  case ZOLTAN_FIRST_COARSE_OBJ_FN_TYPE:
    ierr = Zoltan_Set_First_Coarse_Obj_Fn(zz, 
                  (ZOLTAN_FIRST_COARSE_OBJ_FN *) fn, data);
    break;
  case ZOLTAN_NEXT_COARSE_OBJ_FN_TYPE:
    ierr = Zoltan_Set_Next_Coarse_Obj_Fn(zz, 
                  (ZOLTAN_NEXT_COARSE_OBJ_FN *) fn, data);
    break;
  case ZOLTAN_NUM_CHILD_FN_TYPE:
    ierr = Zoltan_Set_Num_Child_Fn(zz, 
                  (ZOLTAN_NUM_CHILD_FN *) fn, data);
    break;
  case ZOLTAN_CHILD_LIST_FN_TYPE:
    ierr = Zoltan_Set_Child_List_Fn(zz, 
                  (ZOLTAN_CHILD_LIST_FN *) fn, data);
    break;
  case ZOLTAN_CHILD_WEIGHT_FN_TYPE:
    ierr = Zoltan_Set_Child_Weight_Fn(zz, 
                  (ZOLTAN_CHILD_WEIGHT_FN *) fn, data);
    break;
  case ZOLTAN_HG_SIZE_CS_FN_TYPE:
    ierr = Zoltan_Set_HG_Size_CS_Fn(zz, 
                  (ZOLTAN_HG_SIZE_CS_FN *) fn, data);
    break;
  case ZOLTAN_HG_CS_FN_TYPE:
    ierr = Zoltan_Set_HG_CS_Fn(zz, 
                  (ZOLTAN_HG_CS_FN *) fn, data);
    break;
  case ZOLTAN_HG_SIZE_EDGE_WTS_FN_TYPE:
    ierr = Zoltan_Set_HG_Size_Edge_Wts_Fn(zz, 
                  (ZOLTAN_HG_SIZE_EDGE_WTS_FN *) fn, data);
    break;
  case ZOLTAN_HG_EDGE_WTS_FN_TYPE:
    ierr = Zoltan_Set_HG_Edge_Wts_Fn(zz, 
                  (ZOLTAN_HG_EDGE_WTS_FN *) fn, data);
    break;
  case ZOLTAN_NUM_FIXED_OBJ_FN_TYPE:
    ierr = Zoltan_Set_Num_Fixed_Obj_Fn(zz, 
                  (ZOLTAN_NUM_FIXED_OBJ_FN *) fn, data);
    break;
  case ZOLTAN_FIXED_OBJ_LIST_FN_TYPE:
    ierr = Zoltan_Set_Fixed_Obj_List_Fn(zz, 
                  (ZOLTAN_FIXED_OBJ_LIST_FN *) fn, data);
    break;
  case ZOLTAN_HIER_NUM_LEVELS_FN_TYPE:
    ierr = Zoltan_Set_Hier_Num_Levels_Fn(zz,
		  (ZOLTAN_HIER_NUM_LEVELS_FN *) fn, data);
    break;
  case ZOLTAN_HIER_PART_FN_TYPE:
    ierr = Zoltan_Set_Hier_Part_Fn(zz,
		  (ZOLTAN_HIER_PART_FN *) fn, data);
    break;
  case ZOLTAN_HIER_METHOD_FN_TYPE:
    ierr = Zoltan_Set_Hier_Method_Fn(zz,
		  (ZOLTAN_HIER_METHOD_FN *) fn, data);
    break;
  default:
    sprintf(msg, "ZOLTAN_FN_TYPE %d is invalid.\n"
            "Value must be in range 0 to %d.", fn_type, ZOLTAN_MAX_FN_TYPES);
    ZOLTAN_PRINT_ERROR(zz->Proc, yo, msg);
    ierr = ZOLTAN_WARN;
  }

  return (ierr);
}
Esempio n. 6
0
int main(int argc, char *argv[])
{
  int i, rc;
  int myRank, numProcs;
  float ver;
  struct Zoltan_Struct *zz;
  int changes, numGidEntries, numLidEntries, numImport, numExport, start_gid, num_nbors;
  ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids, exportLocalGids;
  int *importProcs, *importToPart, *exportProcs, *exportToPart;
  int *parts=NULL;
  ZOLTAN_ID_PTR lids=NULL;
  FILE *fp;
  struct Zoltan_DD_Struct *dd;
  GRAPH_DATA myGraph;
  int gid_length = 1;   /* our global IDs consist of 1 integer */
  int lid_length = 1;   /* our local IDs consist of 1 integer */

  /******************************************************************
  ** Initialize MPI and Zoltan
  ******************************************************************/

  MPI_Init(&argc, &argv);
  MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
  MPI_Comm_size(MPI_COMM_WORLD, &numProcs);

  rc = Zoltan_Initialize(argc, argv, &ver);

  if (rc != ZOLTAN_OK){
    printf("sorry...\n");
    MPI_Finalize();
    exit(0);
  }

  /******************************************************************
  ** Read graph from input file and distribute it 
  ******************************************************************/

  fp = fopen(fname, "r");
  if (!fp){
    if (myRank == 0) fprintf(stderr,"ERROR: Can not open %s\n",fname);
    MPI_Finalize();
    exit(1);
  }
  fclose(fp);

  read_input_file(myRank, numProcs, fname, &myGraph);

  /*fprintf(stderr,"%d have %d objects\n",myRank,myGraph.numMyVertices);*/

  /******************************************************************
  ** Create a distributed data directory which maps vertex
  ** global IDs to their current partition number.  We'll use this
  ** after migrating vertices, to update the partition in which
  ** our vertices neighbors are.
  **
  ** Our local IDs (array "lids") are of type ZOLTAN_ID_TYPE because
  ** we are using Zoltan's distributed data directory.  It assumes
  ** that a global ID is a sequence of "gid_length" ZOLTAN_ID_TYPEs.
  ** It assumes that a local ID is a sequence of "lid_length"
  ** ZOLTAN_ID_TYPEs.
  ******************************************************************/

  rc = Zoltan_DD_Create(&dd, MPI_COMM_WORLD, 
                           gid_length,    /* length of a global ID */
                           lid_length,    /* length of a local ID */
                           0,             /* length of user data  */
                           myGraph.numMyVertices,  /* hash table size */
                           0);                     /* debug level */

  parts = malloc(myGraph.numMyVertices * sizeof(int));
  lids = malloc(myGraph.numMyVertices * sizeof(ZOLTAN_ID_TYPE));
  
  for (i=0; i < myGraph.numMyVertices; i++){
    parts[i] = myRank;   /* part number of this vertex */
    lids[i] = (ZOLTAN_ID_TYPE)i;         /* local ID on my process for this vertex */
  }
  
  rc = Zoltan_DD_Update(dd, 
                        myGraph.vertexGID, 
                        lids,
                        NULL,
                        parts,
                        myGraph.numMyVertices);
  

  myGraph.dd = dd;

  /******************************************************************
  ** Create a Zoltan library structure for this instance of load
  ** balancing.  Set the parameters and query functions that will
  ** govern the library's calculation.  See the Zoltan User's
  ** Guide for the definition of these and many other parameters.
  ******************************************************************/

  zz = Zoltan_Create(MPI_COMM_WORLD);

  /* General parameters */

  Zoltan_Set_Param(zz, "DEBUG_LEVEL", "0");
  Zoltan_Set_Param(zz, "LB_METHOD", "GRAPH");
  Zoltan_Set_Param(zz, "LB_APPROACH", "PARTITION");
  Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1"); 
  Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
  Zoltan_Set_Param(zz, "RETURN_LISTS", "ALL");

  /* Graph parameters */

  Zoltan_Set_Param(zz, "CHECK_GRAPH", "2"); 
  Zoltan_Set_Param(zz, "PHG_EDGE_SIZE_THRESHOLD", ".35");  /* 0-remove all, 1-remove none */

  /* Query functions, defined in this source file */

  Zoltan_Set_Num_Obj_Fn(zz, get_number_of_vertices, &myGraph);
  Zoltan_Set_Obj_List_Fn(zz, get_vertex_list, &myGraph);
  Zoltan_Set_Num_Edges_Multi_Fn(zz, get_num_edges_list, &myGraph);
  Zoltan_Set_Edge_List_Multi_Fn(zz, get_edge_list, &myGraph);

  Zoltan_Set_Obj_Size_Multi_Fn(zz, get_message_sizes,&myGraph);
  Zoltan_Set_Pack_Obj_Multi_Fn(zz, pack_object_messages,&myGraph);
  Zoltan_Set_Unpack_Obj_Multi_Fn(zz, unpack_object_messages,&myGraph);
  Zoltan_Set_Mid_Migrate_PP_Fn(zz, mid_migrate,&myGraph);

  /******************************************************************
  ** Visualize the graph partitioning before calling Zoltan.
  ******************************************************************/

  if (myRank== 0){
    printf("\nGraph partition before calling Zoltan\n");
  }

  showGraphPartitions(myRank, myGraph.dd);

  /******************************************************************
  ** Zoltan can now partition the simple graph.
  ** In this simple example, we assume the number of partitions is
  ** equal to the number of processes.  Process rank 0 will own
  ** partition 0, process rank 1 will own partition 1, and so on.
  ******************************************************************/

  rc = Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
        &changes,        /* 1 if partitioning was changed, 0 otherwise */ 
        &numGidEntries,  /* Number of integers used for a global ID */
        &numLidEntries,  /* Number of integers used for a local ID */
        &numImport,      /* Number of vertices to be sent to me */
        &importGlobalGids,  /* Global IDs of vertices to be sent to me */
        &importLocalGids,   /* Local IDs of vertices to be sent to me */
        &importProcs,    /* Process rank for source of each incoming vertex */
        &importToPart,   /* New partition for each incoming vertex */
        &numExport,      /* Number of vertices I must send to other processes*/
        &exportGlobalGids,  /* Global IDs of the vertices I must send */
        &exportLocalGids,   /* Local IDs of the vertices I must send */
        &exportProcs,    /* Process to which I send each of the vertices */
        &exportToPart);  /* Partition to which each vertex will belong */

  if (rc != ZOLTAN_OK){
    printf("sorry...\n");
    MPI_Finalize();
    Zoltan_Destroy(&zz);
    exit(0);
  }

  /*fprintf(stderr,"%d export %d import %d\n",myRank,numExport,numImport);*/

  /******************************************************************
  ** Update the data directory with the new partition numbers
  ******************************************************************/

  for (i=0; i < numExport; i++){
    parts[exportLocalGids[i]] = exportToPart[i];
  }

  rc = Zoltan_DD_Update(dd, 
                        myGraph.vertexGID, 
                        lids,
                        NULL,
                        parts,
                        myGraph.numMyVertices);

  /******************************************************************
  ** Migrate vertices to new partitions
  ******************************************************************/

  rc = Zoltan_Migrate(zz, 
                      numImport, importGlobalGids, importLocalGids,
                      importProcs, importToPart,
                      numExport, exportGlobalGids, exportLocalGids,
                      exportProcs, exportToPart);


  /******************************************************************
  ** Use the data dictionary to find neighbors' partitions
  ******************************************************************/

  start_gid = myGraph.numMyVertices - numImport;
  num_nbors = myGraph.nborIndex[myGraph.numMyVertices] - myGraph.nborIndex[start_gid];

  rc = Zoltan_DD_Find(dd,
             (ZOLTAN_ID_PTR)(myGraph.nborGID + start_gid), NULL, NULL, 
              myGraph.nborPart + start_gid, num_nbors, NULL);

  /******************************************************************
  ** Visualize the graph partitioning after calling Zoltan.
  ******************************************************************/

  if (myRank == 0){
    printf("Graph partition after calling Zoltan\n");
  }
  showGraphPartitions(myRank, myGraph.dd);

  /******************************************************************
  ** Free the arrays allocated by Zoltan_LB_Partition, and free
  ** the storage allocated for the Zoltan structure.
  ******************************************************************/

  Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids, 
                      &importProcs, &importToPart);
  Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids, 
                      &exportProcs, &exportToPart);

  Zoltan_Destroy(&zz);

  /**********************
  ** all done ***********
  **********************/

  MPI_Finalize();

  if (myGraph.vertex_capacity > 0){
    free(myGraph.vertexGID);
    free(myGraph.nborIndex);
    if (myGraph.nbor_capacity > 0){
      free(myGraph.nborGID);
      free(myGraph.nborPart);
    }
  }

  if (parts) free(parts);
  if (lids) free(lids);

  return 0;
}
Esempio n. 7
0
  int MESH_PartitionWithZoltan(Mesh_ptr mesh, int nparts, int **part, int noptions, 
                               char **options, MSTK_Comm comm) { 

  MEdge_ptr fedge;
  MFace_ptr mf, oppf, rface;
  MRegion_ptr mr, oppr;
  List_ptr fedges, efaces, rfaces, fregions;
  int  i, j, k, id;
  int  nv, ne, nf, nr=0, nfe, nef, nfr, nrf, idx, idx2;
  int  numflag, nedgecut, ipos;
  int  wtflag;

  int rc;
  float ver;
  struct Zoltan_Struct *zz;
  GRAPH_DATA graph;
  int changes, numGidEntries, numLidEntries, numImport, numExport;
  ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids, exportLocalGids;
  int *importProcs, *importToPart, *exportProcs, *exportToPart;

  int rank;
  MPI_Comm_rank(comm,&rank);
 
  rc = Zoltan_Initialize(0, NULL, &ver);

  if (rc != ZOLTAN_OK){
    MSTK_Report("MESH_PartitionWithZoltan","Could not initialize Zoltan",MSTK_FATAL);
    MPI_Finalize();
    exit(0);
  }

  /******************************************************************
  ** Create a Zoltan library structure for this instance of partition 
  ********************************************************************/
  zz = Zoltan_Create(comm);

  /*****************************************************************
   ** Figure out partitioning method
   *****************************************************************/
  
  char partition_method_str[32];
  strcpy(partition_method_str,"RCB");  /* Default - Recursive Coordinate Bisection */
  if (noptions) {
    for (i = 0; i < noptions; i++) {
      if (strncmp(options[i],"LB_PARTITION",12) == 0) {
        char *result = NULL, instring[256];
        strcpy(instring,options[i]);
        result = strtok(instring,"=");
        result = strtok(NULL," ");
        strcpy(partition_method_str,result);
      }
    }
  }
  
  if (rank == 0) {
    char mesg[256];
    sprintf(mesg,"Using partitioning method %s for ZOLTAN\n",partition_method_str);
    MSTK_Report("MESH_PartitionWithZoltan",mesg,MSTK_MESG);
  }

  /* General parameters for Zoltan */
  Zoltan_Set_Param(zz, "DEBUG_LEVEL", "0");
  Zoltan_Set_Param(zz, "LB_METHOD", partition_method_str);
  Zoltan_Set_Param(zz, "LB_APPROACH", "PARTITION");
  Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");
  Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
  Zoltan_Set_Param(zz, "RETURN_LISTS", "ALL");


  graph.numMyNodes = 0;
  graph.numAllNbors = 0;
  graph.nodeGID = NULL;
  graph.nodeCoords = NULL;
  graph.nborIndex = NULL;
  graph.nborGID = NULL;
  graph.nborProc = NULL;

  if (strcmp(partition_method_str,"RCB") == 0) {
    if (rank == 0) {
      nr = MESH_Num_Regions(mesh);
      nf = MESH_Num_Faces(mesh);

      if (!nf && !nr)
        MSTK_Report("MESH_PartitionWithZoltan","Cannot partition wire meshes",
                    MSTK_FATAL);

      if (nr == 0) { /* Surface or planar mesh */

        int ndim = 2;       /* assume mesh is planar */
        idx = 0;
        MVertex_ptr mv;
        while ((mv = MESH_Next_Vertex(mesh,&idx))) {
          double vxyz[3];
          MV_Coords(mv,vxyz);
          if (vxyz[2] != 0.0) {
            ndim = 3;  /* non-planar or planar with non-zero z */
            break;
          }
        }
        NDIM_4_ZOLTAN = ndim-1;  /* ignore last dimension to avoid partitioning in that dimension */

        graph.numMyNodes = nf;

        graph.nodeGID = (ZOLTAN_ID_TYPE *) malloc(sizeof(ZOLTAN_ID_TYPE) * nf);
        graph.nodeCoords = (double *) malloc(sizeof(double) * NDIM_4_ZOLTAN * nf);

        idx = 0;
        while ((mf = MESH_Next_Face(mesh,&idx))) {
          double fxyz[MAXPV2][3], cen[3];
          int nfv;

          MF_Coords(mf,&nfv,fxyz);
          cen[0] = cen[1] = cen[2] = 0.0;
          for (j = 0; j < nfv; j++)
            for (k = 0; k < NDIM_4_ZOLTAN; k++) 
              cen[k] += fxyz[j][k];              
          for (k = 0; k < NDIM_4_ZOLTAN; k++) cen[k] /= nfv;

          id = MF_ID(mf);
          graph.nodeGID[id-1] = id;
          memcpy(&(graph.nodeCoords[NDIM_4_ZOLTAN*(id-1)]),cen,NDIM_4_ZOLTAN*sizeof(double));
        }

      }
      else { /* Volume mesh */

        int ndim = 3;
        NDIM_4_ZOLTAN = ndim-1;  /* ignore last dimension  to avoid partitioning in that dimension */
        graph.numMyNodes = nr;

        graph.nodeGID = (ZOLTAN_ID_TYPE *) malloc(sizeof(ZOLTAN_ID_TYPE) * nr);
        graph.nodeCoords = (double *) malloc(sizeof(double) * NDIM_4_ZOLTAN * nr);

        idx = 0;
        while ((mr = MESH_Next_Region(mesh,&idx))) {
          double rxyz[MAXPV3][3], cen[3];
          int nrv;
          
          MR_Coords(mr,&nrv,rxyz);
          cen[0] = cen[1] = cen[2] = 0.0;
          for (j = 0; j < nrv; j++)
            for (k = 0; k < NDIM_4_ZOLTAN; k++)
              cen[k] += rxyz[j][k];
          for (k = 0; k < NDIM_4_ZOLTAN; k++) cen[k] /= nrv;
          for (k = 0; k < NDIM_4_ZOLTAN; k++) 
            if (fabs(cen[k]) < 1.0e-10) cen[k] = 0.0; 

          id = MR_ID(mr);
          graph.nodeGID[id-1] = id;
          memcpy(&(graph.nodeCoords[NDIM_4_ZOLTAN*(id-1)]),cen,NDIM_4_ZOLTAN*sizeof(double));
        }

      }
    }

    MPI_Bcast(&NDIM_4_ZOLTAN,1,MPI_INT,0,comm);

    /* Set some default values */
    Zoltan_Set_Param(zz, "RCB_RECTILINEAR_BLOCKS","1");
    //    Zoltan_Set_Param(zz, "AVERAGE_CUTS", "1");

    if (noptions > 1) {
      for (i = 1; i < noptions; i++) {
        char *paramstr = NULL, *valuestr = NULL, instring[256];
        strcpy(instring,options[i]);
        paramstr = strtok(instring,"=");
        valuestr = strtok(NULL," ");
        Zoltan_Set_Param(zz,paramstr,valuestr);
      }
    }

    /* Query functions - defined in simpleQueries.h */

    Zoltan_Set_Num_Obj_Fn(zz, get_number_of_nodes, &graph);
    Zoltan_Set_Obj_List_Fn(zz, get_node_list, &graph);
    Zoltan_Set_Num_Geom_Fn(zz, get_num_dimensions_reduced, &graph);    /* reduced dimensions */
    Zoltan_Set_Geom_Multi_Fn(zz, get_element_centers_reduced, &graph); /* reduced dimension centers */

  }
  else if (strcmp(partition_method_str,"GRAPH") == 0) {

    if(rank == 0) {
      nv = MESH_Num_Vertices(mesh);
      ne = MESH_Num_Edges(mesh);
      nf = MESH_Num_Faces(mesh);
      nr = MESH_Num_Regions(mesh);
      
      ipos = 0;
      
      /* build nodes and neighbors list, similar as in partition with metis
         Assign processor 0 the whole mesh, assign other processors a NULL mesh */
  
      if (nr == 0) {
        if (nf == 0) {
          MSTK_Report("MESH_PartitionWithZoltan",
                      "Cannot partition wire meshes with Zoltan",MSTK_FATAL);
          exit(-1);
      
        }

        graph.nodeGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * nf);
        graph.nborIndex = (int *)malloc(sizeof(int) * (nf + 1));
        graph.nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * 2*ne);
        graph.nborProc = (int *)malloc(sizeof(int) * 2*ne);
      
        graph.nborIndex[0] = 0;
      
        /* Surface mesh */
        idx = 0; i = 0;
        while ((mf = MESH_Next_Face(mesh,&idx))) {
          graph.nodeGID[i] = MF_ID(mf);
          fedges = MF_Edges(mf,1,0);
          nfe = List_Num_Entries(fedges);
	
          idx2 = 0;
          while ((fedge = List_Next_Entry(fedges,&idx2))) {
	  
            efaces = ME_Faces(fedge);
            nef = List_Num_Entries(efaces);
	  
            if (nef == 1) {
              continue;          /* boundary edge; nothing to do */
            } else {
              int j;
              for (j = 0; j < nef; j++) {
                oppf = List_Entry(efaces,j);
                if (oppf == mf) {
                  graph.nborGID[ipos] = MF_ID(oppf);
                  /* initially set all nodes on processor 0 */
                  graph.nborProc[ipos] = 0;
                  ipos++;
                }
              }
            }
	  
            List_Delete(efaces);
	  
          }
	
          List_Delete(fedges);
          i++;
          graph.nborIndex[i] = ipos;
        }
        graph.numMyNodes = i;
        graph.numAllNbors = ipos;
      }
      else {
        graph.nodeGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * nr);
        graph.nborIndex = (int *)malloc(sizeof(int) * (nr + 1));
        graph.nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * 2*nf);
        graph.nborProc = (int *)malloc(sizeof(int) * 2*nf);
      
        graph.nborIndex[0] = 0;
      
        /* Volume mesh */
      
        idx = 0; i = 0;
        while ((mr = MESH_Next_Region(mesh,&idx))) {
          graph.nodeGID[i] = MR_ID(mr);
          rfaces = MR_Faces(mr);
          nrf = List_Num_Entries(rfaces);
      
          idx2 = 0;
          while ((rface = List_Next_Entry(rfaces,&idx2))) {
	  
            fregions = MF_Regions(rface);
            nfr = List_Num_Entries(fregions);
	  
            if (nfr > 1) {
              oppr = List_Entry(fregions,0);
              if (oppr == mr)
                oppr = List_Entry(fregions,1);
	    
              graph.nborGID[ipos] = MR_ID(oppr);
              /* initially set all nodes on processor 0 */
              graph.nborProc[ipos] = 0;
              ipos++;
            }
	  
            List_Delete(fregions);
	  
          }
	
          List_Delete(rfaces);
	
          i++;
          graph.nborIndex[i] = ipos;
        }
        graph.numMyNodes = i;
        graph.numAllNbors = ipos;
      }
    }

    /* Graph parameters */

    /* Zoltan_Set_Param(zz, "CHECK_GRAPH", "2"); */
    Zoltan_Set_Param(zz, "PHG_EDGE_SIZE_THRESHOLD", ".35");  /* 0-remove all, 1-remove none */

    /* Query functions - defined in simpleQueries.h */

    Zoltan_Set_Num_Obj_Fn(zz, get_number_of_nodes, &graph);
    Zoltan_Set_Obj_List_Fn(zz, get_node_list, &graph);
    Zoltan_Set_Num_Edges_Multi_Fn(zz, get_num_edges_list, &graph);
    Zoltan_Set_Edge_List_Multi_Fn(zz, get_edge_list, &graph);    
  }

  /* Partition the graph */
  /******************************************************************                                                                             
   ** Zoltan can now partition the graph.                                                                                                   
   ** We assume the number of partitions is                                                                                
   ** equal to the number of processes.  Process rank 0 will own                                                                                   
   ** partition 0, process rank 1 will own partition 1, and so on.                                                                                 
   ******************************************************************/
  rc = Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
			   &changes,        /* 1 if partitioning was changed, 0 otherwise */
			   &numGidEntries,  /* Number of integers used for a global ID */
			   &numLidEntries,  /* Number of integers used for a local ID */
			   &numImport,      /* Number of nodes to be sent to me */
			   &importGlobalGids,  /* Global IDs of nodes to be sent to me */
			   &importLocalGids,   /* Local IDs of nodes to be sent to me */
			   &importProcs,    /* Process rank for source of each incoming node */
			   &importToPart,   /* New partition for each incoming node */
			   &numExport,      /* Number of nodes I must send to other processes*/
			   &exportGlobalGids,  /* Global IDs of the nodes I must send */
			   &exportLocalGids,   /* Local IDs of the nodes I must send */
			   &exportProcs,    /* Process to which I send each of the nodes */
			   &exportToPart);  /* Partition to which each node will belong */

  if (rc != ZOLTAN_OK){
    if (rank == 0)
      MSTK_Report("MESH_PartitionWithZoltan","Could not partition mesh with ZOLTAN",
                  MSTK_ERROR);
    Zoltan_Destroy(&zz);
    MPI_Finalize();
    return 0;
  }

  if(rank == 0) {
    *part = (int *) calloc(graph.numMyNodes,sizeof(int));
    for ( i = 0; i < numExport; i++ ) {
      (*part)[exportGlobalGids[i]-1] = exportToPart[i];
    }
    if (graph.nodeGID) free(graph.nodeGID);
    if (graph.nodeCoords) free(graph.nodeCoords);
    if (graph.nborIndex) free(graph.nborIndex);
    if (graph.nborGID) free(graph.nborGID);
    if (graph.nborProc) free(graph.nborProc);
  }
  else { 
    *part = NULL;
  }


  Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids, &exportProcs, &exportToPart);
  Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids, &importProcs, &importToPart);
  Zoltan_Destroy(&zz);                

  return 1;
}
Esempio n. 8
0
int main(int argc, char *argv[])
{
  int rc, do_hier, status;
  float ver;
  struct Zoltan_Struct *zz;
  int changes, numGidEntries, numLidEntries, numImport, numExport;
  int generate_files = 0;
  char *platform=NULL, *topology=NULL;
  char *graph_package=NULL;
  ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids, exportLocalGids;
  int *importProcs, *importToPart, *exportProcs, *exportToPart;
  struct option opts[10];
  double comm_time[10];
  float cut_weight[3] = {0., 0., 0.};
  long nvert=0;
  char *debug_level=NULL;

  status = 0;

  MPI_Init(&argc, &argv);
  MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
  MPI_Comm_size(MPI_COMM_WORLD, &numProcs);

  Zoltan_Initialize(argc, argv, &ver);
  zz = Zoltan_Create(MPI_COMM_WORLD);

  /******************************************************************
  ** Check that this test makes sense.
  ******************************************************************/

  if (sizeof(long) < sizeof(ZOLTAN_ID_TYPE)){
    if (myRank == 0){
      printf("ERROR: This code assumes that a long is at least %d bytes\n",(int)sizeof(ZOLTAN_ID_TYPE));
    }
    status = 1;
  }

  check_error_status(status, "configuration error");

  /******************************************************************
  ** Initialize zoltan
  ******************************************************************/

  /* options */

  opts[0].name = "platform";
  opts[0].has_arg = 1;
  opts[0].flag = NULL;
  opts[0].val = 1;

  opts[1].name = "topology";
  opts[1].has_arg = 1;
  opts[1].flag = NULL;
  opts[1].val = 2;

  opts[2].name = "size";
  opts[2].has_arg = 1;
  opts[2].flag = NULL;
  opts[2].val = 4;

  opts[3].name = "verbose";
  opts[3].has_arg = 0;
  opts[3].flag = NULL;
  opts[3].val = 5;

  opts[4].name = "help";
  opts[4].has_arg = 0;
  opts[4].flag = NULL;
  opts[4].val = 6;

  opts[5].name = "graph_package";
  opts[5].has_arg = 1;
  opts[5].flag = NULL;
  opts[5].val = 7;

  opts[6].name = "generate_files";
  opts[6].has_arg = 0;
  opts[6].flag = NULL;
  opts[6].val = 8;

  opts[7].name = "debug_level";
  opts[7].has_arg = 1;
  opts[7].flag = NULL;
  opts[7].val = 9;

  opts[8].name = 0;
  opts[8].has_arg = 0;
  opts[8].flag = NULL;
  opts[8].val = 0;

  status = 0;

  while (1){
    rc = getopt_long_only(argc, argv, "",  opts, NULL);

    if (rc == '?'){
      MPI_Barrier(MPI_COMM_WORLD);
      if (myRank == 0) usage();
      MPI_Finalize();
      exit(0);
    }
    else if (rc == 1){
      platform = optarg;
      if (myRank == 0)
        printf( "For platform %s\n",optarg );
    }
    else if (rc == 2){
      topology = optarg;
      if (myRank == 0)
        printf( "For topology %s\n",optarg);
    }
    else if (rc == 7){
      graph_package = optarg;
      if (myRank == 0)
        printf( "Zoltan parameter GRAPH_PACKAGE = %s\n",graph_package);
    }
    else if (rc == 8){
      generate_files = 1;
      if (myRank == 0)
        printf( "Zoltan_Generate_Files will be called for each level.\n");
    }
    else if (rc == 4){
      nvert = atol(optarg);
      if (nvert < 1) status = 1;
      check_error_status(status, "--size={approximate number of vertices}");
      if (myRank == 0){
        printf( "Graph will have approximately %ld vertices.\n",nvert);
      }
    }
    else if (rc == 5){
      verbose = 1;
    }
    else if (rc == 6){
      if (myRank == 0) usage();
      MPI_Finalize();
      exit(0);
    }
    else if (rc == 9){
      debug_level = optarg;
    }
    else if (rc <= 0){
      break;
    }
  }

  if ((platform==NULL) && (topology==NULL)){
    if (myRank == 0)
      fprintf(stdout,"No platform or topology, so we'll skip hierarchical partitioning\n");
    do_hier = 0;
  }
  else if (graph_package == NULL){
    if (myRank == 0)
      fprintf(stdout,"No graph package, so we'll skip hierarchical partitioning\n");
    do_hier = 0;
  }
  else{
    do_hier = 1;
  }

  /* start */

  Zoltan_Memory_Debug(0);

  if (nvert > 0)
    numGlobalVertices = nvert;
  else
    numGlobalVertices = NUM_GLOBAL_VERTICES;

  status = create_a_graph();
  check_error_status(status, "creating the graph");

  Zoltan_Set_Param(zz, "DEBUG_LEVEL", "0");
  Zoltan_Set_Param(zz, "REMAP", "0");
  Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");
  Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
  Zoltan_Set_Param(zz, "RETURN_LISTS", "ALL"); /* export AND import lists */
  Zoltan_Set_Param(zz, "OBJ_WEIGHT_DIM", "1"); /* number of weights per vertex */
  Zoltan_Set_Param(zz, "EDGE_WEIGHT_DIM", "1");/* number of weights per hyperedge */

  Zoltan_Set_Num_Obj_Fn(zz, get_number_of_vertices, NULL);
  Zoltan_Set_Obj_List_Fn(zz, get_vertex_list, NULL);
  Zoltan_Set_Num_Edges_Multi_Fn(zz, get_num_edges_list,  NULL);
  Zoltan_Set_Edge_List_Multi_Fn(zz, get_edge_list,  NULL);

  /* GRAPH PARTITION */

  Zoltan_Set_Param(zz, "LB_METHOD", "GRAPH");
  Zoltan_Set_Param(zz, "LB_APPROACH", "PARTITION");

  if (graph_package)
    Zoltan_Set_Param(zz, "GRAPH_PACKAGE", graph_package);

  if (verbose){
    debug(zz, "Initial graph", 0);
  }

  if (generate_files){
    rc = Zoltan_Generate_Files(zz, "flat", myRank, 0, 1, 0);
    if (rc != ZOLTAN_OK) status = 1;
    check_error_status(status, "Zoltan_Generate_Files");
  }

  /* Performance before partitioning */
  time_communication(comm_time+0);
  cut_weight[0] = get_edge_cut_weight(zz);

  if (cut_weight[0] < 0.0) status = 1;
  check_error_status(status, "First call to get_edge_cut_weight");

  rc = Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
        &changes,        /* 1 if partitioning was changed, 0 otherwise */
        &numGidEntries,  /* Number of integers used for a global ID */
        &numLidEntries,  /* Number of integers used for a local ID */
        &numImport,      /* Number of vertices to be sent to me */
        &importGlobalGids,  /* Global IDs of vertices to be sent to me */
        &importLocalGids,   /* Local IDs of vertices to be sent to me */
        &importProcs,    /* Process rank for source of each incoming vertex */
        &importToPart,   /* New partition for each incoming vertex */
        &numExport,      /* Number of vertices I must send to other processes*/
        &exportGlobalGids,  /* Global IDs of the vertices I must send */
        &exportLocalGids,   /* Local IDs of the vertices I must send */
        &exportProcs,    /* Process to which I send each of the vertices */
        &exportToPart);  /* Partition to which each vertex will belong */

  if (rc != ZOLTAN_OK) status = 1;
  check_error_status(status, "First call to LB_Partition");

  status = migrate_graph(numExport, numImport, exportLocalGids, importGlobalGids);
  check_error_status(status, "migration");

  if (verbose){
    debug(zz, "After flat partitioning and migration", 0);
  }

  time_communication(comm_time+1);      /* With graph partitioning */
  cut_weight[1] = get_edge_cut_weight(zz);

  if (cut_weight[1] < 0.0) status = 1;
  check_error_status(status, "Second call to get_edge_cut_weight");

  Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids,
                      &importProcs, &importToPart);
  Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids,
                      &exportProcs, &exportToPart);

  if (do_hier){

    /* HIERARCHICAL PARTITION */

    free_graph();
    status = create_a_graph();
    check_error_status(status, "create graph for hierarchical partitioning");

    Zoltan_Set_Param(zz, "LB_METHOD", "HIER");
    Zoltan_Set_Param(zz, "HIER_ASSIST", "1");
    if (generate_files){
      Zoltan_Set_Param(zz, "HIER_GENERATE_FILES", "1");
    }

    if (debug_level)   /* 1, 2 or 3 */
      Zoltan_Set_Param(zz, "HIER_DEBUG_LEVEL", debug_level);
    else
      Zoltan_Set_Param(zz, "HIER_DEBUG_LEVEL", "0");

    /* TODO: Suppose graph is not symmetric, and we request SYMMETRIZE.  Do we still get
     *  a "good" answer when each sub-graph in the hierarchy is symmetrized?
     */

    if (topology)
      Zoltan_Set_Param(zz, "TOPOLOGY", topology);
    else if (platform)
      Zoltan_Set_Param(zz, "PLATFORM", platform);

    rc = Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
          &changes,        /* 1 if partitioning was changed, 0 otherwise */
          &numGidEntries,  /* Number of integers used for a global ID */
          &numLidEntries,  /* Number of integers used for a local ID */
          &numImport,      /* Number of vertices to be sent to me */
          &importGlobalGids,  /* Global IDs of vertices to be sent to me */
          &importLocalGids,   /* Local IDs of vertices to be sent to me */
          &importProcs,    /* Process rank for source of each incoming vertex */
          &importToPart,   /* New partition for each incoming vertex */
          &numExport,      /* Number of vertices I must send to other processes*/
          &exportGlobalGids,  /* Global IDs of the vertices I must send */
          &exportLocalGids,   /* Local IDs of the vertices I must send */
          &exportProcs,    /* Process to which I send each of the vertices */
          &exportToPart);  /* Partition to which each vertex will belong */

    if (rc != ZOLTAN_OK) status = 1;
    check_error_status(status, "Second call to LB_Partition");

    status = migrate_graph(numExport, numImport, exportLocalGids, importGlobalGids);
    check_error_status(status, "second migration");

    if (verbose){
      debug(zz, "After hierarchical partitioning and migration", 0);
    }

    time_communication(comm_time+2);      /* With hierarchical graph partitioning */
    cut_weight[2] = get_edge_cut_weight(zz);

    if (cut_weight[2] < 0.0) status = 1;
    check_error_status(status, "Third call to get_edge_cut_weight");

    Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids,
                        &importProcs, &importToPart);
    Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids,
                        &exportProcs, &exportToPart);
  }

  Zoltan_Destroy(&zz);

  free_graph();

  if (myRank == 0){
    fprintf(stdout,"Graph cut weight before partitioning: %f\n",cut_weight[0]);
    fprintf(stdout,"             after flat partitioning: %f\n",cut_weight[1]);
    if (do_hier)
      fprintf(stdout,"     after hierarchical partitioning: %f\n",cut_weight[2]);
    fflush(stdout);
  }

  if (cut_weight[1] >= cut_weight[0]){
    status = 1;
    if (zz->Proc == 0){
      fprintf(stderr,"FAILED: No improvement shown in flat partitioning");
    }
  }

  if (do_hier && (cut_weight[2] > cut_weight[0])){
    status = 1;
    if (zz->Proc == 0){
      fprintf(stderr,"FAILED: No improvement shown in hierarchical partitioning");
    }
  }


  MPI_Finalize();

  return status;
}