145 if (pL.get<
int>(
"aggregation: max agg size") == -1)
146 pL.set(
"aggregation: max agg size", INT_MAX);
149 RCP<const FactoryBase> graphFact =
GetFactory(
"Graph");
161 std::string mapOnePtName = pL.get<std::string>(
"OnePt aggregate map name");
162 RCP<Map> OnePtMap = Teuchos::null;
163 if (mapOnePtName.length()) {
164 std::string mapOnePtFactName = pL.get<std::string>(
"OnePt aggregate map factory");
165 if (mapOnePtFactName ==
"" || mapOnePtFactName ==
"NoFactory") {
168 RCP<const FactoryBase> mapOnePtFact =
GetFactory(mapOnePtFactName);
169 OnePtMap = currentLevel.
Get<RCP<Map>>(mapOnePtName, mapOnePtFact.get());
174 std::string mapInterfaceName = pL.get<std::string>(
"Interface aggregate map name");
175 RCP<Map> InterfaceMap = Teuchos::null;
177 RCP<const LWGraph> graph;
178 RCP<const LWGraph_kokkos> graph_kokkos;
179 RCP<Aggregates> aggregates;
180 RCP<const Teuchos::Comm<int>> comm;
183 const std::string aggregationBackend = pL.get<std::string>(
"aggregation: backend");
184 const std::string aggAlgo = pL.get<std::string>(
"aggregation: coloring algorithm");
195 if (
IsType<RCP<LWGraph>>(currentLevel,
"Graph")) {
196 if ((aggregationBackend ==
"default") || (aggregationBackend ==
"host")) {
199 comm = graph->GetComm();
200 numRows = graph->GetNodeNumVertices();
204 graph_kokkos = tmp_graph->copyToDevice();
205 aggregates = rcp(
new Aggregates(*graph_kokkos));
206 comm = graph_kokkos->GetComm();
207 numRows = graph_kokkos->GetNodeNumVertices();
210 }
else if (
IsType<RCP<LWGraph_kokkos>>(currentLevel,
"Graph")) {
211 if ((aggregationBackend ==
"default") || (aggregationBackend ==
"kokkos")) {
213 aggregates = rcp(
new Aggregates(*graph_kokkos));
214 comm = graph_kokkos->GetComm();
215 numRows = graph_kokkos->GetNodeNumVertices();
219 graph = tmp_graph_kokkos->copyToHost();
221 comm = graph->GetComm();
222 numRows = graph->GetNodeNumVertices();
226 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Graph has bad type.");
230 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");
231 if (aggAlgo !=
"mis2 coarsening" && aggAlgo !=
"mis2 aggregation") {
233 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");
238 aggregates->setObjectLabel(
"UC");
243 AggStatHostType aggStatHost;
247 aggStatHost = AggStatHostType(Kokkos::ViewAllocateWithoutInitializing(
"aggregation status"), numRows);
248 Kokkos::deep_copy(aggStatHost,
READY);
250 aggStat = AggStatType(Kokkos::ViewAllocateWithoutInitializing(
"aggregation status"), numRows);
251 Kokkos::deep_copy(aggStat,
READY);
255 if (pL.get<
bool>(
"aggregation: use interface aggregation") ==
true) {
256 Teuchos::Array<LO> nodeOnInterface =
Get<Array<LO>>(currentLevel,
"nodeOnInterface");
257 for (LO i = 0; i < numRows; i++) {
258 if (nodeOnInterface[i])
266 auto dirichletBoundaryMap = graph->GetBoundaryNodeMap();
267 Kokkos::parallel_for(
268 "MueLu - UncoupledAggregation: tagging boundary nodes in aggStat",
269 Kokkos::RangePolicy<LocalOrdinal, typename LWGraph::execution_space>(0, numRows),
271 if (dirichletBoundaryMap(nodeIdx) ==
true) {
276 auto dirichletBoundaryMap = graph_kokkos->GetBoundaryNodeMap();
277 Kokkos::parallel_for(
278 "MueLu - UncoupledAggregation: tagging boundary nodes in aggStat",
279 Kokkos::RangePolicy<LocalOrdinal, typename LWGraph_kokkos::execution_space>(0, numRows),
281 if (dirichletBoundaryMap(nodeIdx) ==
true) {
288 if (OnePtMap != Teuchos::null) {
289 LO nDofsPerNode =
Get<LO>(currentLevel,
"DofsPerNode");
292 GO indexBase = graph->GetDomainMap()->getIndexBase();
293 for (LO i = 0; i < numRows; i++) {
295 GO grid = (graph->GetDomainMap()->getGlobalElement(i) - indexBase) * nDofsPerNode + indexBase;
297 for (LO kr = 0; kr < nDofsPerNode; kr++)
298 if (OnePtMap->isNodeGlobalElement(grid + kr))
299 aggStatHost(i) =
ONEPT;
302 GO indexBase = graph_kokkos->GetDomainMap()->getIndexBase();
303 auto lclDomainMap = graph_kokkos->GetDomainMap()->getLocalMap();
304 auto lclOnePtMap = OnePtMap->getLocalMap();
305 const LocalOrdinal INVALID = Tpetra::Details::OrdinalTraits<LocalOrdinal>::invalid();
306 Kokkos::parallel_for(
307 "MueLu - UncoupledAggregation: tagging OnePt map",
308 Kokkos::RangePolicy<LocalOrdinal, typename LWGraph_kokkos::execution_space>(0, numRows),
311 GO grid = (lclDomainMap.getGlobalElement(i) - indexBase) * nDofsPerNode + indexBase;
313 for (LO kr = 0; kr < nDofsPerNode; kr++)
314 if (lclOnePtMap.getLocalElement(grid + kr) != INVALID)
320 LO numNonAggregatedNodes = numRows;
321 if (aggAlgo ==
"mis2 coarsening" || aggAlgo ==
"mis2 aggregation") {
322 TEUCHOS_ASSERT(!runOnHost);
326 using device_t =
typename graph_t::device_type;
327 using exec_space =
typename device_t::execution_space;
328 using rowmap_t =
typename graph_t::row_map_type;
329 using colinds_t =
typename graph_t::entries_type;
330 using lno_t =
typename colinds_t::non_const_value_type;
331 rowmap_t aRowptrs = graph_kokkos->getRowPtrs();
332 colinds_t aColinds = graph_kokkos->getEntries();
334 typename colinds_t::non_const_type labels;
336 if (aggAlgo ==
"mis2 coarsening") {
338 labels = KokkosGraph::graph_mis2_coarsen<device_t, rowmap_t, colinds_t>(aRowptrs, aColinds, numAggs);
339 }
else if (aggAlgo ==
"mis2 aggregation") {
341 labels = KokkosGraph::graph_mis2_aggregate<device_t, rowmap_t, colinds_t>(aRowptrs, aColinds, numAggs);
344 size_t labelCapacity = numAggs * 1.5;
348 Kokkos::UnorderedMap<LocalOrdinal, void, exec_space> used_labels(labelCapacity);
349 Kokkos::parallel_for(
350 "MueLu::UncoupledAggregationFactory::MIS2::nonempty_aggs",
351 Kokkos::RangePolicy<exec_space>(0, numRows),
352 KOKKOS_LAMBDA(lno_t i) {
353 if (aggStat(i) ==
READY)
354 used_labels.insert(labels(i));
357 if (used_labels.failed_insert()) {
359 labelCapacity = (labelCapacity + 1) * 1.5;
364 Kokkos::View<LO*, typename device_t::memory_space> new_labels(
"new_labels", numAggs);
365 Kokkos::parallel_scan(
366 "MueLu::UncoupledAggregationFactory::MIS2::set_new_labels",
367 Kokkos::RangePolicy<exec_space>(0, used_labels.capacity()),
368 KOKKOS_LAMBDA(lno_t i, lno_t & update,
const bool is_final) {
369 if (used_labels.valid_at(i)) {
370 auto label = used_labels.key_at(i);
372 new_labels(label) = update;
380 Kokkos::parallel_for(
381 "MueLu::UncoupledAggregationFactory::MIS2::reassign_labels",
382 Kokkos::RangePolicy<exec_space>(0, numRows),
383 KOKKOS_LAMBDA(lno_t i) {
384 labels(i) = new_labels(labels(i));
390 auto vertex2AggId = aggregates->GetVertex2AggId()->getLocalViewDevice(Tpetra::Access::ReadWrite);
391 auto procWinner = aggregates->GetProcWinner()->getLocalViewDevice(Tpetra::Access::OverwriteAll);
392 int rank = comm->getRank();
393 Kokkos::parallel_for(
394 Kokkos::RangePolicy<exec_space>(0, numRows),
395 KOKKOS_LAMBDA(lno_t i) {
396 if (aggStat(i) ==
READY) {
397#ifdef HAVE_MUELU_DEBUG
398 KOKKOS_ASSERT(labels(i) >= 0);
400 procWinner(i, 0) = rank;
402 vertex2AggId(i, 0) = labels(i);
410 numNonAggregatedNodes = 0;
411 aggregates->SetNumAggregates(numAggs);
414 DoGraphColoring(currentLevel, aggAlgo, pL.get<
bool>(
"aggregation: deterministic"), graph_kokkos, aggregates);
420 std::vector<GO> localStats;
422 localStats = std::vector<GO>(1 + 2 *
algos_.size());
423 localStats[0] = numRows;
425 for (
size_t a = 0; a <
algos_.size(); a++) {
426 std::string phase =
algos_[a]->description();
428 SubFactoryMonitor sfm2(*
this,
"Algo \"" + phase +
"\"" + (numNonAggregatedNodes == 0 ?
" [skipped since no nodes are left to aggregate]" :
""), currentLevel);
431 algos_[a]->SetupPhase(pL, comm, numRows, numNonAggregatedNodes);
433 if (numNonAggregatedNodes > 0) {
435 algos_[a]->BuildAggregatesNonKokkos(pL, *graph, *aggregates, aggStatHost, numNonAggregatedNodes);
437 algos_[a]->BuildAggregates(pL, *graph_kokkos, *aggregates, aggStat, numNonAggregatedNodes);
439 algos_[a]->SetProcRankVerbose(oldRank);
442 localStats[2 * a + 1] = numRows - numNonAggregatedNodes;
443 localStats[2 * a + 2] = aggregates->GetNumAggregates();
447 std::vector<GO> globalStats(1 + 2 *
algos_.size());
448 Teuchos::reduceAll(*comm, Teuchos::REDUCE_SUM, (
int)localStats.size(), localStats.data(), globalStats.data());
449 GO numGlobalRows = globalStats[0];
450 GO numGlobalAggregatedPrev = 0, numGlobalAggsPrev = 0;
451 std::stringstream ss;
452 for (
size_t a = 0; a <
algos_.size(); a++) {
453 std::string phase =
algos_[a]->description();
454 GO numGlobalAggregated = globalStats[2 * a + 1];
455 GO numGlobalAggs = globalStats[2 * a + 2];
456 GO numGlobalNonAggregatedNodes = numGlobalRows - numGlobalAggregatedPrev;
457 double aggPercent = 100 * as<double>(numGlobalAggregated) / as<double>(numGlobalRows);
458 if (aggPercent > 99.99 && aggPercent < 100.00) {
466 ss <<
"Algo \"" + phase +
"\"" + (numGlobalNonAggregatedNodes == 0 ?
" [skipped since no nodes are left to aggregate]" :
"") << std::endl
467 <<
" aggregated : " << (numGlobalAggregated - numGlobalAggregatedPrev) <<
" (phase), " << std::fixed
468 << std::setprecision(2) << numGlobalAggregated <<
"/" << numGlobalRows <<
" [" << aggPercent <<
"%] (total)\n"
469 <<
" remaining : " << numGlobalRows - numGlobalAggregated <<
"\n"
470 <<
" aggregates : " << numGlobalAggs - numGlobalAggsPrev <<
" (phase), " << numGlobalAggs <<
" (total)" << std::endl;
471 numGlobalAggregatedPrev = numGlobalAggregated;
472 numGlobalAggsPrev = numGlobalAggs;
478 TEUCHOS_TEST_FOR_EXCEPTION(numNonAggregatedNodes,
Exceptions::RuntimeError,
"MueLu::UncoupledAggregationFactory::Build: Leftover nodes found! Error!");
480 aggregates->AggregatesCrossProcessors(
false);
481 aggregates->ComputeAggregateSizes(
true );
483 Set(currentLevel,
"Aggregates", aggregates);
489 const std::string& aggAlgo,
490 const bool deterministic,
491 const RCP<const LWGraph_kokkos> graph,
492 RCP<Aggregates> aggregates)
const {
501 using KernelHandle = KokkosKernels::Experimental::
502 KokkosKernelsHandle<
typename graph_t::row_map_type::value_type,
503 typename graph_t::entries_type::value_type,
504 typename graph_t::entries_type::value_type,
505 typename graph_t::device_type::execution_space,
506 typename graph_t::device_type::memory_space,
507 typename graph_t::device_type::memory_space>;
510 kh.create_distance2_graph_coloring_handle();
513 auto coloringHandle = kh.get_distance2_graph_coloring_handle();
515 const LO numRows = graph->GetNodeNumVertices();
526 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_SERIAL);
528 }
else if (aggAlgo ==
"serial") {
529 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_SERIAL);
531 }
else if (aggAlgo ==
"default") {
532 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_DEFAULT);
534 }
else if (aggAlgo ==
"vertex based") {
535 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_VB);
537 }
else if (aggAlgo ==
"vertex based bit set") {
538 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_VB_BIT);
540 }
else if (aggAlgo ==
"edge filtering") {
541 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_VB_BIT_EF);
543 }
else if (aggAlgo ==
"net based bit set") {
544 coloringHandle->set_algorithm(KokkosGraph::COLORING_D2_NB_BIT);
547 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")
551 typename graph_t::row_map_type aRowptrs = graph->getRowPtrs();
552 typename graph_t::entries_type aColinds = graph->getEntries();
557 SubFactoryMonitor sfm2(*
this,
"Algo \"Graph Coloring\": KokkosGraph Call", currentLevel);
558 KokkosGraph::Experimental::graph_color_distance2(&kh, numRows, aRowptrs, aColinds);
562 aggregates->SetGraphColors(coloringHandle->get_vertex_colors());
563 aggregates->SetGraphNumColors(
static_cast<LO
>(coloringHandle->get_num_colors()));
566 kh.destroy_distance2_graph_coloring_handle();