From c1bfbacdd2c2fc00d2b8332b137445a7a601c352 Mon Sep 17 00:00:00 2001 From: Christian Glusa Date: Mon, 13 Jan 2025 15:24:56 -0700 Subject: [PATCH] MueLu UncoupledAggregationFactory: Add hidden option "aggregation: backend" The option allows to select the aggregation code path: - "default": do whatever matches the input graph, - "host": old, host-only aggregation code path, - "kokkos": Kokkos code path. Signed-off-by: Christian Glusa --- packages/muelu/doc/UsersGuide/masterList.xml | 9 +++ .../muelu/doc/UsersGuide/paramlist_hidden.tex | 2 + .../Graph/Containers/MueLu_LWGraph_decl.hpp | 3 + .../Graph/Containers/MueLu_LWGraph_def.hpp | 25 +++++++++ .../MueLu_UncoupledAggregationFactory_def.hpp | 55 +++++++++++++++---- .../MueLu_ParameterListInterpreter_def.hpp | 10 ++-- .../muelu/src/MueCentral/MueLu_MasterList.cpp | 3 + 7 files changed, 91 insertions(+), 16 deletions(-) diff --git a/packages/muelu/doc/UsersGuide/masterList.xml b/packages/muelu/doc/UsersGuide/masterList.xml index 952118cd7bcf..a04fbdf1feb7 100644 --- a/packages/muelu/doc/UsersGuide/masterList.xml +++ b/packages/muelu/doc/UsersGuide/masterList.xml @@ -376,6 +376,15 @@ + + aggregation: backend + string + "default" + Aggregation scheme. Possible values: "default", "host", "kokkos" + false + parameter not existing in ML + + aggregation: type string diff --git a/packages/muelu/doc/UsersGuide/paramlist_hidden.tex b/packages/muelu/doc/UsersGuide/paramlist_hidden.tex index 69be16c8c132..24b890efed59 100644 --- a/packages/muelu/doc/UsersGuide/paramlist_hidden.tex +++ b/packages/muelu/doc/UsersGuide/paramlist_hidden.tex @@ -62,6 +62,8 @@ \cbb{coarse: overlap}{int}{0}{Coarse solver subdomain overlap.} +\cbb{aggregation: backend}{string}{"default"}{Aggregation scheme. Possible values: "default", "host", "kokkos"} + \cbb{aggregation: type}{string}{"uncoupled"}{Aggregation scheme. Possible values: see Table~\ref{t:aggregation}.} \cbb{aggregation: mode}{string}{"uncoupled"}{Controls whether aggregates are allowed to cross processor boundaries. Possible values: "coupled" aggregates can cross processor boundaries, "uncoupled" aggregates cannot cross processor boundaries.} diff --git a/packages/muelu/src/Graph/Containers/MueLu_LWGraph_decl.hpp b/packages/muelu/src/Graph/Containers/MueLu_LWGraph_decl.hpp index d229903bd6a5..6775fac4f1e2 100644 --- a/packages/muelu/src/Graph/Containers/MueLu_LWGraph_decl.hpp +++ b/packages/muelu/src/Graph/Containers/MueLu_LWGraph_decl.hpp @@ -15,6 +15,7 @@ #include "MueLu_LWGraph_fwd.hpp" #include "MueLu_LWGraphBase.hpp" +#include "MueLu_LWGraph_kokkos_fwd.hpp" namespace MueLu { @@ -32,6 +33,8 @@ template { public: using LWGraphBase::LWGraphBase; + + RCP > copyToDevice(); }; } // namespace MueLu diff --git a/packages/muelu/src/Graph/Containers/MueLu_LWGraph_def.hpp b/packages/muelu/src/Graph/Containers/MueLu_LWGraph_def.hpp index 8600be87d667..c11784d7b8d2 100644 --- a/packages/muelu/src/Graph/Containers/MueLu_LWGraph_def.hpp +++ b/packages/muelu/src/Graph/Containers/MueLu_LWGraph_def.hpp @@ -10,10 +10,35 @@ #ifndef MUELU_LWGRAPH_DEF_HPP #define MUELU_LWGRAPH_DEF_HPP +#include "MueLu_LWGraph_kokkos.hpp" #include "MueLu_LWGraph_decl.hpp" namespace MueLu { +template +RCP > MueLu::LWGraph::copyToDevice() { + auto graph = this->getGraph(); + + auto row_map_d = Kokkos::create_mirror_view(graph.row_map); + auto entries_d = Kokkos::create_mirror_view(graph.entries); + Kokkos::deep_copy(row_map_d, graph.row_map); + Kokkos::deep_copy(entries_d, graph.entries); + + using local_graph_type_device = typename MueLu::LWGraphBase::local_graph_type; + auto graph_d = local_graph_type_device(entries_d, row_map_d); + + auto lw_d = rcp(new MueLu::LWGraph_kokkos(graph_d, this->GetDomainMap(), this->GetImportMap(), this->getObjectLabel())); + + using bndry_nodes_type = typename MueLu::LWGraphBase::boundary_nodes_type; + + auto bndry = this->GetBoundaryNodeMap(); + auto bndry_d = bndry_nodes_type("boundary_nodes", bndry.extent(0)); + Kokkos::deep_copy(bndry_d, bndry); + lw_d->SetBoundaryNodeMap(bndry_d); + + return lw_d; +} + } // namespace MueLu #endif // MUELU_LWGRAPH_DEF_HPP diff --git a/packages/muelu/src/Graph/UncoupledAggregation/MueLu_UncoupledAggregationFactory_def.hpp b/packages/muelu/src/Graph/UncoupledAggregation/MueLu_UncoupledAggregationFactory_def.hpp index 170506f48d39..1c8aebe78005 100644 --- a/packages/muelu/src/Graph/UncoupledAggregation/MueLu_UncoupledAggregationFactory_def.hpp +++ b/packages/muelu/src/Graph/UncoupledAggregation/MueLu_UncoupledAggregationFactory_def.hpp @@ -76,6 +76,8 @@ RCP UncoupledAggregationFactorygetEntry("aggregation: backend").setValidator(rcp(new Teuchos::StringValidator(Teuchos::tuple("default", "host", "kokkos")))); #undef SET_VALID_ENTRY // general variables needed in AggregationFactory @@ -175,20 +177,53 @@ void UncoupledAggregationFactory::Build(Level RCP aggregates; RCP> comm; LO numRows; + + const std::string aggregationBackend = pL.get("aggregation: backend"); + + // "Graph" can have type "LWGraph" or "LWGraph_kokkos". + // The aggregation phases can call either "BuildAggregatesNonKokkos" or "BuildAggregates". + + // "aggregation: backend" can take values "default", "non-Kokkos" or "Kokkos". + // "default": run depending on the type of "Graph" + // "non-Kokkos": run the non-Kokkos aggregation, moving "Graph" to host if necessary + // "Kokkos": run the Kokkos aggregation, potentially move "Graph", moving "Graph" to device if necessary + bool runOnHost; if (IsType>(currentLevel, "Graph")) { - graph = Get>(currentLevel, "Graph"); - aggregates = rcp(new Aggregates(*graph)); - comm = graph->GetComm(); - numRows = graph->GetNodeNumVertices(); - runOnHost = true; + if ((aggregationBackend == "default") || (aggregationBackend == "non-Kokkos")) { + graph = Get>(currentLevel, "Graph"); + aggregates = rcp(new Aggregates(*graph)); + comm = graph->GetComm(); + numRows = graph->GetNodeNumVertices(); + runOnHost = true; + } else { + RCP tmp_graph = Get>(currentLevel, "Graph"); + graph_kokkos = tmp_graph->copyToDevice(); + aggregates = rcp(new Aggregates(*graph_kokkos)); + comm = graph_kokkos->GetComm(); + numRows = graph_kokkos->GetNodeNumVertices(); + runOnHost = false; + } + } else if (IsType>(currentLevel, "Graph")) { + if ((aggregationBackend == "default") || (aggregationBackend == "Kokkos")) { + graph_kokkos = Get>(currentLevel, "Graph"); + aggregates = rcp(new Aggregates(*graph_kokkos)); + comm = graph_kokkos->GetComm(); + numRows = graph_kokkos->GetNodeNumVertices(); + runOnHost = false; + } else { + RCP tmp_graph_kokkos = Get>(currentLevel, "Graph"); + graph = tmp_graph_kokkos->copyToHost(); + aggregates = rcp(new Aggregates(*graph)); + comm = graph->GetComm(); + numRows = graph->GetNodeNumVertices(); + runOnHost = true; + } } else { - graph_kokkos = Get>(currentLevel, "Graph"); - aggregates = rcp(new Aggregates(*graph_kokkos)); - comm = graph_kokkos->GetComm(); - numRows = graph_kokkos->GetNodeNumVertices(); - runOnHost = false; + TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Graph has bad type."); + } + if (!runOnHost) { TEUCHOS_TEST_FOR_EXCEPTION(pL.get("aggregation: use interface aggregation"), std::invalid_argument, "Option: 'aggregation: use interface aggregation' is not supported in the Kokkos version of uncoupled aggregation"); // Sanity Checking: match ML behavior is not supported in UncoupledAggregation_Kokkos in Phase 1 , but it is in 2a and 2b TEUCHOS_TEST_FOR_EXCEPTION(pL.get("aggregation: match ML phase1"), std::invalid_argument, "Option: 'aggregation: match ML phase1' is not supported in the Kokkos version of uncoupled aggregation"); diff --git a/packages/muelu/src/Interface/MueLu_ParameterListInterpreter_def.hpp b/packages/muelu/src/Interface/MueLu_ParameterListInterpreter_def.hpp index 643b92518838..e79a8d512d92 100644 --- a/packages/muelu/src/Interface/MueLu_ParameterListInterpreter_def.hpp +++ b/packages/muelu/src/Interface/MueLu_ParameterListInterpreter_def.hpp @@ -1099,12 +1099,10 @@ void ParameterListInterpreter:: MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: min agg size", int, aggParams); MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: max agg size", int, aggParams); MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: max selected neighbors", int, aggParams); - if (useKokkos_) { - // if not using kokkos refactor Uncoupled, there is no algorithm option (always Serial) - MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: phase 1 algorithm", std::string, aggParams); - MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: deterministic", bool, aggParams); - MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: coloring algorithm", std::string, aggParams); - } + MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: backend", std::string, aggParams); + MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: phase 1 algorithm", std::string, aggParams); + MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: deterministic", bool, aggParams); + MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: coloring algorithm", std::string, aggParams); MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: enable phase 1", bool, aggParams); MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: enable phase 2a", bool, aggParams); MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: enable phase 2b", bool, aggParams); diff --git a/packages/muelu/src/MueCentral/MueLu_MasterList.cpp b/packages/muelu/src/MueCentral/MueLu_MasterList.cpp index 53fbea02cd61..5dec82ecde13 100644 --- a/packages/muelu/src/MueCentral/MueLu_MasterList.cpp +++ b/packages/muelu/src/MueCentral/MueLu_MasterList.cpp @@ -164,6 +164,7 @@ namespace MueLu { "" "" "" + "" "" "" "" @@ -596,6 +597,8 @@ namespace MueLu { ("coarse: overlap","coarse: overlap") + ("aggregation: backend","aggregation: backend") + ("aggregation: type","aggregation: type") ("aggregation: mode","aggregation: mode")