mirror of
https://github.com/PhasicFlow/phasicFlow.git
synced 2025-06-12 16:26:23 +00:00
Zoltan is added as thirdParty package
This commit is contained in:
542
thirdParty/Zoltan/example/CPP/exampleBLOCK.cpp
vendored
Normal file
542
thirdParty/Zoltan/example/CPP/exampleBLOCK.cpp
vendored
Normal file
@ -0,0 +1,542 @@
|
||||
/*
|
||||
* @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 C++ example of using Zoltan to compute a quick partitioning
|
||||
// of a set of objects.
|
||||
//
|
||||
|
||||
#ifdef MPICPP
|
||||
#undef MPICPP
|
||||
#endif /* MPICPP */
|
||||
|
||||
//#define MPICPP // Uncomment to use C++ interface for MPI.
|
||||
|
||||
#include <mpi.h>
|
||||
#include <stdio.h>
|
||||
#include <zoltan_cpp.h>
|
||||
|
||||
// Class representing collection of objects to be partitioned.
|
||||
|
||||
class objectCollection {
|
||||
|
||||
private:
|
||||
|
||||
int numGlobalObjects;
|
||||
int numMyObjects;
|
||||
int *myGlobalIDs;
|
||||
|
||||
public:
|
||||
|
||||
// constructor
|
||||
|
||||
objectCollection():numGlobalObjects(0), numMyObjects(0), myGlobalIDs(NULL){}
|
||||
|
||||
// destructor
|
||||
|
||||
~objectCollection(){ if (myGlobalIDs) delete [] myGlobalIDs;}
|
||||
|
||||
void set_num_global_objects(int n) {numGlobalObjects = n;}
|
||||
int get_num_global_objects() {return numGlobalObjects;}
|
||||
|
||||
void set_num_my_objects(int n) {numMyObjects = n;}
|
||||
int get_num_my_objects() {return numMyObjects;}
|
||||
|
||||
void set_my_global_ids(int *p) {myGlobalIDs = p;}
|
||||
int *get_my_global_ids() {return myGlobalIDs;}
|
||||
|
||||
// query functions that respond to requests from Zoltan
|
||||
|
||||
static int get_number_of_objects(void *data, int *ierr){
|
||||
|
||||
objectCollection *objs = (objectCollection *)data;
|
||||
*ierr = ZOLTAN_OK;
|
||||
|
||||
return objs->numMyObjects;
|
||||
}
|
||||
|
||||
static void get_object_list(void *data, int sizeGID, int sizeLID,
|
||||
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
|
||||
int wgt_dim, float *obj_wgts, int *ierr){
|
||||
|
||||
objectCollection *objs = (objectCollection *)data;
|
||||
*ierr = ZOLTAN_OK;
|
||||
|
||||
// In this example, return the IDs of our objects, but no weights.
|
||||
// Zoltan will assume equally weighted objects.
|
||||
|
||||
for (int i=0; i<objs->get_num_my_objects(); i++){
|
||||
globalID[i] = objs->get_my_global_ids()[i];
|
||||
localID[i] = i;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static const char *global_fname="objects.txt"; // File containing objects to be partitioned.
|
||||
|
||||
static int get_next_line(FILE *fp, char *buf, int bufsize);
|
||||
static void input_file_error(int numProcs, int tag, int startProc);
|
||||
static void showSimpleMeshPartitions(int myProc, int numIDs, int *GIDs, int *parts);
|
||||
static void read_input_objects(int myRank, int numProcs, const char *fname, objectCollection &myData);
|
||||
|
||||
static void MPIExit()
|
||||
{
|
||||
#ifdef MPICPP
|
||||
MPI::Finalize();
|
||||
#else
|
||||
MPI_Finalize();
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/////////////////////////////////
|
||||
// Initialize MPI and Zoltan
|
||||
/////////////////////////////////
|
||||
|
||||
int rank, size;
|
||||
float version;
|
||||
|
||||
#ifdef MPICPP
|
||||
MPI::Init(argc, argv);
|
||||
rank = MPI::COMM_WORLD.Get_rank();
|
||||
size = MPI::COMM_WORLD.Get_size();
|
||||
#else
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &size);
|
||||
#endif
|
||||
|
||||
Zoltan_Initialize(argc, argv, &version);
|
||||
|
||||
/////////////////////////////////
|
||||
// Create a Zoltan object
|
||||
/////////////////////////////////
|
||||
|
||||
#ifdef MPICPP
|
||||
Zoltan *zz = new Zoltan(MPI::COMM_WORLD);
|
||||
#else
|
||||
Zoltan *zz = new Zoltan(MPI_COMM_WORLD);
|
||||
#endif
|
||||
|
||||
if (zz == NULL){
|
||||
MPIExit();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Read objects from input file and distribute them unevenly
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
FILE *fp = fopen(global_fname, "r");
|
||||
if (!fp){
|
||||
if (rank == 0) fprintf(stderr,"ERROR: Can not open %s\n",global_fname);
|
||||
MPIExit();
|
||||
exit(1);
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
objectCollection objects;
|
||||
|
||||
read_input_objects(rank, size, global_fname, objects);
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Set the Zoltan parameters, and the names of the query functions
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
// General parameters
|
||||
|
||||
zz->Set_Param( "LB_METHOD", "BLOCK"); /* Zoltan method: "BLOCK" */
|
||||
zz->Set_Param( "NUM_GID_ENTRIES", "1"); /* global ID is 1 integer */
|
||||
zz->Set_Param( "NUM_LID_ENTRIES", "1"); /* local ID is 1 integer */
|
||||
zz->Set_Param( "OBJ_WEIGHT_DIM", "0"); /* we omit object weights */
|
||||
|
||||
// Query functions
|
||||
|
||||
zz->Set_Num_Obj_Fn(objectCollection::get_number_of_objects, &objects);
|
||||
zz->Set_Obj_List_Fn(objectCollection::get_object_list, &objects);
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Zoltan can now partition the objects in this collection.
|
||||
// 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.
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
int changes;
|
||||
int numGidEntries;
|
||||
int numLidEntries;
|
||||
int numImport;
|
||||
ZOLTAN_ID_PTR importGlobalIds;
|
||||
ZOLTAN_ID_PTR importLocalIds;
|
||||
int *importProcs;
|
||||
int *importToPart;
|
||||
int numExport;
|
||||
ZOLTAN_ID_PTR exportGlobalIds;
|
||||
ZOLTAN_ID_PTR exportLocalIds;
|
||||
int *exportProcs;
|
||||
int *exportToPart;
|
||||
|
||||
int rc = zz->LB_Partition(changes, numGidEntries, numLidEntries,
|
||||
numImport, importGlobalIds, importLocalIds, importProcs, importToPart,
|
||||
numExport, exportGlobalIds, exportLocalIds, exportProcs, exportToPart);
|
||||
|
||||
if (rc != ZOLTAN_OK){
|
||||
printf("Partitioning failed on process %d\n",rank);
|
||||
MPIExit();
|
||||
delete zz;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Visualize the partitioning before and after calling Zoltan.
|
||||
//
|
||||
// In this example, partition number equals process rank.
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
int *parts = new int [objects.get_num_my_objects()];
|
||||
|
||||
for (int i=0; i < objects.get_num_my_objects(); i++){
|
||||
parts[i] = rank;
|
||||
}
|
||||
|
||||
if (rank == 0){
|
||||
printf("\nObject partition assignments before calling Zoltan\n");
|
||||
}
|
||||
|
||||
showSimpleMeshPartitions(rank, objects.get_num_my_objects(),
|
||||
objects.get_my_global_ids(), parts);
|
||||
|
||||
for (int i=0; i < numExport; i++){
|
||||
parts[exportLocalIds[i]] = exportToPart[i];
|
||||
}
|
||||
|
||||
if (rank == 0){
|
||||
printf("Object partition assignments after calling Zoltan\n");
|
||||
}
|
||||
|
||||
showSimpleMeshPartitions(rank, objects.get_num_my_objects(),
|
||||
objects.get_my_global_ids(), parts);
|
||||
|
||||
delete [] parts;
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Free the arrays allocated by LB_Partition, and free
|
||||
// the storage allocated for the Zoltan structure and the mesh.
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
Zoltan::LB_Free_Part(&importGlobalIds, &importLocalIds, &importProcs,
|
||||
&importToPart);
|
||||
Zoltan::LB_Free_Part(&exportGlobalIds, &exportLocalIds, &exportProcs,
|
||||
&exportToPart);
|
||||
|
||||
delete zz;
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// all done ////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
MPIExit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
// Proc 0 notifies others of error and exits
|
||||
|
||||
static void input_file_error(int numProcs, int tag, int startProc)
|
||||
{
|
||||
int i, val;
|
||||
|
||||
val = -1;
|
||||
|
||||
fprintf(stderr,"ERROR in input file.\n");
|
||||
|
||||
for (i=startProc; i < numProcs; i++){
|
||||
// these procs have posted receive for "tag"
|
||||
#ifdef MPICPP
|
||||
MPI::COMM_WORLD.Send(&val, 1, MPI::INT, i, tag);
|
||||
#else
|
||||
MPI_Send(&val, 1, MPI_INT, i, tag, MPI_COMM_WORLD);
|
||||
#endif
|
||||
|
||||
}
|
||||
for (i=1; i < startProc; i++){
|
||||
// these procs are done
|
||||
#ifdef MPICPP
|
||||
MPI::COMM_WORLD.Send(&val, 1, MPI::INT, i, 0);
|
||||
#else
|
||||
MPI_Send(&val, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
|
||||
#endif
|
||||
}
|
||||
|
||||
MPIExit();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Draw the partition assignments of the objects */
|
||||
|
||||
void showSimpleMeshPartitions(int myProc, int numIDs, int *GIDs, int *parts)
|
||||
{
|
||||
int partAssign[25], allPartAssign[25];
|
||||
int i, j, part;
|
||||
|
||||
memset(partAssign, 0, sizeof(int) * 25);
|
||||
|
||||
for (i=0; i < numIDs; i++){
|
||||
partAssign[GIDs[i]-1] = parts[i];
|
||||
}
|
||||
|
||||
#ifdef MPICPP
|
||||
MPI::COMM_WORLD.Reduce(partAssign, allPartAssign, 25, MPI::INT, MPI::MAX, 0);
|
||||
#else
|
||||
MPI_Reduce(partAssign, allPartAssign, 25, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
|
||||
#endif
|
||||
|
||||
if (myProc == 0){
|
||||
|
||||
for (i=20; i >= 0; i-=5){
|
||||
for (j=0; j < 5; j++){
|
||||
part = allPartAssign[i + j];
|
||||
if (j < 4)
|
||||
printf("%d-----",part);
|
||||
else
|
||||
printf("%d\n",part);
|
||||
}
|
||||
if (i > 0)
|
||||
printf("| | | | |\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Proc 0 reads the objects in the input file and divides them across processes
|
||||
//
|
||||
|
||||
void read_input_objects(int myRank, int numProcs, const char *fname, objectCollection &myData)
|
||||
{
|
||||
int val, nobj, remainingObj;
|
||||
int obj_ack_tag = 5, obj_count_tag = 10, obj_id_tag = 15;
|
||||
#ifdef MPICPP
|
||||
MPI::Status status;
|
||||
#else
|
||||
MPI_Status status;
|
||||
#endif
|
||||
|
||||
if (myRank == 0){
|
||||
|
||||
char *buf = new char [512];
|
||||
FILE *fp = fopen(fname, "r");
|
||||
|
||||
int num = get_next_line(fp, buf, 512);
|
||||
if (num == 0) input_file_error(numProcs, obj_count_tag, 1);
|
||||
num = sscanf(buf, "%d", &val);
|
||||
myData.set_num_global_objects(val);
|
||||
if (num != 1) input_file_error(numProcs, obj_count_tag, 1);
|
||||
|
||||
if (numProcs > 1){
|
||||
nobj = myData.get_num_global_objects() / 2;
|
||||
remainingObj = myData.get_num_global_objects() - nobj;
|
||||
}
|
||||
else{
|
||||
nobj = myData.get_num_global_objects();
|
||||
remainingObj = 0;
|
||||
}
|
||||
|
||||
int *mygids = new int [nobj];
|
||||
myData.set_num_my_objects(nobj);
|
||||
myData.set_my_global_ids(mygids);
|
||||
|
||||
for (int i=0; i < nobj; i++){
|
||||
|
||||
num = get_next_line(fp, buf, 512);
|
||||
if (num == 0) input_file_error(numProcs, obj_count_tag, 1);
|
||||
num = sscanf(buf, "%d", &val);
|
||||
if (num != 1) input_file_error(numProcs, obj_count_tag, 1);
|
||||
mygids[i] = val;
|
||||
|
||||
}
|
||||
|
||||
int *gids = new int [nobj + 1];
|
||||
int ack = 0;
|
||||
|
||||
for (int i=1; i < numProcs; i++){
|
||||
|
||||
if (remainingObj > 1){
|
||||
nobj = remainingObj / 2;
|
||||
remainingObj -= nobj;
|
||||
}
|
||||
else if (remainingObj == 1){
|
||||
nobj = 1;
|
||||
remainingObj = 0;
|
||||
}
|
||||
else{
|
||||
nobj = 0;
|
||||
}
|
||||
|
||||
if ((i == numProcs - 1) && (remainingObj > 0))
|
||||
nobj += remainingObj;
|
||||
|
||||
if (nobj > 0){
|
||||
for (int j=0; j < nobj; j++){
|
||||
num = get_next_line(fp, buf, 512);
|
||||
if (num == 0) input_file_error(numProcs, obj_count_tag, i);
|
||||
num = sscanf(buf, "%d", &val);
|
||||
if (num != 1) input_file_error(numProcs, obj_count_tag, i);
|
||||
gids[j] = val;;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MPICPP
|
||||
MPI::COMM_WORLD.Send(&nobj, 1, MPI::INT, i, obj_count_tag);
|
||||
MPI::COMM_WORLD.Recv(&ack, 1, MPI::INT, i, obj_ack_tag, status);
|
||||
#else
|
||||
MPI_Send(&nobj, 1, MPI_INT, i, obj_count_tag, MPI_COMM_WORLD);
|
||||
MPI_Recv(&ack, 1, MPI_INT, i, obj_ack_tag, MPI_COMM_WORLD, &status);
|
||||
#endif
|
||||
|
||||
if (nobj > 0)
|
||||
MPI_Send(gids, nobj, MPI_INT, i, obj_id_tag, MPI_COMM_WORLD);
|
||||
|
||||
}
|
||||
|
||||
delete [] gids;
|
||||
delete [] buf;
|
||||
|
||||
fclose(fp);
|
||||
|
||||
/* signal all procs it is OK to go on */
|
||||
ack = 0;
|
||||
for (int i=1; i < numProcs; i++){
|
||||
#ifdef MPICPP
|
||||
MPI::COMM_WORLD.Send(&ack, 1, MPI::INT, i, 0);
|
||||
#else
|
||||
MPI_Send(&ack, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else{
|
||||
|
||||
#ifdef MPICPP
|
||||
MPI::COMM_WORLD.Recv(&val, 1, MPI::INT, 0, obj_count_tag, status);
|
||||
#else
|
||||
MPI_Recv(&val, 1, MPI_INT, 0, obj_count_tag, MPI_COMM_WORLD, &status);
|
||||
#endif
|
||||
|
||||
myData.set_num_my_objects(val);
|
||||
|
||||
int ack = 0;
|
||||
|
||||
if (myData.get_num_my_objects() > 0){
|
||||
int *mygids = new int [myData.get_num_my_objects()];
|
||||
#ifdef MPICPP
|
||||
MPI::COMM_WORLD.Send(&ack, 1, MPI::INT, 0, obj_ack_tag);
|
||||
MPI::COMM_WORLD.Recv(mygids, myData.get_num_my_objects(), MPI::INT, 0,
|
||||
obj_id_tag, status);
|
||||
#else
|
||||
MPI_Send(&ack, 1, MPI_INT, 0, obj_ack_tag, MPI_COMM_WORLD);
|
||||
MPI_Recv(mygids, myData.get_num_my_objects(), MPI_INT, 0,
|
||||
obj_id_tag, MPI_COMM_WORLD, &status);
|
||||
#endif
|
||||
|
||||
myData.set_my_global_ids(mygids);
|
||||
}
|
||||
else if (myData.get_num_my_objects() == 0){
|
||||
#ifdef MPICPP
|
||||
MPI::COMM_WORLD.Send(&ack, 1, MPI::INT, 0, obj_ack_tag);
|
||||
#else
|
||||
MPI_Send(&ack, 1, MPI_INT, 0, obj_ack_tag, MPI_COMM_WORLD);
|
||||
#endif
|
||||
}
|
||||
else{
|
||||
MPIExit();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef MPICPP
|
||||
MPI::COMM_WORLD.Recv(&ack, 1, MPI::INT, 0, 0, status);
|
||||
#else
|
||||
MPI_Recv(&ack, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
|
||||
#endif
|
||||
if (ack < 0){
|
||||
MPIExit();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user