10 #ifndef MUELU_UNCOUPLEDAGGREGATIONFACTORY_DEF_HPP_
11 #define MUELU_UNCOUPLEDAGGREGATIONFACTORY_DEF_HPP_
15 #include <Xpetra_Map.hpp>
17 #include <Xpetra_MultiVectorFactory.hpp>
23 #include "MueLu_InterfaceAggregationAlgorithm.hpp"
24 #include "MueLu_OnePtAggregationAlgorithm.hpp"
25 #include "MueLu_PreserveDirichletAggregationAlgorithm.hpp"
27 #include "MueLu_AggregationPhase1Algorithm.hpp"
28 #include "MueLu_AggregationPhase2aAlgorithm.hpp"
29 #include "MueLu_AggregationPhase2bAlgorithm.hpp"
30 #include "MueLu_AggregationPhase3Algorithm.hpp"
33 #include "MueLu_LWGraph.hpp"
34 #include "MueLu_Aggregates.hpp"
38 #include "KokkosGraph_Distance2ColorHandle.hpp"
39 #include "KokkosGraph_Distance2Color.hpp"
40 #include "KokkosGraph_MIS2.hpp"
44 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
46 : bDefinitionPhase_(true) {}
48 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
51 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
58 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
77 SET_VALID_ENTRY(
"aggregation: error on nodes with no on-rank neighbors");
82 #undef SET_VALID_ENTRY
86 validParamList->
set<
RCP<const FactoryBase>>(
"DofsPerNode", null,
"Generating factory for variable \'DofsPerNode\', usually the same as for \'Graph\'");
89 validParamList->
set<std::string>(
"OnePt aggregate map name",
"",
"Name of input map for single node aggregates. (default='')");
90 validParamList->
set<std::string>(
"OnePt aggregate map factory",
"",
"Generating factory of (DOF) map for single node aggregates.");
95 validParamList->
set<std::string>(
"Interface aggregate map name",
"",
"Name of input map for interface aggregates. (default='')");
96 validParamList->
set<std::string>(
"Interface aggregate map factory",
"",
"Generating factory of (DOF) map for interface aggregates.");
97 validParamList->
set<
RCP<const FactoryBase>>(
"nodeOnInterface", Teuchos::null,
"Array specifying whether or not a node is on the interface (1 or 0).");
99 return validParamList;
102 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
104 Input(currentLevel,
"Graph");
105 Input(currentLevel,
"DofsPerNode");
110 std::string mapOnePtName = pL.
get<std::string>(
"OnePt aggregate map name");
111 if (mapOnePtName.length() > 0) {
112 std::string mapOnePtFactName = pL.
get<std::string>(
"OnePt aggregate map factory");
113 if (mapOnePtFactName ==
"" || mapOnePtFactName ==
"NoFactory") {
122 if (pL.
get<
bool>(
"aggregation: use interface aggregation") ==
true) {
129 "nodeOnInterface was not provided by the user on level0!");
132 Input(currentLevel,
"nodeOnInterface");
137 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
142 bDefinitionPhase_ =
false;
144 if (pL.
get<
int>(
"aggregation: max agg size") == -1)
145 pL.
set(
"aggregation: max agg size", INT_MAX);
160 std::string mapOnePtName = pL.
get<std::string>(
"OnePt aggregate map name");
162 if (mapOnePtName.length()) {
163 std::string mapOnePtFactName = pL.
get<std::string>(
"OnePt aggregate map factory");
164 if (mapOnePtFactName ==
"" || mapOnePtFactName ==
"NoFactory") {
168 OnePtMap = currentLevel.
Get<
RCP<Map>>(mapOnePtName, mapOnePtFact.
get());
173 std::string mapInterfaceName = pL.
get<std::string>(
"Interface aggregate map name");
174 RCP<Map> InterfaceMap = Teuchos::null;
182 const std::string aggregationBackend = pL.
get<std::string>(
"aggregation: backend");
194 if ((aggregationBackend ==
"default") || (aggregationBackend ==
"non-Kokkos")) {
195 graph = Get<RCP<LWGraph>>(currentLevel,
"Graph");
201 RCP<LWGraph> tmp_graph = Get<RCP<LWGraph>>(currentLevel,
"Graph");
204 comm = graph_kokkos->GetComm();
205 numRows = graph_kokkos->GetNodeNumVertices();
209 if ((aggregationBackend ==
"default") || (aggregationBackend ==
"Kokkos")) {
210 graph_kokkos = Get<RCP<LWGraph_kokkos>>(currentLevel,
"Graph");
212 comm = graph_kokkos->
GetComm();
219 comm = graph->GetComm();
220 numRows = graph->GetNodeNumVertices();
228 TEUCHOS_TEST_FOR_EXCEPTION(pL.
get<
bool>(
"aggregation: use interface aggregation"), std::invalid_argument,
"Option: 'aggregation: use interface aggregation' is not supported in the Kokkos version of uncoupled aggregation");
230 TEUCHOS_TEST_FOR_EXCEPTION(pL.
get<
bool>(
"aggregation: match ML phase1"), std::invalid_argument,
"Option: 'aggregation: match ML phase1' is not supported in the Kokkos version of uncoupled aggregation");
239 AggStatHostType aggStatHost;
243 aggStatHost = AggStatHostType(Kokkos::ViewAllocateWithoutInitializing(
"aggregation status"), numRows);
244 Kokkos::deep_copy(aggStatHost,
READY);
246 aggStat = AggStatType(Kokkos::ViewAllocateWithoutInitializing(
"aggregation status"), numRows);
247 Kokkos::deep_copy(aggStat,
READY);
251 if (pL.
get<
bool>(
"aggregation: use interface aggregation") ==
true) {
253 for (
LO i = 0; i < numRows; i++) {
254 if (nodeOnInterface[i])
263 Kokkos::parallel_for(
264 "MueLu - UncoupledAggregation: tagging boundary nodes in aggStat",
265 Kokkos::RangePolicy<LocalOrdinal, typename LWGraph::execution_space>(0, numRows),
267 if (dirichletBoundaryMap(nodeIdx) ==
true) {
273 Kokkos::parallel_for(
274 "MueLu - UncoupledAggregation: tagging boundary nodes in aggStat",
275 Kokkos::RangePolicy<LocalOrdinal, typename LWGraph_kokkos::execution_space>(0, numRows),
277 if (dirichletBoundaryMap(nodeIdx) ==
true) {
284 if (OnePtMap != Teuchos::null) {
285 LO nDofsPerNode = Get<LO>(currentLevel,
"DofsPerNode");
289 for (
LO i = 0; i < numRows; i++) {
291 GO grid = (graph->
GetDomainMap()->getGlobalElement(i) - indexBase) * nDofsPerNode + indexBase;
293 for (
LO kr = 0; kr < nDofsPerNode; kr++)
294 if (OnePtMap->isNodeGlobalElement(grid + kr))
295 aggStatHost(i) =
ONEPT;
299 auto lclDomainMap = graph_kokkos->
GetDomainMap()->getLocalMap();
300 auto lclOnePtMap = OnePtMap->getLocalMap();
301 const LocalOrdinal INVALID = Tpetra::Details::OrdinalTraits<LocalOrdinal>::invalid();
302 Kokkos::parallel_for(
303 "MueLu - UncoupledAggregation: tagging OnePt map",
304 Kokkos::RangePolicy<LocalOrdinal, typename LWGraph_kokkos::execution_space>(0, numRows),
307 GO grid = (lclDomainMap.getGlobalElement(i) - indexBase) * nDofsPerNode + indexBase;
309 for (
LO kr = 0; kr < nDofsPerNode; kr++)
310 if (lclOnePtMap.getLocalElement(grid + kr) != INVALID)
316 LO numNonAggregatedNodes = numRows;
317 std::string aggAlgo = pL.
get<std::string>(
"aggregation: coloring algorithm");
318 if (aggAlgo ==
"mis2 coarsening" || aggAlgo ==
"mis2 aggregation") {
323 using device_t =
typename graph_t::device_type;
324 using exec_space =
typename device_t::execution_space;
325 using rowmap_t =
typename graph_t::row_map_type;
326 using colinds_t =
typename graph_t::entries_type;
327 using lno_t =
typename colinds_t::non_const_value_type;
328 rowmap_t aRowptrs = graph_kokkos->
getRowPtrs();
329 colinds_t aColinds = graph_kokkos->
getEntries();
331 typename colinds_t::non_const_type labels;
333 if (aggAlgo ==
"mis2 coarsening") {
335 labels = KokkosGraph::graph_mis2_coarsen<device_t, rowmap_t, colinds_t>(aRowptrs, aColinds, numAggs);
336 }
else if (aggAlgo ==
"mis2 aggregation") {
338 labels = KokkosGraph::graph_mis2_aggregate<device_t, rowmap_t, colinds_t>(aRowptrs, aColinds, numAggs);
343 Kokkos::View<bool*, typename device_t::memory_space> has_nodes(
"has_nodes", numAggs);
344 Kokkos::parallel_for(
345 Kokkos::RangePolicy<exec_space>(0, numRows),
346 KOKKOS_LAMBDA(lno_t i) {
347 if (aggStat(i) ==
READY)
348 Kokkos::atomic_assign(&has_nodes(labels(i)),
true);
352 Kokkos::View<LO*, typename device_t::memory_space> new_labels(
"new_labels", numAggs);
353 Kokkos::parallel_scan(
354 Kokkos::RangePolicy<exec_space>(0, numAggs),
355 KOKKOS_LAMBDA(lno_t i, lno_t & update,
const bool is_final) {
357 new_labels(i) = update;
364 Kokkos::parallel_for(
365 Kokkos::RangePolicy<exec_space>(0, numRows),
366 KOKKOS_LAMBDA(lno_t i) {
367 labels(i) = new_labels(labels(i));
371 auto vertex2AggId = aggregates->
GetVertex2AggId()->getLocalViewDevice(Xpetra::Access::ReadWrite);
372 auto procWinner = aggregates->
GetProcWinner()->getLocalViewDevice(Xpetra::Access::OverwriteAll);
373 int rank = comm->getRank();
374 Kokkos::parallel_for(
375 Kokkos::RangePolicy<exec_space>(0, numRows),
376 KOKKOS_LAMBDA(lno_t i) {
377 if (aggStat(i) ==
READY) {
378 #ifdef HAVE_MUELU_DEBUG
379 KOKKOS_ASSERT(labels(i) >= 0);
381 procWinner(i, 0) = rank;
383 vertex2AggId(i, 0) = labels(i);
391 numNonAggregatedNodes = 0;
395 DoGraphColoring(currentLevel, aggAlgo, pL.
get<
bool>(
"aggregation: deterministic"), graph_kokkos, aggregates);
401 std::vector<GO> localStats;
403 localStats = std::vector<GO>(1 + 2 * algos_.size());
404 localStats[0] = numRows;
406 for (
size_t a = 0; a < algos_.size(); a++) {
407 std::string phase = algos_[a]->description();
409 SubFactoryMonitor sfm2(*
this,
"Algo \"" + phase +
"\"" + (numNonAggregatedNodes == 0 ?
" [skipped since no nodes are left to aggregate]" :
""), currentLevel);
410 int oldRank = algos_[a]->SetProcRankVerbose(this->GetProcRankVerbose());
411 if (numNonAggregatedNodes > 0) {
413 algos_[a]->BuildAggregatesNonKokkos(pL, *graph, *aggregates, aggStatHost, numNonAggregatedNodes);
415 algos_[a]->BuildAggregates(pL, *graph_kokkos, *aggregates, aggStat, numNonAggregatedNodes);
417 algos_[a]->SetProcRankVerbose(oldRank);
420 localStats[2 * a + 1] = numRows - numNonAggregatedNodes;
425 std::vector<GO> globalStats(1 + 2 * algos_.size());
426 Teuchos::reduceAll(*comm,
Teuchos::REDUCE_SUM, (
int)localStats.size(), localStats.data(), globalStats.data());
427 GO numGlobalRows = globalStats[0];
428 GO numGlobalAggregatedPrev = 0, numGlobalAggsPrev = 0;
429 std::stringstream ss;
430 for (
size_t a = 0; a < algos_.size(); a++) {
431 std::string phase = algos_[a]->description();
432 GO numGlobalAggregated = globalStats[2 * a + 1];
433 GO numGlobalAggs = globalStats[2 * a + 2];
434 GO numGlobalNonAggregatedNodes = numGlobalRows - numGlobalAggregatedPrev;
435 double aggPercent = 100 * as<double>(numGlobalAggregated) / as<double>(numGlobalRows);
436 if (aggPercent > 99.99 && aggPercent < 100.00) {
444 ss <<
"Algo \"" + phase +
"\"" + (numGlobalNonAggregatedNodes == 0 ?
" [skipped since no nodes are left to aggregate]" :
"") << std::endl
445 <<
" aggregated : " << (numGlobalAggregated - numGlobalAggregatedPrev) <<
" (phase), " << std::fixed
446 << std::setprecision(2) << numGlobalAggregated <<
"/" << numGlobalRows <<
" [" << aggPercent <<
"%] (total)\n"
447 <<
" remaining : " << numGlobalRows - numGlobalAggregated <<
"\n"
448 <<
" aggregates : " << numGlobalAggs - numGlobalAggsPrev <<
" (phase), " << numGlobalAggs <<
" (total)" << std::endl;
449 numGlobalAggregatedPrev = numGlobalAggregated;
450 numGlobalAggsPrev = numGlobalAggs;
461 Set(currentLevel,
"Aggregates", aggregates);
464 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
467 const std::string& aggAlgo,
468 const bool deterministic,
479 using KernelHandle = KokkosKernels::Experimental::
480 KokkosKernelsHandle<
typename graph_t::row_map_type::value_type,
481 typename graph_t::entries_type::value_type,
482 typename graph_t::entries_type::value_type,
483 typename graph_t::device_type::execution_space,
484 typename graph_t::device_type::memory_space,
485 typename graph_t::device_type::memory_space>;
488 kh.create_distance2_graph_coloring_handle();
491 auto coloringHandle = kh.get_distance2_graph_coloring_handle();
504 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_SERIAL);
506 }
else if (aggAlgo ==
"serial") {
507 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_SERIAL);
509 }
else if (aggAlgo ==
"default") {
510 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_DEFAULT);
512 }
else if (aggAlgo ==
"vertex based") {
513 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_VB);
515 }
else if (aggAlgo ==
"vertex based bit set") {
516 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_VB_BIT);
518 }
else if (aggAlgo ==
"edge filtering") {
519 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_VB_BIT_EF);
521 }
else if (aggAlgo ==
"net based bit set") {
522 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_NB_BIT);
525 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unrecognized distance 2 coloring algorithm, valid options are: serial, default, matrix squared, vertex based, vertex based bit set, edge filtering")
529 typename graph_t::row_map_type aRowptrs = graph->
getRowPtrs();
530 typename graph_t::entries_type aColinds = graph->
getEntries();
535 SubFactoryMonitor sfm2(*
this,
"Algo \"Graph Coloring\": KokkosGraph Call", currentLevel);
536 KokkosGraph::Experimental::graph_color_distance2(&kh, numRows, aRowptrs, aColinds);
541 aggregates->
SetGraphNumColors(static_cast<LO>(coloringHandle->get_num_colors()));
544 kh.destroy_distance2_graph_coloring_handle();
Kokkos::View< unsigned *, typename LWGraphHostType::device_type > AggStatHostType
Algorithm for coarsening a graph with uncoupled aggregation. keep special marked nodes as singleton n...
RCP< MueLu::LWGraph< LocalOrdinal, GlobalOrdinal, Node > > copyToHost()
MueLu::DefaultLocalOrdinal LocalOrdinal
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access). Usage: Level->Get< RCP<Matrix> >("A", factory) if factory == NULL => use default factory.
void DoGraphColoring(Level ¤tLevel, const std::string &aggAlgo, const bool deterministic, const RCP< const LWGraph_kokkos > graph, RCP< Aggregates > aggregates) const
const RCP< LOVector > & GetProcWinner() const
Returns constant vector that maps local node IDs to owning processor IDs.
KOKKOS_INLINE_FUNCTION row_type getRowPtrs() const
Return the row pointers of the local graph.
void SetGraphNumColors(const LO graphNumColors)
Set the number of colors needed by the distance 2 coloring.
Container class for aggregation information.
KOKKOS_INLINE_FUNCTION LO GetNumAggregates() const
typename std::conditional< OnHost, typename local_graph_device_type::HostMirror, local_graph_device_type >::type local_graph_type
void setValidator(RCP< const ParameterEntryValidator > const &validator)
virtual ~UncoupledAggregationFactory()
Destructor.
T & get(const std::string &name, T def_value)
Timer to be used in factories. Similar to Monitor but with additional timers.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
KOKKOS_INLINE_FUNCTION size_type GetNodeNumVertices() const
Return number of graph vertices.
KOKKOS_INLINE_FUNCTION const boundary_nodes_type GetBoundaryNodeMap() const
Returns map with global ids of boundary nodes.
void DeclareInput(Level ¤tLevel) const
Input.
static const NoFactory * get()
Algorithm for coarsening a graph with uncoupled aggregation. creates aggregates along an interface us...
Builds one-to-one aggregates for all Dirichlet boundary nodes. For some applications this might be ne...
LO GetGraphNumColors()
Get the number of colors needed by the distance 2 coloring.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Class that holds all level-specific information.
Timer to be used in factories. Similar to SubMonitor but adds a timer level by level.
#define MUELU_UNAGGREGATED
KOKKOS_INLINE_FUNCTION entries_type getEntries() const
Return the list entries in the local graph.
void SetGraphColors(colors_view_type graphColors)
Set a distance 2 coloring of the underlying graph. The coloring is computed and set during Phase1 of ...
virtual void setObjectLabel(const std::string &objectLabel)
const RCP< LOMultiVector > & GetVertex2AggId() const
Returns constant vector that maps local node IDs to local aggregates IDs.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
#define SET_VALID_ENTRY(name)
UncoupledAggregationFactory()
Constructor.
Among unaggregated points, see if we can make a reasonable size aggregate out of it.IdeaAmong unaggregated points, see if we can make a reasonable size aggregate out of it. We do this by looking at neighbors and seeing how many are unaggregated and on my processor. Loosely, base the number of new aggregates created on the percentage of unaggregated nodes.
void Build(Level ¤tLevel) const
Build aggregates.
Add leftovers to existing aggregatesIdeaIn phase 2b non-aggregated nodes are added to existing aggreg...
RCP< MueLu::LWGraph_kokkos< LocalOrdinal, GlobalOrdinal, Node > > copyToDevice()
const RCP< const Map > GetDomainMap() const
KOKKOS_INLINE_FUNCTION void AggregatesCrossProcessors(const bool &flag)
Record whether aggregates include DOFs from other processes.
Algorithm for coarsening a graph with uncoupled aggregation.
int GetLevelID() const
Return level number.
Exception throws to report errors in the internal logical of the program.
#define TEUCHOS_ASSERT(assertion_test)
Handle leftover nodes. Try to avoid singleton nodesIdeaIn phase 3 we try to stick unaggregated nodes ...
ParameterEntry & getEntry(const std::string &name)
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput()
const RCP< const Teuchos::Comm< int > > GetComm() const
aggregates_sizes_type::const_type ComputeAggregateSizes(bool forceRecompute=false) const
Compute sizes of aggregates.
Kokkos::View< unsigned *, typename LWGraphType::device_type > AggStatType
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need's value has been saved.
void SetNumAggregates(LO nAggregates)
Set number of local aggregates on current processor.