10 #ifndef _ZOLTAN2_ALGZOLTAN_HPP_
11 #define _ZOLTAN2_ALGZOLTAN_HPP_
22 #include <zoltan_cpp.h>
23 #include <zoltan_partition_tree.h>
41 template <
typename Adapter>
49 typedef typename Adapter::scalar_t scalar_t;
52 typedef typename Adapter::userCoord_t userCoord_t;
54 const RCP<const Environment> env;
55 const RCP<const Comm<int> > problemComm;
56 const RCP<const typename Adapter::base_adapter_t> adapter;
57 RCP<const Model<Adapter> > model;
62 void setMPIComm(
const RCP<
const Comm<int> > &problemComm__) {
63 # ifdef HAVE_ZOLTAN2_MPI
64 mpicomm = Teuchos::getRawMpiComm(*problemComm__);
66 mpicomm = MPI_COMM_WORLD;
75 Zoltan_Initialize(argc, argv, &ver);
78 void setCallbacksIDs()
80 zz->Set_Num_Obj_Fn(zoltanNumObj<Adapter>, (
void *) &(*adapter));
81 zz->Set_Obj_List_Fn(zoltanObjList<Adapter>, (
void *) &(*adapter));
83 const part_t *myparts;
84 adapter->getPartsView(myparts);
86 zz->Set_Part_Multi_Fn(zoltanParts<Adapter>, (
void *) &(*adapter));
90 zz->Set_Param(
"NUM_GID_ENTRIES", tmp);
92 zz->Set_Param(
"NUM_LID_ENTRIES", tmp);
95 template <
typename AdapterWithCoords>
101 zz->Set_Num_Geom_Fn(zoltanNumGeom<AdapterWithCoords>, (
void *) ia);
102 zz->Set_Geom_Multi_Fn(zoltanGeom<AdapterWithCoords>, (
void *) ia);
105 void setCallbacksGraph(
112 void setCallbacksGraph(
119 void setCallbacksGraph(
126 #ifdef HAVE_ZOLTAN2_HYPERGRAPH
127 void setCallbacksHypergraph(
133 zz->Set_HG_Size_CS_Fn(zoltanHGSizeCS_withMatrixAdapter<Adapter>,
135 zz->Set_HG_CS_Fn(zoltanHGCS_withMatrixAdapter<Adapter>,
144 void setCallbacksHypergraph(
147 zz->Set_HG_Size_CS_Fn(zoltanHGSizeCS_withGraphAdapter<Adapter>,
149 zz->Set_HG_CS_Fn(zoltanHGCS_withGraphAdapter<Adapter>,
152 if (adp->getNumWeightsPerEdge() != 0) {
153 if (adp->getNumWeightsPerEdge() > 1) {
154 std::cout <<
"Zoltan2 warning: getNumWeightsPerEdge() returned "
155 << adp->getNumWeightsPerEdge() <<
" but PHG supports only "
156 <<
" one weight per edge; only first weight will be used."
159 zz->Set_HG_Size_Edge_Wts_Fn(zoltanHGSizeEdgeWts_withGraphAdapter<Adapter>,
160 (
void *) &(*adapter));
161 zz->Set_HG_Edge_Wts_Fn(zoltanHGEdgeWts_withGraphAdapter<Adapter>,
162 (
void *) &(*adapter));
169 const Teuchos::ParameterList &pl = env->getParameters();
171 const Teuchos::ParameterEntry *pe = pl.getEntryPtr(
"hypergraph_model_type");
172 std::string model_type(
"traditional");
174 model_type = pe->getValue<std::string>(&model_type);
177 if (model_type==
"ghosting" ||
178 !adp->areEntityIDsUnique(adp->getPrimaryEntityType())) {
185 zz->Set_Num_Obj_Fn(zoltanHGNumObj_withModel<Adapter>, (
void *) &(*mdl));
186 zz->Set_Obj_List_Fn(zoltanHGObjList_withModel<Adapter>, (
void *) &(*mdl));
188 zz->Set_HG_Size_CS_Fn(zoltanHGSizeCS_withModel<Adapter>, (
void *) &(*mdl));
189 zz->Set_HG_CS_Fn(zoltanHGCS_withModel<Adapter>, (
void *) &(*mdl));
193 zz->Set_HG_Size_CS_Fn(zoltanHGSizeCS_withMeshAdapter<Adapter>,
195 zz->Set_HG_CS_Fn(zoltanHGCS_withMeshAdapter<Adapter>,
206 virtual bool isPartitioningTreeBinary()
const
212 void rcb_recursive_partitionTree_calculations(
215 std::vector<part_t> & splitRangeBeg,
216 std::vector<part_t> & splitRangeEnd)
const
225 int err = Zoltan_RCB_Partition_Tree(zz->Get_C_Handle(),
226 arrayIndex - numParts + 1,
227 &parent, &left_leaf, &right_leaf);
229 throw std::logic_error(
"Zoltan_RCB_Partition_Tree returned in error." );
234 rcb_recursive_partitionTree_calculations(left_leaf+numParts-1, numParts,
235 splitRangeBeg, splitRangeEnd);
238 rcb_recursive_partitionTree_calculations(right_leaf+numParts-1, numParts,
239 splitRangeBeg, splitRangeEnd);
244 int leftIndex = (left_leaf > 0) ? (left_leaf-1+numParts) : (-left_leaf);
245 int rightIndex = (right_leaf > 0) ? (right_leaf-1+numParts) : (-right_leaf);
246 splitRangeBeg[arrayIndex] = splitRangeBeg[leftIndex];
247 splitRangeEnd[arrayIndex] = splitRangeEnd[rightIndex];
250 if(splitRangeBeg[rightIndex] != splitRangeEnd[leftIndex]) {
251 throw std::logic_error(
"RCB expected left_leaf indices and right leaf"
252 " indices to be continuous but it was not so." );
257 void rcb_getPartitionTree(part_t numParts,
258 part_t & numTreeVerts,
259 std::vector<part_t> & permPartNums,
260 std::vector<part_t> & splitRangeBeg,
261 std::vector<part_t> & splitRangeEnd,
262 std::vector<part_t> & treeVertParents)
const
270 part_t numTreeNodes = 2 * numParts - 1;
271 numTreeVerts = numTreeNodes - 1;
273 permPartNums.resize(numParts);
274 for(part_t n = 0; n < numParts; ++n) {
278 treeVertParents.resize(numTreeNodes);
286 part_t saveRootNodeChildrenA = -1;
287 part_t saveRootNodeChildrenB = -1;
288 part_t saveFinalNodeChildrenA = -1;
289 part_t saveFinalNodeChildrenB = -1;
290 for(part_t n = numParts; n < numTreeNodes; ++n) {
294 int err = Zoltan_RCB_Partition_Tree(zz->Get_C_Handle(),
295 static_cast<int>(n - numParts) + 1,
296 &parent, &left_leaf, &right_leaf);
298 throw std::logic_error(
"Zoltan_RCB_Partition_Tree returned in error.");
300 part_t leftIndex = (left_leaf > 0) ? (left_leaf-1+numParts) : (-left_leaf);
301 part_t rightIndex = (right_leaf > 0) ? (right_leaf-1+numParts) : (-right_leaf);
302 treeVertParents[leftIndex] = n;
303 treeVertParents[rightIndex] = n;
305 if(parent == 1 || parent == -1) {
307 saveRootNodeChildrenA = leftIndex;
308 saveRootNodeChildrenB = rightIndex;
310 if(n == numTreeNodes-1) {
311 saveFinalNodeChildrenA = leftIndex;
312 saveFinalNodeChildrenB = rightIndex;
315 treeVertParents[rootNode] = -1;
317 splitRangeBeg.resize(numTreeNodes);
318 splitRangeEnd.resize(numTreeNodes);
320 for(part_t n = 0; n < numParts; ++n) {
321 splitRangeBeg[n] = n;
322 splitRangeEnd[n] = n + 1;
328 rcb_recursive_partitionTree_calculations(rootNode, numParts, splitRangeBeg,
332 std::swap(treeVertParents[rootNode], treeVertParents[numTreeNodes-1]);
334 treeVertParents[saveFinalNodeChildrenA] = rootNode;
335 treeVertParents[saveFinalNodeChildrenB] = rootNode;
337 if(saveRootNodeChildrenA == numTreeNodes - 1) {
338 saveRootNodeChildrenA = rootNode;
340 if(saveRootNodeChildrenB == numTreeNodes - 1) {
341 saveRootNodeChildrenB = rootNode;
343 treeVertParents[saveRootNodeChildrenA] = numTreeNodes - 1;
344 treeVertParents[saveRootNodeChildrenB] = numTreeNodes - 1;
346 std::swap(splitRangeBeg[rootNode], splitRangeBeg[numTreeNodes-1]);
347 std::swap(splitRangeEnd[rootNode], splitRangeEnd[numTreeNodes-1]);
352 void phg_getPartitionTree(part_t numParts,
353 part_t & numTreeVerts,
354 std::vector<part_t> & permPartNums,
355 std::vector<part_t> & splitRangeBeg,
356 std::vector<part_t> & splitRangeEnd,
357 std::vector<part_t> & treeVertParents)
const
365 int tree_array_size = -1;
366 int err = Zoltan_PHG_Partition_Tree_Size(
367 zz->Get_C_Handle(), &tree_array_size);
369 throw std::logic_error(
"Zoltan_PHG_Partition_Tree_Size returned error.");
380 part_t numTreeNodes = 0;
381 std::vector<part_t> mapIndex(tree_array_size);
382 part_t trackNonTerminalIndex = numParts;
383 for(part_t n = 0; n < static_cast<part_t>(tree_array_size); ++n) {
384 part_t phgIndex = n + 1;
387 err = Zoltan_PHG_Partition_Tree(
388 zz->Get_C_Handle(), phgIndex, &lo_index, &hi_index);
392 mapIndex[n] = (lo_index == hi_index) ?
394 (trackNonTerminalIndex++);
399 mapIndex[0] = numTreeNodes - 1;
401 numTreeVerts = numTreeNodes - 1;
403 permPartNums.resize(numParts);
404 for(part_t n = 0; n < numParts; ++n) {
410 treeVertParents.resize(numTreeNodes);
411 splitRangeBeg.resize(numTreeNodes);
412 splitRangeEnd.resize(numTreeNodes);
414 for(part_t n = 0; n < tree_array_size; ++n) {
415 part_t phgIndex = n + 1;
418 err = Zoltan_PHG_Partition_Tree(
419 zz->Get_C_Handle(), phgIndex, &lo_index, &hi_index);
421 throw std::logic_error(
"Zoltan_PHG_Partition_Tree returned in error.");
425 part_t finalIndex = mapIndex[n];
434 part_t parentPHGIndex =
435 ((phgIndex%2) == 0) ? (phgIndex/2) : ((phgIndex-1)/2);
438 treeVertParents[finalIndex] = (n==0) ? -1 : mapIndex[parentPHGIndex-1];
440 splitRangeBeg[finalIndex] =
static_cast<part_t
>(lo_index);
441 splitRangeEnd[finalIndex] =
static_cast<part_t
>(hi_index+1);
447 void getPartitionTree(part_t numParts,
448 part_t & numTreeVerts,
449 std::vector<part_t> & permPartNums,
450 std::vector<part_t> & splitRangeBeg,
451 std::vector<part_t> & splitRangeEnd,
452 std::vector<part_t> & treeVertParents)
const
455 const Teuchos::ParameterList &pl = env->getParameters();
456 bool keep_partition_tree =
false;
457 const Teuchos::ParameterEntry * pe = pl.getEntryPtr(
"keep_partition_tree");
459 keep_partition_tree = pe->getValue(&keep_partition_tree);
460 if(!keep_partition_tree) {
461 throw std::logic_error(
462 "Requested tree when param keep_partition_tree is off.");
468 const Teuchos::ParameterList & zoltan_pl = pl.sublist(
"zoltan_parameters");
469 std::string lb_method;
470 pe = zoltan_pl.getEntryPtr(
"LB_METHOD");
472 lb_method = pe->getValue(&lb_method);
474 if(lb_method ==
"phg") {
475 phg_getPartitionTree(numParts, numTreeVerts, permPartNums,
476 splitRangeBeg, splitRangeEnd, treeVertParents);
478 else if(lb_method ==
"rcb") {
479 rcb_getPartitionTree(numParts, numTreeVerts, permPartNums,
480 splitRangeBeg, splitRangeEnd, treeVertParents);
483 throw std::logic_error(
"Did not recognize LB_METHOD: " + lb_method);
495 const RCP<
const Comm<int> > &problemComm__,
497 env(env__), problemComm(problemComm__), adapter(adapter__)
499 setMPIComm(problemComm__);
501 zz = rcp(
new Zoltan(mpicomm));
506 const RCP<
const Comm<int> > &problemComm__,
508 env(env__), problemComm(problemComm__), adapter(adapter__)
510 setMPIComm(problemComm__);
512 zz = rcp(
new Zoltan(mpicomm));
514 setCallbacksGeom(&(*adapter));
518 const RCP<
const Comm<int> > &problemComm__,
520 env(env__), problemComm(problemComm__), adapter(adapter__)
522 setMPIComm(problemComm__);
524 zz = rcp(
new Zoltan(mpicomm));
526 setCallbacksGraph(adapter);
527 #ifdef HAVE_ZOLTAN2_HYPERGRAPH
528 setCallbacksHypergraph(adapter);
530 if (adapter->coordinatesAvailable()) {
531 setCallbacksGeom(adapter->getCoordinateInput());
536 const RCP<
const Comm<int> > &problemComm__,
538 env(env__), problemComm(problemComm__), adapter(adapter__)
540 setMPIComm(problemComm__);
542 zz = rcp(
new Zoltan(mpicomm));
544 setCallbacksGraph(adapter);
545 #ifdef HAVE_ZOLTAN2_HYPERGRAPH
546 setCallbacksHypergraph(adapter);
548 if (adapter->coordinatesAvailable()) {
549 setCallbacksGeom(adapter->getCoordinateInput());
554 const RCP<
const Comm<int> > &problemComm__,
556 env(env__), problemComm(problemComm__), adapter(adapter__)
558 setMPIComm(problemComm__);
560 zz = rcp(
new Zoltan(mpicomm));
562 setCallbacksGraph(adapter);
566 #ifdef HAVE_ZOLTAN2_HYPERGRAPH
567 setCallbacksHypergraph(adapter);
569 setCallbacksGeom(&(*adapter));
577 template <
typename Adapter>
585 size_t numGlobalParts = solution->getTargetGlobalNumberOfParts();
587 sprintf(paramstr,
"%lu", numGlobalParts);
588 zz->Set_Param(
"NUM_GLOBAL_PARTS", paramstr);
590 int wdim = adapter->getNumWeightsPerID();
591 sprintf(paramstr,
"%d", wdim);
592 zz->Set_Param(
"OBJ_WEIGHT_DIM", paramstr);
594 const Teuchos::ParameterList &pl = env->getParameters();
597 const Teuchos::ParameterEntry *pe = pl.getEntryPtr(
"imbalance_tolerance");
600 tolerance = pe->getValue<
double>(&tolerance);
601 sprintf(str,
"%f", tolerance);
602 zz->Set_Param(
"IMBALANCE_TOL", str);
605 pe = pl.getEntryPtr(
"partitioning_approach");
607 std::string approach;
608 approach = pe->getValue<std::string>(&approach);
609 if (approach ==
"partition")
610 zz->Set_Param(
"LB_APPROACH",
"PARTITION");
612 zz->Set_Param(
"LB_APPROACH",
"REPARTITION");
615 pe = pl.getEntryPtr(
"partitioning_objective");
617 std::string strChoice = pe->getValue<std::string>(&strChoice);
618 if (strChoice == std::string(
"multicriteria_minimize_total_weight"))
619 zz->Set_Param(
"RCB_MULTICRITERIA_NORM",
"1");
620 else if (strChoice == std::string(
"multicriteria_balance_total_maximum"))
621 zz->Set_Param(
"RCB_MULTICRITERIA_NORM",
"2");
622 else if (strChoice == std::string(
"multicriteria_minimize_maximum_weight"))
623 zz->Set_Param(
"RCB_MULTICRITERIA_NORM",
"3");
630 bool keep_partition_tree =
false;
631 pe = pl.getEntryPtr(
"keep_partition_tree");
633 keep_partition_tree = pe->getValue(&keep_partition_tree);
634 if (keep_partition_tree) {
638 zz->Set_Param(
"KEEP_CUTS",
"1");
639 zz->Set_Param(
"PHG_KEEP_TREE",
"1");
643 pe = pl.getEntryPtr(
"rectilinear");
645 bool val = pe->getValue(&val);
647 zz->Set_Param(
"RCB_RECTILINEAR_BLOCKS",
"1");
652 const Teuchos::ParameterList &zpl = pl.sublist(
"zoltan_parameters");
653 for (ParameterList::ConstIterator iter = zpl.begin();
654 iter != zpl.end(); iter++) {
655 const std::string &zname = pl.name(iter);
657 std::string zval = pl.entry(iter).getValue(&zval);
658 zz->Set_Param(zname.c_str(), zval.c_str());
661 catch (std::exception &) {
666 int pdim = (wdim > 1 ? wdim : 1);
667 for (
int d = 0; d < pdim; d++) {
668 if (!solution->criteriaHasUniformPartSizes(d)) {
669 float *partsizes =
new float[numGlobalParts];
670 int *partidx =
new int[numGlobalParts];
671 int *wgtidx =
new int[numGlobalParts];
672 for (
size_t i=0; i<numGlobalParts; i++) partidx[i] = i;
673 for (
size_t i=0; i<numGlobalParts; i++) wgtidx[i] = d;
674 for (
size_t i=0; i<numGlobalParts; i++)
675 partsizes[i] = solution->getCriteriaPartSize(0, i);
676 zz->LB_Set_Part_Sizes(1, numGlobalParts, partidx, wgtidx, partsizes);
689 ZOLTAN_ID_PTR dGids = NULL, dLids = NULL;
690 int *dProcs = NULL, *dParts = NULL;
692 ZOLTAN_ID_PTR oGids = NULL, oLids = NULL;
693 int *oProcs = NULL, *oParts = NULL;
695 zz->Set_Param(
"RETURN_LISTS",
"PARTS");
698 int ierr = zz->LB_Partition(changed, nGidEnt, nLidEnt,
699 nDummy, dGids, dLids, dProcs, dParts,
700 nObj, oGids, oLids, oProcs, oParts);
702 env->globalInputAssertion(__FILE__, __LINE__,
"Zoltan LB_Partition",
706 #ifdef HAVE_ZOLTAN2_HYPERGRAPH
712 numObjects=model->getLocalNumObjects();
717 ArrayRCP<part_t> partList(
new part_t[numObjects], 0, numObjects,
true);
718 for (
int i = 0; i < nObj; i++) {
721 partList[tmp] = oParts[i];
723 #ifdef HAVE_ZOLTAN2_HYPERGRAPH
733 Teuchos::RCP<const map_t> mapWithCopies;
734 Teuchos::RCP<const map_t> oneToOneMap;
737 typedef Tpetra::Vector<scalar_t, lno_t, gno_t> vector_t;
738 vector_t vecWithCopies(mapWithCopies);
739 vector_t oneToOneVec(oneToOneMap);
742 assert(nObj ==
lno_t(oneToOneMap->getLocalNumElements()));
743 for (lno_t i = 0; i < nObj; i++)
744 oneToOneVec.replaceLocalValue(i, oParts[i]);
747 Teuchos::RCP<const Tpetra::Import<lno_t, gno_t> > importer =
748 Tpetra::createImport<lno_t, gno_t>(oneToOneMap, mapWithCopies);
749 vecWithCopies.doImport(oneToOneVec, *importer, Tpetra::REPLACE);
752 lno_t nlocal =
lno_t(mapWithCopies->getLocalNumElements());
753 for (lno_t i = 0; i < nlocal; i++)
754 partList[i] = vecWithCopies.getData()[i];
758 solution->setParts(partList);
761 zz->LB_Free_Part(&oGids, &oLids, &oProcs, &oParts);
AlgZoltan(const RCP< const Environment > &env__, const RCP< const Comm< int > > &problemComm__, const RCP< const VectorAdapter< user_t > > &adapter__)
IdentifierAdapter defines the interface for identifiers.
fast typical checks for valid arguments
MatrixAdapter defines the adapter interface for matrices.
Defines the Model interface.
AlgZoltan(const RCP< const Environment > &env__, const RCP< const Comm< int > > &problemComm__, const RCP< const MatrixAdapter< user_t, userCoord_t > > &adapter__)
GraphAdapter defines the interface for graph-based user data.
MeshAdapter defines the interface for mesh input.
std::bitset< NUM_MODEL_FLAGS > modelFlag_t
map_t::global_ordinal_type gno_t
Defines the PartitioningSolution class.
SparseMatrixAdapter_t::part_t part_t
void partition(const RCP< PartitioningSolution< Adapter > > &solution)
Partitioning method.
callback functions for the Zoltan package (templated on Adapter)
A PartitioningSolution is a solution to a partitioning problem.
VectorAdapter defines the interface for vector input.
AlgZoltan(const RCP< const Environment > &env__, const RCP< const Comm< int > > &problemComm__, const RCP< const MeshAdapter< user_t > > &adapter__)
Algorithm defines the base class for all algorithms.
map_t::local_ordinal_type lno_t
static void ASSIGN(first_t &a, second_t b)
Traits class to handle conversions between gno_t/lno_t and TPL data types (e.g., ParMETIS's idx_t...
Gathering definitions used in software development.
The base class for all model classes.
AlgZoltan(const RCP< const Environment > &env__, const RCP< const Comm< int > > &problemComm__, const RCP< const GraphAdapter< user_t, userCoord_t > > &adapter__)
A gathering of useful namespace methods.
HyperGraphModel defines the interface required for hyper graph models.
void getVertexMaps(Teuchos::RCP< const map_t > &copiesMap, Teuchos::RCP< const map_t > &onetooneMap) const
Sets pointers to the vertex map with copies and the vertex map without copies Note: the pointers will...
AlgZoltan(const RCP< const Environment > &env__, const RCP< const Comm< int > > &problemComm__, const RCP< const IdentifierAdapter< user_t > > &adapter__)
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t