Cloned SEACAS for EXODUS library with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

871 lines
25 KiB

2 years ago
/*
* @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
*/
/**************************************************************
* Basic example of using Zoltan to partition a hypergraph.
*
* We think a hypergraph as a matrix, where the hyperedges are
* the rows, and the vertices are the columns. If (i,j) is
* non-zero, this indicates that vertex j is in hyperedge i.
*
* In some Zoltan documentation, the non-zeroes in hypergraph
* matrices are called "pins".
*
***************************************************************/
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "zoltan.h"
/* Name of file containing hypergraph to be partitioned */
static char *global_fname="hypergraph.txt";
/* Structure to hold distributed hypergraph */
typedef struct{
/* Zoltan will partition vertices, while minimizing edge cuts */
int numGlobalVertices; /* number of vertices in global hypergraph */
int numMyVertices; /* number of vertices that I own initially */
ZOLTAN_ID_TYPE *vtxGID; /* global ID of these vertices */
int numGlobalEdges; /* number of edges in global hypergraph */
int numMyHEdges; /* number of my hyperedges */
int numAllNbors; /* number of vertices in my hyperedges */
ZOLTAN_ID_TYPE *edgeGID; /* global ID of each of my hyperedges */
int *nborIndex; /* index into nborGID array of edge's vertices */
ZOLTAN_ID_TYPE *nborGID; /* Vertices of edge edgeGID[i] begin at nborGID[nborIndex[i]] */
} HGRAPH_DATA;
/* 4 application defined query functions. If we were going to define
* a weight for each hyperedge, we would need to define 2 more query functions.
*/
static int get_number_of_vertices(void *data, int *ierr);
static void get_vertex_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr);
static void get_hypergraph_size(void *data, int *num_lists, int *num_nonzeroes,
int *format, int *ierr);
static void get_hypergraph(void *data, int sizeGID, int num_edges, int num_nonzeroes,
int format, ZOLTAN_ID_PTR edgeGID, int *vtxPtr,
ZOLTAN_ID_PTR vtxGID, int *ierr);
/* Functions to read hypergraph in from file, distribute it, view it, handle errors */
static int get_next_line(FILE *fp, char *buf, int bufsize);
static int get_line_ints(char *buf, int bufsize, int *vals);
static void input_file_error(int numProcs, int tag, int startProc);
static void showHypergraph(int myProc, int numProc, int numIDs, ZOLTAN_ID_TYPE *GIDs, int *parts);
static void read_input_file(int myRank, int numProcs, char *fname, HGRAPH_DATA *data);
static HGRAPH_DATA global_hg;
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;
HGRAPH_DATA hg;
/******************************************************************
** 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 hypergraph from input file and distribute it
******************************************************************/
fp = fopen(global_fname, "r");
if (!fp){
if (myRank == 0) fprintf(stderr,"ERROR: Can not open %s\n",global_fname);
MPI_Finalize();
exit(1);
}
fclose(fp);
read_input_file(myRank, numProcs, global_fname, &hg);
/******************************************************************
** 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", "HYPERGRAPH"); /* partitioning method */
Zoltan_Set_Param(zz, "HYPERGRAPH_PACKAGE", "PHG"); /* version of method */
Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");/* global IDs are integers */
Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");/* local IDs are integers */
Zoltan_Set_Param(zz, "RETURN_LISTS", "ALL"); /* export AND import lists */
Zoltan_Set_Param(zz, "OBJ_WEIGHT_DIM", "0"); /* use Zoltan default vertex weights */
Zoltan_Set_Param(zz, "EDGE_WEIGHT_DIM", "0");/* use Zoltan default hyperedge weights */
/* PHG parameters - see the Zoltan User's Guide for many more
* (The "REPARTITION" approach asks Zoltan to create a partitioning that is
* better but is not too far from the current partitioning, rather than partitioning
* from scratch. It may be faster but of lower quality that LB_APPROACH=PARTITION.)
*/
Zoltan_Set_Param(zz, "LB_APPROACH", "REPARTITION");
/* Application defined query functions */
Zoltan_Set_Num_Obj_Fn(zz, get_number_of_vertices, &hg);
Zoltan_Set_Obj_List_Fn(zz, get_vertex_list, &hg);
Zoltan_Set_HG_Size_CS_Fn(zz, get_hypergraph_size, &hg);
Zoltan_Set_HG_CS_Fn(zz, get_hypergraph, &hg);
/******************************************************************
** Zoltan can now partition the vertices of hypergraph.
** 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 hypergraph partitioning before and after calling Zoltan.
******************************************************************/
parts = (int *)malloc(sizeof(int) * hg.numMyVertices);
for (i=0; i < hg.numMyVertices; i++){
parts[i] = myRank;
}
if (myRank== 0){
printf("\nHypergraph partition before calling Zoltan\n");
}
showHypergraph(myRank, numProcs, hg.numMyVertices, hg.vtxGID, parts);
for (i=0; i < numExport; i++){
parts[exportLocalGids[i]] = exportToPart[i];
}
if (myRank == 0){
printf("Graph partition after calling Zoltan\n");
}
showHypergraph(myRank, numProcs, hg.numMyVertices, hg.vtxGID, 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 (hg.numMyVertices > 0){
free(parts);
free(hg.vtxGID);
}
if (hg.numMyHEdges > 0){
free(hg.edgeGID);
free(hg.nborIndex);
if (hg.numAllNbors > 0){
free(hg.nborGID);
}
}
return 0;
}
/* Application defined query functions */
static int get_number_of_vertices(void *data, int *ierr)
{
HGRAPH_DATA *hg = (HGRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
return hg->numMyVertices;
}
static void get_vertex_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr)
{
int i;
HGRAPH_DATA *hg= (HGRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
/* In this example, return the IDs of our vertices, but no weights.
* Zoltan will assume equally weighted vertices.
*/
for (i=0; i<hg->numMyVertices; i++){
globalID[i] = hg->vtxGID[i];
localID[i] = i;
}
}
static void get_hypergraph_size(void *data, int *num_lists, int *num_nonzeroes,
int *format, int *ierr)
{
HGRAPH_DATA *hg = (HGRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
*num_lists = hg->numMyHEdges;
*num_nonzeroes = hg->numAllNbors;
/* We will provide compressed hyperedge (row) format. The alternative is
* is compressed vertex (column) format: ZOLTAN_COMPRESSED_VERTEX.
*/
*format = ZOLTAN_COMPRESSED_EDGE;
return;
}
static void get_hypergraph(void *data, int sizeGID, int num_edges, int num_nonzeroes,
int format, ZOLTAN_ID_PTR edgeGID, int *vtxPtr,
ZOLTAN_ID_PTR vtxGID, int *ierr)
{
int i;
HGRAPH_DATA *hg = (HGRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
if ( (num_edges != hg->numMyHEdges) || (num_nonzeroes != hg->numAllNbors) ||
(format != ZOLTAN_COMPRESSED_EDGE)) {
*ierr = ZOLTAN_FATAL;
return;
}
for (i=0; i < num_edges; i++){
edgeGID[i] = hg->edgeGID[i];
vtxPtr[i] = hg->nborIndex[i];
}
for (i=0; i < num_nonzeroes; i++){
vtxGID[i] = hg->nborGID[i];
}
return;
}
/* Function to find next line of information in input file */
static int get_next_line(FILE *fp, char *buf, int bufsize)
{
int i, cval, len;
char *c;
while (1){
c = fgets(buf, bufsize, fp);
if (c == NULL)
return 0; /* end of file */
len = strlen(c);
for (i=0, c=buf; i < len; i++, c++){
cval = (int)*c;
if (isspace(cval) == 0) break;
}
if (i == len) continue; /* blank line */
if (*c == '#') continue; /* comment */
if (c != buf){
strcpy(buf, c);
}
break;
}
return strlen(buf); /* number of characters */
}
/* Function to return the list of non-negative integers in a line */
static int get_line_ints(char *buf, int bufsize, int *vals)
{
char *c = buf;
int count=0;
while (1){
while (!(isdigit(*c))){
if ((c - buf) >= bufsize) break;
c++;
}
if ( (c-buf) >= bufsize) break;
vals[count++] = atoi(c);
while (isdigit(*c)){
if ((c - buf) >= bufsize) break;
c++;
}
if ( (c-buf) >= bufsize) break;
}
return count;
}
/* Proc 0 notifies others of error and exits */
static void input_file_error(int numProcs, int tag, int startProc)
{
int i, val[3];
val[0] = -1; /* error flag */
fprintf(stderr,"ERROR in input file.\n");
for (i=startProc; i < numProcs; i++){
/* these procs have posted a receive for "tag" expecting counts */
MPI_Send(val, 3, MPI_INT, i, tag, MPI_COMM_WORLD);
}
for (i=1; i < startProc; i++){
/* these procs are done and waiting for ok-to-go */
MPI_Send(val, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
MPI_Finalize();
exit(1);
}
/* Draw the partition assignments of the objects */
static void showHypergraph(int myProc, int numProcs, int numIDs, ZOLTAN_ID_TYPE *GIDs, int *parts)
{
int *partAssign, *allPartAssign;
int i, j, part, count, numVtx, numEdges;
int edgeIdx, vtxIdx;
int maxPart, nPart, partIdx;
int **M;
int *partNums, *partCount;
ZOLTAN_ID_TYPE *nextID;
ZOLTAN_ID_TYPE edgeID, vtxID;
int cutn, cutl;
float imbal, localImbal;
numVtx = global_hg.numGlobalVertices;
numEdges = global_hg.numGlobalEdges;
partAssign = (int *)calloc(sizeof(int), numVtx);
allPartAssign = (int *)calloc(sizeof(int), numVtx);
for (i=0; i < numIDs; i++){
partAssign[GIDs[i]-1] = parts[i];
}
MPI_Reduce(partAssign, allPartAssign, numVtx, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
free(partAssign);
if (myProc > 0){
free(allPartAssign);
return;
}
/* Creating a dense matrix containing hyperedges, because this is small
* example problem, and it is simpler.
*/
M = (int **)calloc(sizeof(int *) , numEdges);
for (i=0; i < numEdges; i++){
M[i] = (int *)calloc(sizeof(int) , numVtx);
}
nextID = global_hg.nborGID;
maxPart = 0;
for (i=0; i < numEdges; i++){
edgeID = global_hg.edgeGID[i];
edgeIdx = (int)edgeID - 1;
count = global_hg.nborIndex[i+1] - global_hg.nborIndex[i];
for (j=0; j < count; j++){
vtxID = *nextID++;
vtxIdx = (int)vtxID - 1;
part = allPartAssign[vtxIdx];
if (part > maxPart) maxPart = part;
M[edgeIdx][vtxIdx] = part+1;
}
}
/* Calculate vertex balance measure 1.0 is perfect, higher is worse */
imbal = 0;
partCount = (int *)calloc(sizeof(int), maxPart+1);
for (i=0; i < numVtx; i++){
partCount[allPartAssign[i]]++;
}
imbal = 0.0;
for (part=0; part <= maxPart; part++){
localImbal = (float)(numProcs * partCount[part]) / (float)numVtx;
if (localImbal > imbal) imbal = localImbal;
}
free(partCount);
free(allPartAssign);
/* Print the hypergraph as a matrix */
printf("\n VERTICES\n ");
for (j=0; j < numVtx; j++){
if (j < 9)
printf("%d ",j+1);
else
printf("%d ",j+1);
}
printf(" NPARTS-1");
printf("\n ");
for (j=0; j < numVtx; j++){
printf("---");
}
printf("\n");
partNums = (int *)calloc(sizeof(int), maxPart + 1);
cutn = 0;
cutl = 0;
for (i=0; i < numEdges; i++){
nPart = 0;
if (i < 9)
printf("%d ",i+1);
else
printf("%d ",i+1);
for (j=0; j < numVtx; j++){
part = M[i][j];
partIdx = part - 1;
if (part > 0){
printf("%d ",partIdx);
if (partNums[partIdx] < i+1){
nPart++;
partNums[partIdx] = i+1;
}
}
else{
printf(" ");
}
}
if (nPart >= 2){
printf(" %d\n",nPart - 1);
cutn++;
cutl += (nPart - 1);
}
else{
printf("\n");
}
}
printf("Total number of cut edges: %d\n",cutn);
printf("Sum of NPARTS-1: %d\n",cutl);
printf("Balance of vertices across partitions: %f\n",imbal);
printf("\n");
for (i=0; i < numEdges; i++){
free(M[i]);
}
free(M);
free(partNums);
}
/*
* Read the hypergraph in the input file and distribute the non-zeroes. (See the
* matrix analogy at the top of the source file.)
*
* We will distribute the hyperedges (rows) to the processes. However, we could
* distribute the vertices (columns), or we could distribute the non-zeroes
* instead.
*
* Zoltan partitions the vertices, so we also create an initial partitioning of the vertices.
*/
void read_input_file(int myRank, int numProcs, char *fname, HGRAPH_DATA *hg)
{
char buf[512];
int bufsize;
int numGlobalVertices, numGlobalEdges, numGlobalNZ;
int num, count, nnbors, ack=0;
int to=-1, from, remaining;
int vGID;
int i, j;
int vals[128], send_count[3];
ZOLTAN_ID_TYPE *idx;
unsigned int id;
FILE *fp;
MPI_Status status;
int ack_tag = 5, count_tag = 10, id_tag = 15;
HGRAPH_DATA *send_hg;
if (myRank == 0){
bufsize = 512;
fp = fopen(fname, "r");
/* Get the number of vertices */
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &numGlobalVertices);
if (num != 1) input_file_error(numProcs, count_tag, 1);
global_hg.numGlobalVertices = numGlobalVertices;
global_hg.numMyVertices = numGlobalVertices;
global_hg.vtxGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * numGlobalVertices);
/* Get the vertex global IDs */
for (i=0; i < numGlobalVertices; i++){
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &vGID);
if (num != 1) input_file_error(numProcs, count_tag, 1);
global_hg.vtxGID[i] = (ZOLTAN_ID_TYPE)vGID;
}
/* Get the number hyperedges which contain those vertices */
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &numGlobalEdges);
if (num != 1) input_file_error(numProcs, count_tag, 1);
global_hg.numGlobalEdges = numGlobalEdges;
global_hg.numMyHEdges = numGlobalEdges;
global_hg.edgeGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * numGlobalEdges);
global_hg.nborIndex = (int *)malloc(sizeof(int) * (numGlobalEdges + 1));
/* Get the total number of vertices or neighbors in all the hyperedges of
* the hypergraph. Or get the number of non-zeroes in the matrix representing
* the hypergraph.
*/
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &numGlobalNZ);
if (num != 1) input_file_error(numProcs, count_tag, 1);
global_hg.nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * numGlobalNZ);
/* Get the list of vertices in each hyperedge */
global_hg.nborIndex[0] = 0;
for (i=0; i < numGlobalEdges; i++){
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = get_line_ints(buf, bufsize, vals);
if (num < 2) input_file_error(numProcs, count_tag, 1);
id = vals[0];
nnbors = vals[1];
if (num < (nnbors + 2)) input_file_error(numProcs, count_tag, 1);
global_hg.edgeGID[i] = (ZOLTAN_ID_TYPE)id;
for (j=0; j < nnbors; j++){
global_hg.nborGID[global_hg.nborIndex[i] + j] = (ZOLTAN_ID_TYPE)vals[2 + j];
}
global_hg.nborIndex[i+1] = global_hg.nborIndex[i] + nnbors;
}
fclose(fp);
/* Create a sub graph for each process */
send_hg = (HGRAPH_DATA *)calloc(sizeof(HGRAPH_DATA) , numProcs);
/*
* Divide the vertices across the processes
*/
remaining = numGlobalVertices;
count = (numGlobalVertices / numProcs) + 1;
idx = global_hg.vtxGID;
for (i=0; i < numProcs; i++){
if (remaining == 0) count = 0;
if (count > remaining) count = remaining;
send_hg[i].numMyVertices = count;
if (count){
send_hg[i].vtxGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * count);
for (j=0; j < count; j++){
send_hg[i].vtxGID[j] = *idx++;
}
}
remaining -= count;
}
/*
* Assign hyperedges to processes, and create a sub-hypergraph for each process.
*/
remaining = numGlobalEdges;
count = (numGlobalEdges / numProcs) + 1;
from = 0;
for (i=0; i < numProcs; i++){
if (remaining == 0) count = 0;
if (count > remaining) count = remaining;
send_hg[i].numMyHEdges = count;
send_hg[i].numAllNbors = 0;
if (count > 0){
to = from + count;
nnbors = global_hg.nborIndex[to] - global_hg.nborIndex[from];
send_hg[i].numAllNbors = nnbors;
send_hg[i].edgeGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * count);
memcpy(send_hg[i].edgeGID, global_hg.edgeGID + from, sizeof(ZOLTAN_ID_TYPE) * count);
send_hg[i].nborIndex = (int *)malloc(sizeof(int) * (count + 1));
send_hg[i].nborIndex[0] = 0;
if (nnbors > 0){
num = global_hg.nborIndex[from];
for (j=1; j <= count; j++){
send_hg[i].nborIndex[j] = global_hg.nborIndex[from+j] - num;
}
send_hg[i].nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * nnbors);
memcpy(send_hg[i].nborGID,
global_hg.nborGID + global_hg.nborIndex[from],
sizeof(ZOLTAN_ID_TYPE) * nnbors);
}
}
remaining -= count;
from = to;
}
/* Send each process its hyperedges and the vertices in its partition */
*hg = send_hg[0];
for (i=1; i < numProcs; i++){
send_count[0] = send_hg[i].numMyVertices;
send_count[1] = send_hg[i].numMyHEdges;
send_count[2] = send_hg[i].numAllNbors;
MPI_Send(send_count, 3, MPI_INT, i, count_tag, MPI_COMM_WORLD);
MPI_Recv(&ack, 1, MPI_INT, i, ack_tag, MPI_COMM_WORLD, &status);
if (send_count[0] > 0){
MPI_Send(send_hg[i].vtxGID, send_count[0], ZOLTAN_ID_MPI_TYPE, i, id_tag, MPI_COMM_WORLD);
free(send_hg[i].vtxGID);
}
if (send_count[1] > 0){
MPI_Send(send_hg[i].edgeGID, send_count[1], ZOLTAN_ID_MPI_TYPE, i, id_tag + 1, MPI_COMM_WORLD);
free(send_hg[i].edgeGID);
MPI_Send(send_hg[i].nborIndex, send_count[1] + 1, MPI_INT, i, id_tag + 2, MPI_COMM_WORLD);
free(send_hg[i].nborIndex);
if (send_count[2] > 0){
MPI_Send(send_hg[i].nborGID, send_count[2], ZOLTAN_ID_MPI_TYPE, i, id_tag + 3, MPI_COMM_WORLD);
free(send_hg[i].nborGID);
}
}
}
free(send_hg);
/* signal all procs it is OK to go on */
ack = 0;
for (i=1; i < numProcs; i++){
MPI_Send(&ack, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
}
else{
MPI_Recv(send_count, 3, MPI_INT, 0, count_tag, MPI_COMM_WORLD, &status);
if (send_count[0] < 0){
MPI_Finalize();
exit(1);
}
ack = 0;
memset(hg, 0, sizeof(HGRAPH_DATA));
hg->numMyVertices = send_count[0];
hg->numMyHEdges = send_count[1];
hg->numAllNbors = send_count[2];
if (send_count[0] > 0){
hg->vtxGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * send_count[0]);
}
if (send_count[1] > 0){
hg->edgeGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * send_count[1]);
hg->nborIndex = (int *)malloc(sizeof(int) * (send_count[1] + 1));
if (send_count[2] > 0){
hg->nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * send_count[2]);
}
}
MPI_Send(&ack, 1, MPI_INT, 0, ack_tag, MPI_COMM_WORLD);
if (send_count[0] > 0){
MPI_Recv(hg->vtxGID,send_count[0], ZOLTAN_ID_MPI_TYPE, 0, id_tag, MPI_COMM_WORLD, &status);
if (send_count[1] > 0){
MPI_Recv(hg->edgeGID,send_count[1], ZOLTAN_ID_MPI_TYPE, 0, id_tag + 1, MPI_COMM_WORLD, &status);
MPI_Recv(hg->nborIndex,send_count[1] + 1, MPI_INT, 0, id_tag + 2, MPI_COMM_WORLD, &status);
if (send_count[2] > 0){
MPI_Recv(hg->nborGID,send_count[2], ZOLTAN_ID_MPI_TYPE, 0, id_tag + 3, MPI_COMM_WORLD, &status);
}
}
}
/* ok to go on? */
MPI_Recv(&ack, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
if (ack < 0){
MPI_Finalize();
exit(1);
}
}
MPI_Bcast(&(global_hg.numGlobalVertices), 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(&(global_hg.numGlobalEdges), 1, MPI_INT, 0, MPI_COMM_WORLD);
}