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);
340 auto vertex2AggId = aggregates->
GetVertex2AggId()->getLocalViewDevice(Xpetra::Access::ReadWrite);
341 auto procWinner = aggregates->
GetProcWinner()->getLocalViewDevice(Xpetra::Access::OverwriteAll);
342 int rank = comm->getRank();
343 Kokkos::parallel_for(
344 Kokkos::RangePolicy<exec_space>(0, numRows),
345 KOKKOS_LAMBDA(lno_t i) {
346 procWinner(i, 0) = rank;
347 if (aggStat(i) ==
READY) {
349 vertex2AggId(i, 0) = labels(i);
352 numNonAggregatedNodes = 0;
356 DoGraphColoring(currentLevel, aggAlgo, pL.
get<
bool>(
"aggregation: deterministic"), graph_kokkos, aggregates);
362 std::vector<GO> localStats;
364 localStats = std::vector<GO>(1 + 2 * algos_.size());
365 localStats[0] = numRows;
367 for (
size_t a = 0; a < algos_.size(); a++) {
368 std::string phase = algos_[a]->description();
370 SubFactoryMonitor sfm2(*
this,
"Algo \"" + phase +
"\"" + (numNonAggregatedNodes == 0 ?
" [skipped since no nodes are left to aggregate]" :
""), currentLevel);
371 int oldRank = algos_[a]->SetProcRankVerbose(this->GetProcRankVerbose());
372 if (numNonAggregatedNodes > 0) {
374 algos_[a]->BuildAggregatesNonKokkos(pL, *graph, *aggregates, aggStatHost, numNonAggregatedNodes);
376 algos_[a]->BuildAggregates(pL, *graph_kokkos, *aggregates, aggStat, numNonAggregatedNodes);
378 algos_[a]->SetProcRankVerbose(oldRank);
381 localStats[2 * a + 1] = numRows - numNonAggregatedNodes;
386 std::vector<GO> globalStats(1 + 2 * algos_.size());
387 Teuchos::reduceAll(*comm,
Teuchos::REDUCE_SUM, (
int)localStats.size(), localStats.data(), globalStats.data());
388 GO numGlobalRows = globalStats[0];
389 GO numGlobalAggregatedPrev = 0, numGlobalAggsPrev = 0;
390 std::stringstream ss;
391 for (
size_t a = 0; a < algos_.size(); a++) {
392 std::string phase = algos_[a]->description();
393 GO numGlobalAggregated = globalStats[2 * a + 1];
394 GO numGlobalAggs = globalStats[2 * a + 2];
395 GO numGlobalNonAggregatedNodes = numGlobalRows - numGlobalAggregatedPrev;
396 double aggPercent = 100 * as<double>(numGlobalAggregated) / as<double>(numGlobalRows);
397 if (aggPercent > 99.99 && aggPercent < 100.00) {
405 ss <<
"Algo \"" + phase +
"\"" + (numGlobalNonAggregatedNodes == 0 ?
" [skipped since no nodes are left to aggregate]" :
"") << std::endl
406 <<
" aggregated : " << (numGlobalAggregated - numGlobalAggregatedPrev) <<
" (phase), " << std::fixed
407 << std::setprecision(2) << numGlobalAggregated <<
"/" << numGlobalRows <<
" [" << aggPercent <<
"%] (total)\n"
408 <<
" remaining : " << numGlobalRows - numGlobalAggregated <<
"\n"
409 <<
" aggregates : " << numGlobalAggs - numGlobalAggsPrev <<
" (phase), " << numGlobalAggs <<
" (total)" << std::endl;
410 numGlobalAggregatedPrev = numGlobalAggregated;
411 numGlobalAggsPrev = numGlobalAggs;
422 Set(currentLevel,
"Aggregates", aggregates);
425 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
428 const std::string& aggAlgo,
429 const bool deterministic,
440 using KernelHandle = KokkosKernels::Experimental::
441 KokkosKernelsHandle<
typename graph_t::row_map_type::value_type,
442 typename graph_t::entries_type::value_type,
443 typename graph_t::entries_type::value_type,
444 typename graph_t::device_type::execution_space,
445 typename graph_t::device_type::memory_space,
446 typename graph_t::device_type::memory_space>;
449 kh.create_distance2_graph_coloring_handle();
452 auto coloringHandle = kh.get_distance2_graph_coloring_handle();
465 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_SERIAL);
467 }
else if (aggAlgo ==
"serial") {
468 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_SERIAL);
470 }
else if (aggAlgo ==
"default") {
471 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_DEFAULT);
473 }
else if (aggAlgo ==
"vertex based") {
474 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_VB);
476 }
else if (aggAlgo ==
"vertex based bit set") {
477 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_VB_BIT);
479 }
else if (aggAlgo ==
"edge filtering") {
480 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_VB_BIT_EF);
482 }
else if (aggAlgo ==
"net based bit set") {
483 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_NB_BIT);
486 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")
490 typename graph_t::row_map_type aRowptrs = graph->
getRowPtrs();
491 typename graph_t::entries_type aColinds = graph->
getEntries();
496 SubFactoryMonitor sfm2(*
this,
"Algo \"Graph Coloring\": KokkosGraph Call", currentLevel);
497 KokkosGraph::Experimental::graph_color_distance2(&kh, numRows, aRowptrs, aColinds);
502 aggregates->
SetGraphNumColors(static_cast<LO>(coloringHandle->get_num_colors()));
505 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.
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.