45 #ifndef _ZOLTAN2_ALGSCOTCH_HPP_ 46 #define _ZOLTAN2_ALGSCOTCH_HPP_ 67 pl.set(
"scotch_verbose",
false,
"verbose output",
70 RCP<Teuchos::EnhancedNumberValidator<int>> scotch_level_Validator =
71 Teuchos::rcp(
new Teuchos::EnhancedNumberValidator<int>(0, 1000, 1, 0) );
72 pl.set(
"scotch_level", 0,
"scotch ordering - Level of the subgraph in the " 73 "separators tree for the initial graph at the root of the tree",
74 scotch_level_Validator);
76 pl.set(
"scotch_imbalance_ratio", 0.2,
"scotch ordering - Dissection " 80 pl.set(
"scotch_ordering_default",
true,
"use default scotch ordering " 83 pl.set(
"scotch_ordering_strategy",
"",
"scotch ordering - Dissection " 89 #ifndef HAVE_ZOLTAN2_SCOTCH 96 template <
typename Adapter>
106 const RCP<
const Comm<int> > &problemComm,
107 const RCP<const base_adapter_t> &adapter
110 throw std::runtime_error(
111 "BUILD ERROR: Scotch requested but not compiled into Zoltan2.\n" 112 "Please set CMake flag Zoltan2_ENABLE_Scotch:BOOL=ON.");
128 #ifdef HAVE_ZOLTAN2_SCOTCH 135 #ifndef HAVE_ZOLTAN2_MPI 138 #include "ptscotch.h" 142 #ifdef SHOW_ZOLTAN2_SCOTCH_MEMORY 155 #ifdef HAVE_SCOTCH_GETMEMORYMAX 157 extern size_t SCOTCH_getMemoryMax();
160 #error "Either turn off ZOLTAN2_ENABLE_SCOTCH_MEMORY_REPORT in cmake configure, or see SHOW_ZOLTAN2_SCOTCH_MEMORY comment in Zoltan2_AlgScotch.hpp" 161 #endif // HAVE_SCOTCH_GETMEMORYMAX 162 #endif // SHOW_ZOLTAN2_SCOTCH_MEMORY 164 template <
typename Adapter>
171 typedef typename Adapter::lno_t
lno_t;
172 typedef typename Adapter::gno_t
gno_t;
173 typedef typename Adapter::scalar_t
scalar_t;
175 typedef typename Adapter::user_t user_t;
176 typedef typename Adapter::userCoord_t userCoord_t;
208 const RCP<
const Comm<int> > &problemComm__,
210 env(env__), problemComm(problemComm__),
211 #ifdef HAVE_ZOLTAN2_MPI 212 mpicomm(Teuchos::getRawMpiComm(*problemComm__)),
216 std::string errStr =
"cannot build GraphModel from IdentifierAdapter, ";
217 errStr +=
"Scotch requires Graph, Matrix, or Mesh Adapter";
218 throw std::runtime_error(errStr);
222 const RCP<
const Comm<int> > &problemComm__,
224 env(env__), problemComm(problemComm__),
225 #ifdef HAVE_ZOLTAN2_MPI 226 mpicomm(Teuchos::getRawMpiComm(*problemComm__)),
230 std::string errStr =
"cannot build GraphModel from IdentifierAdapter, ";
231 errStr +=
"Scotch requires Graph, Matrix, or Mesh Adapter";
232 throw std::runtime_error(errStr);
236 const RCP<
const Comm<int> > &problemComm__,
238 env(env__), problemComm(problemComm__),
239 #ifdef HAVE_ZOLTAN2_MPI 240 mpicomm(Teuchos::getRawMpiComm(*problemComm__)),
242 adapter(adapter__), model_flags()
244 this->model_flags.reset();
248 const RCP<
const Comm<int> > &problemComm__,
250 env(env__), problemComm(problemComm__),
251 #ifdef HAVE_ZOLTAN2_MPI 252 mpicomm(Teuchos::getRawMpiComm(*problemComm__)),
254 adapter(adapter__), model_flags()
256 this->model_flags.reset();
258 const ParameterList &pl = env->getParameters();
259 const Teuchos::ParameterEntry *pe;
261 std::string defString(
"default");
262 std::string objectOfInterest(defString);
263 pe = pl.getEntryPtr(
"objects_to_partition");
265 objectOfInterest = pe->getValue<std::string>(&objectOfInterest);
267 if (objectOfInterest == defString ||
268 objectOfInterest == std::string(
"matrix_rows") )
270 else if (objectOfInterest == std::string(
"matrix_columns"))
272 else if (objectOfInterest == std::string(
"matrix_nonzeros"))
277 const RCP<
const Comm<int> > &problemComm__,
279 env(env__), problemComm(problemComm__),
280 #ifdef HAVE_ZOLTAN2_MPI 281 mpicomm(Teuchos::getRawMpiComm(*problemComm__)),
283 adapter(adapter__), model_flags()
285 this->model_flags.reset();
287 const ParameterList &pl = env->getParameters();
288 const Teuchos::ParameterEntry *pe;
290 std::string defString(
"default");
291 std::string objectOfInterest(defString);
292 pe = pl.getEntryPtr(
"objects_to_partition");
294 objectOfInterest = pe->getValue<std::string>(&objectOfInterest);
296 if (objectOfInterest == defString ||
297 objectOfInterest == std::string(
"mesh_nodes") )
299 else if (objectOfInterest == std::string(
"mesh_elements"))
317 const RCP<const Environment> env;
318 const RCP<const Comm<int> > problemComm;
319 #ifdef HAVE_ZOLTAN2_MPI 320 const MPI_Comm mpicomm;
322 const RCP<const base_adapter_t> adapter;
324 RCP<graphModel_t > model;
326 void buildModel(
bool isLocal);
329 static int setStrategy(SCOTCH_Strat * c_strat_ptr,
const ParameterList &pList,
int procRank);
333 template <
typename Adapter>
336 const ParameterList &pl = env->getParameters();
337 const Teuchos::ParameterEntry *pe;
339 std::string defString(
"default");
340 std::string symParameter(defString);
341 pe = pl.getEntryPtr(
"symmetrize_graph");
343 symParameter = pe->getValue<std::string>(&symParameter);
344 if (symParameter == std::string(
"transpose"))
346 else if (symParameter == std::string(
"bipartite"))
349 bool sgParameter =
false;
350 pe = pl.getEntryPtr(
"subset_graph");
352 sgParameter = pe->getValue(&sgParameter);
364 this->model = rcp(
new graphModel_t(this->adapter,
371 template <
typename Adapter>
377 this->buildModel(
false);
379 size_t numGlobalParts = solution->getTargetGlobalNumberOfParts();
381 SCOTCH_Num partnbr=0;
384 #ifdef HAVE_ZOLTAN2_MPI 386 int me = problemComm->getRank();
388 const SCOTCH_Num baseval = 0;
391 SCOTCH_Strat stratstr;
393 SCOTCH_stratInit(&stratstr);
396 SCOTCH_Dgraph *gr = SCOTCH_dgraphAlloc();
397 ierr = SCOTCH_dgraphInit(gr, mpicomm);
399 env->globalInputAssertion(__FILE__, __LINE__,
"SCOTCH_dgraphInit",
403 ArrayView<const gno_t> vtxID;
404 ArrayView<StridedData<lno_t, scalar_t> > vwgts;
405 size_t nVtx = model->getVertexList(vtxID, vwgts);
406 SCOTCH_Num vertlocnbr=0;
408 SCOTCH_Num vertlocmax = vertlocnbr;
411 ArrayView<const gno_t> edgeIds;
412 ArrayView<const lno_t> offsets;
413 ArrayView<StridedData<lno_t, scalar_t> > ewgts;
415 size_t nEdge = model->getEdgeList(edgeIds, offsets, ewgts);
417 SCOTCH_Num edgelocnbr=0;
419 const SCOTCH_Num edgelocsize = edgelocnbr;
421 SCOTCH_Num *vertloctab;
424 SCOTCH_Num *edgeloctab;
428 SCOTCH_Num *vendloctab = NULL;
429 SCOTCH_Num *vlblloctab = NULL;
430 SCOTCH_Num *edgegsttab = NULL;
433 SCOTCH_Num *velotab = NULL;
434 SCOTCH_Num *edlotab = NULL;
436 int nVwgts = model->getNumWeightsPerVertex();
437 int nEwgts = model->getNumWeightsPerEdge();
438 if (nVwgts > 1 && me == 0) {
439 std::cerr <<
"Warning: NumWeightsPerVertex is " << nVwgts
440 <<
" but Scotch allows only one weight. " 441 <<
" Zoltan2 will use only the first weight per vertex." 444 if (nEwgts > 1 && me == 0) {
445 std::cerr <<
"Warning: NumWeightsPerEdge is " << nEwgts
446 <<
" but Scotch allows only one weight. " 447 <<
" Zoltan2 will use only the first weight per edge." 452 velotab =
new SCOTCH_Num[nVtx+1];
454 scale_weights(nVtx, vwgts[0], velotab);
458 edlotab =
new SCOTCH_Num[nEdge+1];
460 scale_weights(nEdge, ewgts[0], edlotab);
464 ierr = SCOTCH_dgraphBuild(gr, baseval, vertlocnbr, vertlocmax,
465 vertloctab, vendloctab, velotab, vlblloctab,
466 edgelocnbr, edgelocsize,
467 edgeloctab, edgegsttab, edlotab);
469 env->globalInputAssertion(__FILE__, __LINE__,
"SCOTCH_dgraphBuild",
473 SCOTCH_Num *partloctab =
new SCOTCH_Num[nVtx+1];
478 float *partsizes =
new float[numGlobalParts];
479 if (!solution->criteriaHasUniformPartSizes(0))
480 for (
size_t i=0; i<numGlobalParts; i++)
481 partsizes[i] = solution->getCriteriaPartSize(0, i);
483 for (
size_t i=0; i<numGlobalParts; i++)
484 partsizes[i] = 1.0 /
float(numGlobalParts);
488 SCOTCH_archInit(&archdat);
490 SCOTCH_Num velosum = 0;
491 SCOTCH_dgraphSize (gr, &velosum, NULL, NULL, NULL);
492 SCOTCH_Num *goalsizes =
new SCOTCH_Num[partnbr];
498 for (SCOTCH_Num i = 0; i < partnbr; i++)
499 goalsizes[i] = SCOTCH_Num(ceil(velosum * partsizes[i]));
502 SCOTCH_archCmpltw(&archdat, partnbr, goalsizes);
505 ierr = SCOTCH_dgraphMap(gr, &archdat, &stratstr, partloctab);
507 env->globalInputAssertion(__FILE__, __LINE__,
"SCOTCH_dgraphMap",
510 SCOTCH_archExit(&archdat);
515 #ifdef SHOW_ZOLTAN2_SCOTCH_MEMORY 516 int me = env->comm_->getRank();
519 #ifdef HAVE_SCOTCH_ZOLTAN2_GETMEMORYMAX 521 size_t scotchBytes = SCOTCH_getMemoryMax();
522 std::cout <<
"Rank " << me <<
": Maximum bytes used by Scotch: ";
523 std::cout << scotchBytes << std::endl;
528 SCOTCH_dgraphExit(gr);
530 SCOTCH_stratExit(&stratstr);
534 ArrayRCP<part_t> partList;
539 solution->setParts(partList);
541 env->memory(
"Zoltan2-Scotch: After creating solution");
547 if (nVwgts)
delete [] velotab;
548 if (nEwgts)
delete [] edlotab;
550 #else // DO NOT HAVE MPI 558 ArrayView<const gno_t> vtxID;
559 ArrayView<StridedData<lno_t, scalar_t> > vwgts;
560 size_t nVtx = model->getVertexList(vtxID, vwgts);
562 ArrayRCP<part_t> partList(
new part_t[nVtx], 0, nVtx,
true);
563 for (
size_t i = 0; i < nVtx; i++) partList[i] = 0;
565 solution->setParts(partList);
567 #endif // DO NOT HAVE MPI 580 template <
typename Adapter>
587 const double INT_EPSILON = 1e-5;
589 SCOTCH_Num nonint, nonint_local = 0;
590 double sum_wgt, sum_wgt_local = 0.;
591 double max_wgt, max_wgt_local = 0.;
595 for (
size_t i = 0; i < n; i++) {
596 double fw = double(fwgts[i]);
598 SCOTCH_Num tmp = (SCOTCH_Num) floor(fw + .5);
599 if (fabs((
double)tmp-fw) > INT_EPSILON) {
604 if (fw > max_wgt_local) max_wgt_local = fw;
607 Teuchos::reduceAll<int,SCOTCH_Num>(*problemComm, Teuchos::REDUCE_MAX, 1,
608 &nonint_local, &nonint);
609 Teuchos::reduceAll<int,double>(*problemComm, Teuchos::REDUCE_SUM, 1,
610 &sum_wgt_local, &sum_wgt);
611 Teuchos::reduceAll<int,double>(*problemComm, Teuchos::REDUCE_MAX, 1,
612 &max_wgt_local, &max_wgt);
615 const double max_wgt_sum = double(SCOTCH_NUMMAX/8);
619 if (nonint || (max_wgt <= INT_EPSILON) || (sum_wgt > max_wgt_sum)) {
621 if (sum_wgt != 0.) scale = max_wgt_sum/sum_wgt;
625 for (
size_t i = 0; i < n; i++)
626 iwgts[i] = (SCOTCH_Num) ceil(
double(fwgts[i])*scale);
630 template <
typename Adapter>
633 bool bPrintOutput =
false;
634 const Teuchos::ParameterEntry *pe;
637 pe = pList.getEntryPtr(
"scotch_verbose");
639 bPrintOutput = pe->getValue(&bPrintOutput);
644 bool scotch_ordering_default =
true;
645 pe = pList.getEntryPtr(
"scotch_ordering_default");
647 scotch_ordering_default = pe->getValue(&scotch_ordering_default);
651 "Scotch: Ordering default setting (parameter: scotch_ordering_default): " 652 << (scotch_ordering_default ?
"True" :
"False" ) << std::endl;
658 if (scotch_ordering_default) {
660 int scotch_level = 0;
661 pe = pList.getEntryPtr(
"scotch_level");
663 scotch_level = pe->getValue(&scotch_level);
666 std::cout <<
"Scotch: Ordering level (parameter: scotch_level): " <<
667 scotch_level << std::endl;
671 double scotch_imbalance_ratio = 0.2;
672 pe = pList.getEntryPtr(
"scotch_imbalance_ratio");
674 scotch_imbalance_ratio = pe->getValue(&scotch_imbalance_ratio);
677 std::cout <<
"Scotch: Ordering dissection imbalance ratio " 678 "(parameter: scotch_imbalance_ratio): " 679 << scotch_imbalance_ratio << std::endl;
682 SCOTCH_stratInit(c_strat_ptr);
684 ierr = SCOTCH_stratGraphOrderBuild( c_strat_ptr,
685 SCOTCH_STRATLEVELMAX | SCOTCH_STRATLEVELMIN |
686 SCOTCH_STRATLEAFSIMPLE | SCOTCH_STRATSEPASIMPLE,
687 scotch_level, scotch_imbalance_ratio);
691 std::string scotch_ordering_strategy_string(
"");
692 pe = pList.getEntryPtr(
"scotch_ordering_strategy");
694 scotch_ordering_strategy_string =
695 pe->getValue(&scotch_ordering_strategy_string);
698 std::cout <<
"Scotch ordering strategy" 699 " (parameter: scotch_ordering_strategy): " <<
700 scotch_ordering_strategy_string << std::endl;
703 SCOTCH_stratInit(c_strat_ptr);
704 ierr = SCOTCH_stratGraphOrder( c_strat_ptr,
705 scotch_ordering_strategy_string.c_str());
711 template <
typename Adapter>
714 throw std::logic_error(
"AlgPTScotch does not yet support global ordering.");
717 template <
typename Adapter>
726 int me = problemComm->getRank();
727 const ParameterList &pl = env->getParameters();
728 const Teuchos::ParameterEntry *pe;
730 bool isVerbose =
false;
731 pe = pl.getEntryPtr(
"scotch_verbose");
733 isVerbose = pe->getValue(&isVerbose);
736 this->buildModel(
true);
737 if (isVerbose && me==0) {
738 std::cout <<
"Built local graph model." << std::endl;
742 SCOTCH_Strat c_strat_ptr;
743 SCOTCH_Graph c_graph_ptr;
746 ierr = SCOTCH_graphInit( &c_graph_ptr);
748 throw std::runtime_error(
"Failed to initialize Scotch graph!");
749 }
else if (isVerbose && me == 0) {
750 std::cout <<
"Initialized Scotch graph." << std::endl;
754 ArrayView<const gno_t> vtxID;
755 ArrayView<StridedData<lno_t, scalar_t> > vwgts;
756 size_t nVtx = model->getVertexList(vtxID, vwgts);
757 SCOTCH_Num vertnbr=0;
761 ArrayView<const gno_t> edgeIds;
762 ArrayView<const lno_t> offsets;
763 ArrayView<StridedData<lno_t, scalar_t> > ewgts;
765 size_t nEdge = model->getEdgeList(edgeIds, offsets, ewgts);
766 SCOTCH_Num edgenbr=0;
776 SCOTCH_Num *vendtab = NULL;
779 SCOTCH_Num *velotab = NULL;
780 SCOTCH_Num *vlbltab = NULL;
781 SCOTCH_Num *edlotab = NULL;
783 int nVwgts = model->getNumWeightsPerVertex();
784 int nEwgts = model->getNumWeightsPerEdge();
785 if (nVwgts > 1 && me == 0) {
786 std::cerr <<
"Warning: NumWeightsPerVertex is " << nVwgts
787 <<
" but Scotch allows only one weight. " 788 <<
" Zoltan2 will use only the first weight per vertex." 791 if (nEwgts > 1 && me == 0) {
792 std::cerr <<
"Warning: NumWeightsPerEdge is " << nEwgts
793 <<
" but Scotch allows only one weight. " 794 <<
" Zoltan2 will use only the first weight per edge." 799 velotab =
new SCOTCH_Num[nVtx+1];
801 scale_weights(nVtx, vwgts[0], velotab);
805 edlotab =
new SCOTCH_Num[nEdge+1];
807 scale_weights(nEdge, ewgts[0], edlotab);
813 ierr = SCOTCH_graphBuild( &c_graph_ptr, baseval,
814 vertnbr, verttab, vendtab, velotab, vlbltab,
815 edgenbr, edgetab, edlotab);
817 throw std::runtime_error(
"Failed to build Scotch graph!");
818 }
else if (isVerbose && me == 0) {
819 std::cout <<
"Built Scotch graph." << std::endl;
822 ierr = SCOTCH_graphCheck(&c_graph_ptr);
824 throw std::runtime_error(
"Graph is inconsistent!");
825 }
else if (isVerbose && me == 0) {
826 std::cout <<
"Graph is consistent." << std::endl;
833 throw std::runtime_error(
"Can't build strategy!");
834 }
else if (isVerbose && me == 0) {
835 std::cout <<
"Graphing strategy built." << std::endl;
842 SCOTCH_Num *rangetab;
846 permtab =
reinterpret_cast<SCOTCH_Num*
>(solution->getPermutationView(
false));
847 peritab =
reinterpret_cast<SCOTCH_Num*
>(solution->getPermutationView(
true));
848 rangetab =
reinterpret_cast<SCOTCH_Num*
>(solution->getSeparatorRangeView());
849 treetab =
reinterpret_cast<SCOTCH_Num*
>(solution->getSeparatorTreeView());
852 permtab =
new SCOTCH_Num[nVtx];
853 peritab =
new SCOTCH_Num[nVtx];
854 rangetab =
new SCOTCH_Num[nVtx+1];
855 treetab =
new SCOTCH_Num[nVtx];
858 ierr = SCOTCH_graphOrder(&c_graph_ptr, &c_strat_ptr, permtab, peritab,
859 &cblk, rangetab, treetab);
861 throw std::runtime_error(
"Could not compute ordering!!");
862 }
else if(isVerbose && me == 0) {
863 std::cout <<
"Ordering computed." << std::endl;
868 solution->setNumSeparatorBlocks(nSepBlocks);
872 const ArrayRCP<lno_t> arv_perm = solution->getPermutationRCP(
false);
873 for (
size_t i = 0; i < nVtx; i++)
877 const ArrayRCP<lno_t> arv_peri = solution->getPermutationRCP(
true);
878 for (
size_t i = 0; i < nVtx; i++)
882 const ArrayRCP<lno_t> arv_range = solution->getSeparatorRangeRCP();
883 for (
size_t i = 0; i <= nVtx; i++)
887 const ArrayRCP<lno_t> arv_tree = solution->getSeparatorTreeRCP();
888 for (
size_t i = 0; i < nVtx; i++)
893 solution->setHaveSeparator(
true);
900 if (nVwgts)
delete [] velotab;
901 if (nEwgts)
delete [] edlotab;
903 SCOTCH_stratExit(&c_strat_ptr);
904 SCOTCH_graphFree(&c_graph_ptr);
906 if (isVerbose && problemComm->getRank() == 0) {
907 std::cout <<
"Freed Scotch graph!" << std::endl;
914 #endif // HAVE_ZOLTAN2_SCOTCH use columns as graph vertices
Zoltan2::BaseAdapter< userTypes_t > base_adapter_t
Adapter::base_adapter_t base_adapter_t
IdentifierAdapter defines the interface for identifiers.
use mesh nodes as vertices
virtual int localOrder(const RCP< LocalOrderingSolution< lno_t > > &solution)
Ordering method.
fast typical checks for valid arguments
MatrixAdapter defines the adapter interface for matrices.
GraphAdapter defines the interface for graph-based user data.
static RCP< Teuchos::BoolParameterEntryValidator > getBoolValidator()
Exists to make setting up validators less cluttered.
algorithm requires consecutive ids
MeshAdapter defines the interface for mesh input.
std::bitset< NUM_MODEL_FLAGS > modelFlag_t
model must symmetrize input
Defines the OrderingSolution class.
model must symmetrize input
virtual int globalOrder(const RCP< GlobalOrderingSolution< gno_t > > &solution)
Ordering method.
Defines the PartitioningSolution class.
static RCP< Teuchos::AnyNumberParameterEntryValidator > getAnyDoubleValidator()
Exists to make setting up validators less cluttered.
static void SAVE_ARRAYRCP(ArrayRCP< first_t > *a, second_t *b, size_t size)
sub-steps, each method's entry and exit
SparseMatrixAdapter_t::part_t part_t
use matrix rows as graph vertices
algorithm requires no self edges
static void getScotchParameters(Teuchos::ParameterList &pl)
Adapter::scalar_t scalar_t
A PartitioningSolution is a solution to a partitioning problem.
use nonzeros as graph vertices
VectorAdapter defines the interface for vector input.
The StridedData class manages lists of weights or coordinates.
Algorithm defines the base class for all algorithms.
static void ASSIGN(first_t &a, second_t b)
static void getValidParameters(ParameterList &pl)
Set up validators specific to this algorithm.
virtual void partition(const RCP< PartitioningSolution< Adapter > > &solution)
Partitioning method.
Traits class to handle conversions between gno_t/lno_t and TPL data types (e.g., ParMETIS's idx_t...
use mesh elements as vertices
GraphModel defines the interface required for graph models.
static void ASSIGN_ARRAY(first_t **a, ArrayView< second_t > &b)
AlgPTScotch(const RCP< const Environment > &env, const RCP< const Comm< int > > &problemComm, const RCP< const base_adapter_t > &adapter)
Defines the GraphModel interface.
A gathering of useful namespace methods.
static void DELETE_ARRAY(first_t **a)
model represents graph within only one rank