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::offset_t offset_t;
174 typedef typename Adapter::scalar_t
scalar_t;
176 typedef typename Adapter::user_t user_t;
177 typedef typename Adapter::userCoord_t userCoord_t;
209 const RCP<
const Comm<int> > &problemComm__,
211 env(env__), problemComm(problemComm__),
212 #ifdef HAVE_ZOLTAN2_MPI 213 mpicomm(Teuchos::getRawMpiComm(*problemComm__)),
217 std::string errStr =
"cannot build GraphModel from IdentifierAdapter, ";
218 errStr +=
"Scotch requires Graph, Matrix, or Mesh Adapter";
219 throw std::runtime_error(errStr);
223 const RCP<
const Comm<int> > &problemComm__,
225 env(env__), problemComm(problemComm__),
226 #ifdef HAVE_ZOLTAN2_MPI 227 mpicomm(Teuchos::getRawMpiComm(*problemComm__)),
231 std::string errStr =
"cannot build GraphModel from IdentifierAdapter, ";
232 errStr +=
"Scotch requires Graph, Matrix, or Mesh Adapter";
233 throw std::runtime_error(errStr);
237 const RCP<
const Comm<int> > &problemComm__,
239 env(env__), problemComm(problemComm__),
240 #ifdef HAVE_ZOLTAN2_MPI 241 mpicomm(Teuchos::getRawMpiComm(*problemComm__)),
243 adapter(adapter__), model_flags()
245 this->model_flags.reset();
249 const RCP<
const Comm<int> > &problemComm__,
251 env(env__), problemComm(problemComm__),
252 #ifdef HAVE_ZOLTAN2_MPI 253 mpicomm(Teuchos::getRawMpiComm(*problemComm__)),
255 adapter(adapter__), model_flags()
257 this->model_flags.reset();
259 const ParameterList &pl = env->getParameters();
260 const Teuchos::ParameterEntry *pe;
262 std::string defString(
"default");
263 std::string objectOfInterest(defString);
264 pe = pl.getEntryPtr(
"objects_to_partition");
266 objectOfInterest = pe->getValue<std::string>(&objectOfInterest);
268 if (objectOfInterest == defString ||
269 objectOfInterest == std::string(
"matrix_rows") )
271 else if (objectOfInterest == std::string(
"matrix_columns"))
273 else if (objectOfInterest == std::string(
"matrix_nonzeros"))
278 const RCP<
const Comm<int> > &problemComm__,
280 env(env__), problemComm(problemComm__),
281 #ifdef HAVE_ZOLTAN2_MPI 282 mpicomm(Teuchos::getRawMpiComm(*problemComm__)),
284 adapter(adapter__), model_flags()
286 this->model_flags.reset();
288 const ParameterList &pl = env->getParameters();
289 const Teuchos::ParameterEntry *pe;
291 std::string defString(
"default");
292 std::string objectOfInterest(defString);
293 pe = pl.getEntryPtr(
"objects_to_partition");
295 objectOfInterest = pe->getValue<std::string>(&objectOfInterest);
297 if (objectOfInterest == defString ||
298 objectOfInterest == std::string(
"mesh_nodes") )
300 else if (objectOfInterest == std::string(
"mesh_elements"))
318 const RCP<const Environment> env;
319 const RCP<const Comm<int> > problemComm;
320 #ifdef HAVE_ZOLTAN2_MPI 321 const MPI_Comm mpicomm;
323 const RCP<const base_adapter_t> adapter;
325 RCP<graphModel_t > model;
327 void buildModel(
bool isLocal);
330 static int setStrategy(SCOTCH_Strat * c_strat_ptr,
const ParameterList &pList,
int procRank);
334 template <
typename Adapter>
337 const ParameterList &pl = env->getParameters();
338 const Teuchos::ParameterEntry *pe;
340 std::string defString(
"default");
341 std::string symParameter(defString);
342 pe = pl.getEntryPtr(
"symmetrize_graph");
344 symParameter = pe->getValue<std::string>(&symParameter);
345 if (symParameter == std::string(
"transpose"))
347 else if (symParameter == std::string(
"bipartite"))
350 bool sgParameter =
false;
351 pe = pl.getEntryPtr(
"subset_graph");
353 sgParameter = pe->getValue(&sgParameter);
365 this->model = rcp(
new graphModel_t(this->adapter,
372 template <
typename Adapter>
378 this->buildModel(
false);
380 size_t numGlobalParts = solution->getTargetGlobalNumberOfParts();
382 SCOTCH_Num partnbr=0;
385 #ifdef HAVE_ZOLTAN2_MPI 387 int me = problemComm->getRank();
389 const SCOTCH_Num baseval = 0;
392 SCOTCH_Strat stratstr;
394 SCOTCH_stratInit(&stratstr);
397 SCOTCH_Dgraph *gr = SCOTCH_dgraphAlloc();
398 ierr = SCOTCH_dgraphInit(gr, mpicomm);
400 env->globalInputAssertion(__FILE__, __LINE__,
"SCOTCH_dgraphInit",
404 ArrayView<const gno_t> vtxID;
405 ArrayView<StridedData<lno_t, scalar_t> > vwgts;
406 size_t nVtx = model->getVertexList(vtxID, vwgts);
407 SCOTCH_Num vertlocnbr=0;
409 SCOTCH_Num vertlocmax = vertlocnbr;
412 ArrayView<const gno_t> edgeIds;
413 ArrayView<const offset_t> offsets;
414 ArrayView<StridedData<lno_t, scalar_t> > ewgts;
416 size_t nEdge = model->getEdgeList(edgeIds, offsets, ewgts);
418 SCOTCH_Num edgelocnbr=0;
420 const SCOTCH_Num edgelocsize = edgelocnbr;
422 SCOTCH_Num *vertloctab;
425 SCOTCH_Num *edgeloctab;
429 SCOTCH_Num *vendloctab = NULL;
430 SCOTCH_Num *vlblloctab = NULL;
431 SCOTCH_Num *edgegsttab = NULL;
434 SCOTCH_Num *velotab = NULL;
435 SCOTCH_Num *edlotab = NULL;
437 int nVwgts = model->getNumWeightsPerVertex();
438 int nEwgts = model->getNumWeightsPerEdge();
439 if (nVwgts > 1 && me == 0) {
440 std::cerr <<
"Warning: NumWeightsPerVertex is " << nVwgts
441 <<
" but Scotch allows only one weight. " 442 <<
" Zoltan2 will use only the first weight per vertex." 445 if (nEwgts > 1 && me == 0) {
446 std::cerr <<
"Warning: NumWeightsPerEdge is " << nEwgts
447 <<
" but Scotch allows only one weight. " 448 <<
" Zoltan2 will use only the first weight per edge." 453 velotab =
new SCOTCH_Num[nVtx+1];
455 scale_weights(nVtx, vwgts[0], velotab);
459 edlotab =
new SCOTCH_Num[nEdge+1];
461 scale_weights(nEdge, ewgts[0], edlotab);
465 ierr = SCOTCH_dgraphBuild(gr, baseval, vertlocnbr, vertlocmax,
466 vertloctab, vendloctab, velotab, vlblloctab,
467 edgelocnbr, edgelocsize,
468 edgeloctab, edgegsttab, edlotab);
470 env->globalInputAssertion(__FILE__, __LINE__,
"SCOTCH_dgraphBuild",
474 SCOTCH_Num *partloctab =
new SCOTCH_Num[nVtx+1];
479 float *partsizes =
new float[numGlobalParts];
480 if (!solution->criteriaHasUniformPartSizes(0))
481 for (
size_t i=0; i<numGlobalParts; i++)
482 partsizes[i] = solution->getCriteriaPartSize(0, i);
484 for (
size_t i=0; i<numGlobalParts; i++)
485 partsizes[i] = 1.0 /
float(numGlobalParts);
489 SCOTCH_archInit(&archdat);
491 SCOTCH_Num velosum = 0;
492 SCOTCH_dgraphSize (gr, &velosum, NULL, NULL, NULL);
493 SCOTCH_Num *goalsizes =
new SCOTCH_Num[partnbr];
499 for (SCOTCH_Num i = 0; i < partnbr; i++)
500 goalsizes[i] = SCOTCH_Num(ceil(velosum * partsizes[i]));
503 SCOTCH_archCmpltw(&archdat, partnbr, goalsizes);
506 ierr = SCOTCH_dgraphMap(gr, &archdat, &stratstr, partloctab);
508 env->globalInputAssertion(__FILE__, __LINE__,
"SCOTCH_dgraphMap",
511 SCOTCH_archExit(&archdat);
516 #ifdef SHOW_ZOLTAN2_SCOTCH_MEMORY 517 int me = env->comm_->getRank();
520 #ifdef HAVE_SCOTCH_ZOLTAN2_GETMEMORYMAX 522 size_t scotchBytes = SCOTCH_getMemoryMax();
523 std::cout <<
"Rank " << me <<
": Maximum bytes used by Scotch: ";
524 std::cout << scotchBytes << std::endl;
529 SCOTCH_dgraphExit(gr);
531 SCOTCH_stratExit(&stratstr);
535 ArrayRCP<part_t> partList;
540 solution->setParts(partList);
542 env->memory(
"Zoltan2-Scotch: After creating solution");
548 if (nVwgts)
delete [] velotab;
549 if (nEwgts)
delete [] edlotab;
551 #else // DO NOT HAVE MPI 559 ArrayView<const gno_t> vtxID;
560 ArrayView<StridedData<lno_t, scalar_t> > vwgts;
561 size_t nVtx = model->getVertexList(vtxID, vwgts);
563 ArrayRCP<part_t> partList(
new part_t[nVtx], 0, nVtx,
true);
564 for (
size_t i = 0; i < nVtx; i++) partList[i] = 0;
566 solution->setParts(partList);
568 #endif // DO NOT HAVE MPI 581 template <
typename Adapter>
588 const double INT_EPSILON = 1e-5;
590 SCOTCH_Num nonint, nonint_local = 0;
591 double sum_wgt, sum_wgt_local = 0.;
592 double max_wgt, max_wgt_local = 0.;
596 for (
size_t i = 0; i < n; i++) {
597 double fw = double(fwgts[i]);
599 SCOTCH_Num tmp = (SCOTCH_Num) floor(fw + .5);
600 if (fabs((
double)tmp-fw) > INT_EPSILON) {
605 if (fw > max_wgt_local) max_wgt_local = fw;
608 Teuchos::reduceAll<int,SCOTCH_Num>(*problemComm, Teuchos::REDUCE_MAX, 1,
609 &nonint_local, &nonint);
610 Teuchos::reduceAll<int,double>(*problemComm, Teuchos::REDUCE_SUM, 1,
611 &sum_wgt_local, &sum_wgt);
612 Teuchos::reduceAll<int,double>(*problemComm, Teuchos::REDUCE_MAX, 1,
613 &max_wgt_local, &max_wgt);
616 const double max_wgt_sum = double(SCOTCH_NUMMAX/8);
620 if (nonint || (max_wgt <= INT_EPSILON) || (sum_wgt > max_wgt_sum)) {
622 if (sum_wgt != 0.) scale = max_wgt_sum/sum_wgt;
626 for (
size_t i = 0; i < n; i++)
627 iwgts[i] = (SCOTCH_Num) ceil(
double(fwgts[i])*scale);
631 template <
typename Adapter>
634 bool bPrintOutput =
false;
635 const Teuchos::ParameterEntry *pe;
638 pe = pList.getEntryPtr(
"scotch_verbose");
640 bPrintOutput = pe->getValue(&bPrintOutput);
645 bool scotch_ordering_default =
true;
646 pe = pList.getEntryPtr(
"scotch_ordering_default");
648 scotch_ordering_default = pe->getValue(&scotch_ordering_default);
652 "Scotch: Ordering default setting (parameter: scotch_ordering_default): " 653 << (scotch_ordering_default ?
"True" :
"False" ) << std::endl;
659 if (scotch_ordering_default) {
661 int scotch_level = 0;
662 pe = pList.getEntryPtr(
"scotch_level");
664 scotch_level = pe->getValue(&scotch_level);
667 std::cout <<
"Scotch: Ordering level (parameter: scotch_level): " <<
668 scotch_level << std::endl;
672 double scotch_imbalance_ratio = 0.2;
673 pe = pList.getEntryPtr(
"scotch_imbalance_ratio");
675 scotch_imbalance_ratio = pe->getValue(&scotch_imbalance_ratio);
678 std::cout <<
"Scotch: Ordering dissection imbalance ratio " 679 "(parameter: scotch_imbalance_ratio): " 680 << scotch_imbalance_ratio << std::endl;
683 SCOTCH_stratInit(c_strat_ptr);
685 ierr = SCOTCH_stratGraphOrderBuild( c_strat_ptr,
686 SCOTCH_STRATLEVELMAX | SCOTCH_STRATLEVELMIN |
687 SCOTCH_STRATLEAFSIMPLE | SCOTCH_STRATSEPASIMPLE,
688 scotch_level, scotch_imbalance_ratio);
692 std::string scotch_ordering_strategy_string(
"");
693 pe = pList.getEntryPtr(
"scotch_ordering_strategy");
695 scotch_ordering_strategy_string =
696 pe->getValue(&scotch_ordering_strategy_string);
699 std::cout <<
"Scotch ordering strategy" 700 " (parameter: scotch_ordering_strategy): " <<
701 scotch_ordering_strategy_string << std::endl;
704 SCOTCH_stratInit(c_strat_ptr);
705 ierr = SCOTCH_stratGraphOrder( c_strat_ptr,
706 scotch_ordering_strategy_string.c_str());
712 template <
typename Adapter>
715 throw std::logic_error(
"AlgPTScotch does not yet support global ordering.");
718 template <
typename Adapter>
727 int me = problemComm->getRank();
728 const ParameterList &pl = env->getParameters();
729 const Teuchos::ParameterEntry *pe;
731 bool isVerbose =
false;
732 pe = pl.getEntryPtr(
"scotch_verbose");
734 isVerbose = pe->getValue(&isVerbose);
737 this->buildModel(
true);
738 if (isVerbose && me==0) {
739 std::cout <<
"Built local graph model." << std::endl;
743 SCOTCH_Strat c_strat_ptr;
744 SCOTCH_Graph c_graph_ptr;
747 ierr = SCOTCH_graphInit( &c_graph_ptr);
749 throw std::runtime_error(
"Failed to initialize Scotch graph!");
750 }
else if (isVerbose && me == 0) {
751 std::cout <<
"Initialized Scotch graph." << std::endl;
755 ArrayView<const gno_t> vtxID;
756 ArrayView<StridedData<lno_t, scalar_t> > vwgts;
757 size_t nVtx = model->getVertexList(vtxID, vwgts);
758 SCOTCH_Num vertnbr=0;
762 ArrayView<const gno_t> edgeIds;
763 ArrayView<const offset_t> offsets;
764 ArrayView<StridedData<lno_t, scalar_t> > ewgts;
766 size_t nEdge = model->getEdgeList(edgeIds, offsets, ewgts);
767 SCOTCH_Num edgenbr=0;
777 SCOTCH_Num *vendtab = NULL;
780 SCOTCH_Num *velotab = NULL;
781 SCOTCH_Num *vlbltab = NULL;
782 SCOTCH_Num *edlotab = NULL;
784 int nVwgts = model->getNumWeightsPerVertex();
785 int nEwgts = model->getNumWeightsPerEdge();
786 if (nVwgts > 1 && me == 0) {
787 std::cerr <<
"Warning: NumWeightsPerVertex is " << nVwgts
788 <<
" but Scotch allows only one weight. " 789 <<
" Zoltan2 will use only the first weight per vertex." 792 if (nEwgts > 1 && me == 0) {
793 std::cerr <<
"Warning: NumWeightsPerEdge is " << nEwgts
794 <<
" but Scotch allows only one weight. " 795 <<
" Zoltan2 will use only the first weight per edge." 800 velotab =
new SCOTCH_Num[nVtx+1];
802 scale_weights(nVtx, vwgts[0], velotab);
806 edlotab =
new SCOTCH_Num[nEdge+1];
808 scale_weights(nEdge, ewgts[0], edlotab);
814 ierr = SCOTCH_graphBuild( &c_graph_ptr, baseval,
815 vertnbr, verttab, vendtab, velotab, vlbltab,
816 edgenbr, edgetab, edlotab);
818 throw std::runtime_error(
"Failed to build Scotch graph!");
819 }
else if (isVerbose && me == 0) {
820 std::cout <<
"Built Scotch graph." << std::endl;
823 ierr = SCOTCH_graphCheck(&c_graph_ptr);
825 throw std::runtime_error(
"Graph is inconsistent!");
826 }
else if (isVerbose && me == 0) {
827 std::cout <<
"Graph is consistent." << std::endl;
834 throw std::runtime_error(
"Can't build strategy!");
835 }
else if (isVerbose && me == 0) {
836 std::cout <<
"Graphing strategy built." << std::endl;
843 SCOTCH_Num *rangetab;
847 permtab =
reinterpret_cast<SCOTCH_Num*
>(solution->getPermutationView(
false));
848 peritab =
reinterpret_cast<SCOTCH_Num*
>(solution->getPermutationView(
true));
849 rangetab =
reinterpret_cast<SCOTCH_Num*
>(solution->getSeparatorRangeView());
850 treetab =
reinterpret_cast<SCOTCH_Num*
>(solution->getSeparatorTreeView());
853 permtab =
new SCOTCH_Num[nVtx];
854 peritab =
new SCOTCH_Num[nVtx];
855 rangetab =
new SCOTCH_Num[nVtx+1];
856 treetab =
new SCOTCH_Num[nVtx];
859 ierr = SCOTCH_graphOrder(&c_graph_ptr, &c_strat_ptr, permtab, peritab,
860 &cblk, rangetab, treetab);
862 throw std::runtime_error(
"Could not compute ordering!!");
863 }
else if(isVerbose && me == 0) {
864 std::cout <<
"Ordering computed." << std::endl;
869 solution->setNumSeparatorBlocks(nSepBlocks);
873 const ArrayRCP<lno_t> arv_perm = solution->getPermutationRCP(
false);
874 for (
size_t i = 0; i < nVtx; i++)
878 const ArrayRCP<lno_t> arv_peri = solution->getPermutationRCP(
true);
879 for (
size_t i = 0; i < nVtx; i++)
883 const ArrayRCP<lno_t> arv_range = solution->getSeparatorRangeRCP();
884 for (
lno_t i = 0; i <= nSepBlocks; i++)
888 const ArrayRCP<lno_t> arv_tree = solution->getSeparatorTreeRCP();
889 for (
lno_t i = 0; i < nSepBlocks; i++)
894 solution->setHaveSeparator(
true);
901 if (nVwgts)
delete [] velotab;
902 if (nEwgts)
delete [] edlotab;
904 SCOTCH_stratExit(&c_strat_ptr);
905 SCOTCH_graphFree(&c_graph_ptr);
907 if (isVerbose && problemComm->getRank() == 0) {
908 std::cout <<
"Freed Scotch graph!" << std::endl;
915 #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