MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_CoalesceDropFactory_kokkos_def.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// MueLu: A package for multigrid based preconditioning
4//
5// Copyright 2012 NTESS and the MueLu contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef MUELU_COALESCEDROPFACTORY_KOKKOS_DEF_HPP
11#define MUELU_COALESCEDROPFACTORY_KOKKOS_DEF_HPP
12
13#include <Kokkos_Core.hpp>
14#include <KokkosSparse_CrsMatrix.hpp>
15#include <sstream>
16#include <string>
17#include <tuple>
18
19#include "Xpetra_Matrix.hpp"
20
22
23#include "MueLu_AmalgamationInfo.hpp"
24#include "MueLu_Exceptions.hpp"
25#include "MueLu_Level.hpp"
26#include "MueLu_LWGraph_kokkos.hpp"
27#include "MueLu_MasterList.hpp"
28#include "MueLu_Monitor.hpp"
29#include "MueLu_Utilities.hpp"
30
34
35// The different dropping algorithms are split up over several translation units. This speeds up compilation and also avoids launch latencies on GPU.
37#include "MueLu_ScalarDroppingClassical.hpp"
38#include "MueLu_ScalarDroppingDistanceLaplacian.hpp"
40#include "MueLu_VectorDroppingClassical.hpp"
41#include "MueLu_VectorDroppingDistanceLaplacian.hpp"
42
43namespace MueLu {
44
45template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
47 RCP<ParameterList> validParamList = rcp(new ParameterList());
48
49#define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
50 SET_VALID_ENTRY("aggregation: use blocking");
51 SET_VALID_ENTRY("aggregation: drop tol");
52 SET_VALID_ENTRY("aggregation: use ml scaling of drop tol");
53 SET_VALID_ENTRY("aggregation: Dirichlet threshold");
54 SET_VALID_ENTRY("aggregation: greedy Dirichlet");
55 SET_VALID_ENTRY("aggregation: row sum drop tol");
56 SET_VALID_ENTRY("aggregation: strength-of-connection: matrix");
57 SET_VALID_ENTRY("aggregation: strength-of-connection: measure");
58 SET_VALID_ENTRY("aggregation: drop scheme");
59 SET_VALID_ENTRY("aggregation: block diagonal: interleaved blocksize");
60 SET_VALID_ENTRY("aggregation: distance laplacian metric");
61 SET_VALID_ENTRY("aggregation: Minv scheme");
62 SET_VALID_ENTRY("aggregation: distance laplacian directional weights");
63 SET_VALID_ENTRY("aggregation: dropping may create Dirichlet");
64#ifdef HAVE_MUELU_COALESCEDROP_ALLOW_OLD_PARAMETERS
65 SET_VALID_ENTRY("aggregation: distance laplacian algo");
66 SET_VALID_ENTRY("aggregation: classical algo");
67#endif
68 SET_VALID_ENTRY("aggregation: symmetrize graph after dropping");
69 SET_VALID_ENTRY("aggregation: coloring: use color graph");
70 SET_VALID_ENTRY("aggregation: coloring: localize color graph");
71
72 SET_VALID_ENTRY("filtered matrix: use lumping");
73 SET_VALID_ENTRY("filtered matrix: reuse graph");
74 SET_VALID_ENTRY("filtered matrix: reuse eigenvalue");
75
76 SET_VALID_ENTRY("filtered matrix: use root stencil");
77 SET_VALID_ENTRY("filtered matrix: lumping choice");
78 SET_VALID_ENTRY("filtered matrix: use spread lumping");
79 SET_VALID_ENTRY("filtered matrix: spread lumping diag dom growth factor");
80 SET_VALID_ENTRY("filtered matrix: spread lumping diag dom cap");
81 SET_VALID_ENTRY("filtered matrix: Dirichlet threshold");
82 SET_VALID_ENTRY("filtered matrix: count negative diagonals");
83
84#undef SET_VALID_ENTRY
85 validParamList->set<bool>("lightweight wrap", true, "Experimental option for lightweight graph access");
86#ifndef HAVE_MUELU_COALESCEDROP_ALLOW_OLD_PARAMETERS
87 validParamList->getEntry("aggregation: drop scheme").setValidator(rcp(new Teuchos::StringValidator(Teuchos::tuple<std::string>("point-wise", "cut-drop"))));
88#else
89 validParamList->getEntry("aggregation: drop scheme").setValidator(rcp(new Teuchos::StringValidator(Teuchos::tuple<std::string>("point-wise", "cut-drop", "signed classical sa", "classical", "distance laplacian", "signed classical", "block diagonal", "block diagonal classical", "block diagonal distance laplacian", "block diagonal signed classical", "block diagonal colored signed classical", "signed classical distance laplacian", "signed classical sa distance laplacian"))));
90 validParamList->getEntry("aggregation: classical algo").setValidator(rcp(new Teuchos::StringValidator(Teuchos::tuple<std::string>("default", "unscaled cut", "scaled cut", "scaled cut symmetric"))));
91 validParamList->getEntry("aggregation: distance laplacian algo").setValidator(rcp(new Teuchos::StringValidator(Teuchos::tuple<std::string>("default", "unscaled cut", "scaled cut", "scaled cut symmetric"))));
92#endif
93 validParamList->getEntry("aggregation: strength-of-connection: matrix").setValidator(rcp(new Teuchos::StringValidator(Teuchos::tuple<std::string>("A", "distance laplacian", "MinvA"))));
94 validParamList->getEntry("aggregation: strength-of-connection: measure").setValidator(rcp(new Teuchos::StringValidator(Teuchos::tuple<std::string>("smoothed aggregation", "signed smoothed aggregation", "signed ruge-stueben", "unscaled"))));
95 validParamList->getEntry("aggregation: distance laplacian metric").setValidator(rcp(new Teuchos::StringValidator(Teuchos::tuple<std::string>("unweighted", "material"))));
96 validParamList->getEntry("aggregation: Minv scheme").setValidator(rcp(new Teuchos::StringValidator(Teuchos::tuple<std::string>("spai", "fsai"))));
97
98 validParamList->set<RCP<const FactoryBase>>("A", Teuchos::null, "Generating factory of the matrix A");
99 validParamList->set<RCP<const FactoryBase>>("UnAmalgamationInfo", Teuchos::null, "Generating factory for UnAmalgamationInfo");
100 validParamList->set<RCP<const FactoryBase>>("Coordinates", Teuchos::null, "Generating factory for Coordinates");
101 validParamList->set<RCP<const FactoryBase>>("BlockNumber", Teuchos::null, "Generating factory for BlockNumber");
102 validParamList->set<RCP<const FactoryBase>>("Material", Teuchos::null, "Generating factory for Material");
103 validParamList->set<RCP<const FactoryBase>>("M", Teuchos::null, "Generating factory for M");
104 validParamList->set<RCP<const FactoryBase>>("Minv", Teuchos::null, "Generating factory for Minv");
105 validParamList->set<RCP<const FactoryBase>>("MinvA", Teuchos::null, "Generating factory for MinvA");
106
107 // Make sure we don't recursively validate options for project auxiliary matrices
108 ParameterList norecurse;
109 norecurse.disableRecursiveValidation();
110 validParamList->set<ParameterList>("project auxiliary matrices", norecurse, "matrices that will be projected on coarse levels");
111
112 return validParamList;
113}
114
115template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
117 Input(currentLevel, "A");
118 Input(currentLevel, "UnAmalgamationInfo");
119
120 const ParameterList& pL = GetParameterList();
121
122 std::string socUsesMatrix = pL.get<std::string>("aggregation: strength-of-connection: matrix");
123 bool needCoords = (socUsesMatrix == "distance laplacian");
124 const bool needM = (socUsesMatrix == "MinvA");
125#ifdef HAVE_MUELU_COALESCEDROP_ALLOW_OLD_PARAMETERS
126 std::string droppingMethod = pL.get<std::string>("aggregation: drop scheme");
127 needCoords |= (droppingMethod.find("distance laplacian") != std::string::npos);
128#endif
129 if (needCoords) {
130 Input(currentLevel, "Coordinates");
131 std::string distLaplMetric = pL.get<std::string>("aggregation: distance laplacian metric");
132 if (distLaplMetric == "material")
133 Input(currentLevel, "Material");
134 }
135 if (needM && (currentLevel.GetLevelID() != 0)) {
136 if (pL.isSublist("project auxiliary matrices")) {
137 auto projectList = pL.sublist("project auxiliary matrices");
138 if (projectList.isParameter("MinvA"))
139 Input(currentLevel, "MinvA");
140 else if (projectList.isParameter("Minv"))
141 Input(currentLevel, "Minv");
142 else if (projectList.isParameter("M"))
143 Input(currentLevel, "M");
144 }
145 }
146
147 bool useBlocking = pL.get<bool>("aggregation: use blocking");
148#ifdef HAVE_MUELU_COALESCEDROP_ALLOW_OLD_PARAMETERS
149 useBlocking |= (droppingMethod.find("block diagonal") != std::string::npos);
150#endif
151 if (useBlocking) {
152 Input(currentLevel, "BlockNumber");
153 }
154}
155
156template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
158 Build(Level& currentLevel) const {
159 auto A = Get<RCP<Matrix>>(currentLevel, "A");
160 TEUCHOS_TEST_FOR_EXCEPTION(A->GetFixedBlockSize() % A->GetStorageBlockSize() != 0, Exceptions::RuntimeError, "A->GetFixedBlockSize() needs to be a multiple of A->GetStorageBlockSize()");
161 LO blkSize = A->GetFixedBlockSize() / A->GetStorageBlockSize();
162
163 std::tuple<GlobalOrdinal, GlobalOrdinal, boundary_nodes_type> results;
164 if (blkSize == 1)
165 results = BuildScalar(currentLevel);
166 else
167 results = BuildVector(currentLevel);
168
169 if (GetVerbLevel() & Statistics1) {
170 GlobalOrdinal numDropped = std::get<0>(results);
171 GlobalOrdinal numKept = std::get<1>(results);
172 auto boundaryNodes = std::get<2>(results);
173
174 GO numLocalBoundaryNodes = 0;
175
176 Kokkos::parallel_reduce(
177 "MueLu:CoalesceDropF:Build:bnd", range_type(0, boundaryNodes.extent(0)),
178 KOKKOS_LAMBDA(const LO i, GO& n) {
179 if (boundaryNodes(i))
180 n++;
181 },
182 numLocalBoundaryNodes);
183
184 if (IsPrint(Statistics1)) {
185 auto comm = A->getRowMap()->getComm();
186
187 std::vector<GlobalOrdinal> localStats = {numLocalBoundaryNodes, numDropped, numKept};
188 std::vector<GlobalOrdinal> globalStats(3);
189 Teuchos::reduceAll(*comm, Teuchos::REDUCE_SUM, 3, localStats.data(), globalStats.data());
190
191 GO numGlobalBoundaryNodes = globalStats[0];
192 GO numGlobalDropped = globalStats[1];
193 GO numGlobalKept = globalStats[2];
194 GO numGlobalTotal = numGlobalKept + numGlobalDropped;
195
196 GetOStream(Statistics1) << "Detected " << numGlobalBoundaryNodes << " Dirichlet nodes" << std::endl;
197 if (numGlobalTotal != 0) {
198 GetOStream(Statistics1) << "Number of dropped entries: "
199 << numGlobalDropped << "/" << numGlobalTotal
200 << " (" << 100 * Teuchos::as<double>(numGlobalDropped) / Teuchos::as<double>(numGlobalTotal) << "%)" << std::endl;
201 }
202 }
203 }
204}
205
206template <class local_matrix_type, class boundary_nodes_view, class... Functors>
207void runBoundaryFunctors(local_matrix_type& lclA, boundary_nodes_view& boundaryNodes, Functors&... functors) {
208 using local_ordinal_type = typename local_matrix_type::ordinal_type;
209 using execution_space = typename local_matrix_type::execution_space;
210 using range_type = Kokkos::RangePolicy<local_ordinal_type, execution_space>;
211 auto range = range_type(0, boundaryNodes.extent(0));
212 auto boundaries = BoundaryDetection::BoundaryFunctor(lclA, functors...);
213 Kokkos::parallel_for("CoalesceDrop::BoundaryDetection", range, boundaries);
214}
215
216template <class magnitudeType>
217void translateOldAlgoParam(const Teuchos::ParameterList& pL, std::string& droppingMethod, bool& useBlocking, std::string& socUsesMatrix, std::string& socUsesMeasure, bool& symmetrizeDroppedGraph, bool& generateColoringGraph, magnitudeType& threshold, MueLu::MatrixConstruction::lumpingType& lumpingChoice) {
218 std::set<std::string> validDroppingMethods = {"piece-wise", "cut-drop"};
219
220 if (!pL.get<bool>("filtered matrix: use lumping")) lumpingChoice = MueLu::MatrixConstruction::no_lumping;
221
222 if (validDroppingMethods.find(droppingMethod) == validDroppingMethods.end()) {
223 std::string algo = droppingMethod;
224 std::string classicalAlgoStr = pL.get<std::string>("aggregation: classical algo");
225 std::string distanceLaplacianAlgoStr = pL.get<std::string>("aggregation: distance laplacian algo");
226
227 // Remove prefix "block diagonal" from algo
228 if (algo.find("block diagonal") == 0) {
229 useBlocking = true;
230 algo = algo.substr(14);
231 if (algo != "") {
232 algo = algo.substr(1);
233 }
234 }
235
236 if ((algo == "classical") || (algo == "signed classical sa") || (algo == "signed classical") || (algo == "colored signed classical")) {
237 socUsesMatrix = "A";
238
239 if (algo == "classical") {
240 socUsesMeasure = "smoothed aggregation";
241 } else if (algo == "signed classical sa") {
242 socUsesMeasure = "signed smoothed aggregation";
243 } else if (algo == "signed classical") {
244 socUsesMeasure = "signed ruge-stueben";
245 } else if (algo == "colored signed classical") {
246 socUsesMeasure = "signed ruge-stueben";
247 generateColoringGraph = true;
248 }
249
250 if (classicalAlgoStr == "default")
251 droppingMethod = "point-wise";
252 else if (classicalAlgoStr == "unscaled cut") {
253 socUsesMeasure = "unscaled";
254 droppingMethod = "cut-drop";
255 } else if (classicalAlgoStr == "scaled cut") {
256 droppingMethod = "cut-drop";
257 } else if (classicalAlgoStr == "scaled cut symmetric") {
258 droppingMethod = "cut-drop";
259 symmetrizeDroppedGraph = true;
260 }
261 } else if ((algo == "distance laplacian") || (algo == "signed classical sa distance laplacian") || (algo == "signed classical distance laplacian")) {
262 socUsesMatrix = "distance laplacian";
263
264 if (algo == "distance laplacian") {
265 socUsesMeasure = "smoothed aggregation";
266 } else if (algo == "signed classical sa distance laplacian") {
267 socUsesMeasure = "signed smoothed aggregation";
268 } else if (algo == "signed classical distance laplacian") {
269 socUsesMeasure = "signed ruge-stueben";
270 }
271
272 if (distanceLaplacianAlgoStr == "default")
273 droppingMethod = "point-wise";
274 else if (distanceLaplacianAlgoStr == "unscaled cut") {
275 socUsesMeasure = "unscaled";
276 droppingMethod = "cut-drop";
277 } else if (distanceLaplacianAlgoStr == "scaled cut") {
278 droppingMethod = "cut-drop";
279 } else if (distanceLaplacianAlgoStr == "scaled cut symmetric") {
280 droppingMethod = "cut-drop";
281 symmetrizeDroppedGraph = true;
282 }
283 } else if (algo == "") {
284 // algo was "block diagonal", but we process and remove the "block diagonal" part
285 socUsesMatrix = "A";
286 threshold = Teuchos::ScalarTraits<magnitudeType>::zero();
287 }
288 }
289}
290
291template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
292std::tuple<GlobalOrdinal, GlobalOrdinal, typename MueLu::LWGraph_kokkos<LocalOrdinal, GlobalOrdinal, Node>::boundary_nodes_type> CoalesceDropFactory_kokkos<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
293 BuildScalar(Level& currentLevel) const {
294 FactoryMonitor m(*this, "BuildScalar", currentLevel);
295
296 using MatrixType = Xpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
297 using GraphType = Xpetra::CrsGraph<LocalOrdinal, GlobalOrdinal, Node>;
298 using local_matrix_type = typename MatrixType::local_matrix_device_type;
299 using local_graph_type = typename GraphType::local_graph_device_type;
300 using rowptr_type = typename local_graph_type::row_map_type::non_const_type;
301 using entries_type = typename local_graph_type::entries_type::non_const_type;
302 using values_type = typename local_matrix_type::values_type::non_const_type;
303 using device_type = typename Node::device_type;
304 using memory_space = typename device_type::memory_space;
305 using results_view_type = Kokkos::View<DecisionType*, memory_space>;
306 using magnitudeType = typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
307 using doubleMultiVector = Xpetra::MultiVector<magnitudeType, LO, GO, NO>;
308
309 typedef Teuchos::ScalarTraits<Scalar> STS;
310 const magnitudeType zero = Teuchos::ScalarTraits<magnitudeType>::zero();
311
312 auto A = Get<RCP<Matrix>>(currentLevel, "A");
313
314 const bool needToBuildFilteredA = currentLevel.IsRequested("A", this);
315
317 // Process parameterlist
318 const ParameterList& pL = GetParameterList();
319
320 // Boundary detection
321 const magnitudeType dirichletThreshold = STS::magnitude(as<SC>(pL.get<double>("aggregation: Dirichlet threshold")));
322 const magnitudeType rowSumTol = as<magnitudeType>(pL.get<double>("aggregation: row sum drop tol"));
323 const LocalOrdinal dirichletNonzeroThreshold = 1;
324
325 // Dropping
326 bool useBlocking = pL.get<bool>("aggregation: use blocking");
327 std::string droppingMethod = pL.get<std::string>("aggregation: drop scheme");
328 std::string socUsesMatrix = pL.get<std::string>("aggregation: strength-of-connection: matrix");
329 std::string socUsesMeasure = pL.get<std::string>("aggregation: strength-of-connection: measure");
330 std::string distanceLaplacianMetric = pL.get<std::string>("aggregation: distance laplacian metric");
331 std::string MinvScheme = pL.get<std::string>("aggregation: Minv scheme");
332 bool symmetrizeDroppedGraph = pL.get<bool>("aggregation: symmetrize graph after dropping");
333 magnitudeType threshold;
334 // If we're doing the ML-style halving of the drop tol at each level, we do that here.
335 if (pL.get<bool>("aggregation: use ml scaling of drop tol"))
336 threshold = pL.get<double>("aggregation: drop tol") / pow(2.0, currentLevel.GetLevelID());
337 else
338 threshold = as<magnitudeType>(pL.get<double>("aggregation: drop tol"));
339 bool aggregationMayCreateDirichlet = pL.get<bool>("aggregation: dropping may create Dirichlet");
340
341 // Fill
342 const bool reuseGraph = pL.get<bool>("filtered matrix: reuse graph") && needToBuildFilteredA;
343 const bool reuseEigenvalue = pL.get<bool>("filtered matrix: reuse eigenvalue");
344
345 const bool useRootStencil = pL.get<bool>("filtered matrix: use root stencil");
346 const bool useSpreadLumping = pL.get<bool>("filtered matrix: use spread lumping");
347 const std::string lumpingChoiceString = pL.get<std::string>("filtered matrix: lumping choice");
349 if (needToBuildFilteredA) {
350 if (lumpingChoiceString == "diag lumping")
352 else if (lumpingChoiceString == "distributed lumping")
354 }
355
356 const magnitudeType filteringDirichletThreshold = as<magnitudeType>(pL.get<double>("filtered matrix: Dirichlet threshold"));
357
358 // coloring graph
359 bool generateColoringGraph = pL.get<bool>("aggregation: coloring: use color graph");
360 const bool localizeColoringGraph = pL.get<bool>("aggregation: coloring: localize color graph");
361 const bool symmetrizeColoringGraph = true;
362
363#ifdef HAVE_MUELU_COALESCEDROP_ALLOW_OLD_PARAMETERS
364 translateOldAlgoParam(pL, droppingMethod, useBlocking, socUsesMatrix, socUsesMeasure, symmetrizeDroppedGraph, generateColoringGraph, threshold, lumpingChoice);
365#endif
366
367 {
368 std::stringstream ss;
369 ss << "dropping scheme = \"" << droppingMethod << "\", strength-of-connection measure = \"" << socUsesMeasure << "\", strength-of-connection matrix = \"" << socUsesMatrix << "\", ";
370 if (socUsesMatrix == "distance laplacian")
371 ss << "distance laplacian metric = \"" << distanceLaplacianMetric << "\", ";
372 ss << "threshold = " << threshold << ", blocksize = " << A->GetFixedBlockSize() << ", useBlocking = " << useBlocking;
373 ss << ", symmetrizeDroppedGraph = " << symmetrizeDroppedGraph << std::endl;
374
375 GetOStream(Runtime0) << ss.str();
376 }
377
378 TEUCHOS_ASSERT(!useRootStencil);
379 TEUCHOS_ASSERT(!useSpreadLumping);
380 TEUCHOS_ASSERT((lumpingChoice != MueLu::MatrixConstruction::distributed_lumping) || !reuseGraph);
381 if (droppingMethod == "cut-drop")
382 TEUCHOS_TEST_FOR_EXCEPTION(threshold > 1.0, Exceptions::RuntimeError, "For cut-drop algorithms, \"aggregation: drop tol\" = " << threshold << ", needs to be <= 1.0");
383
385 // We perform four sweeps over the rows of A:
386 // Pass 1: detection of boundary nodes
387 // Pass 2: diagonal extraction
388 // Pass 3: drop decision for each entry and construction of the rowptr of the filtered matrix
389 // Pass 4: fill of the filtered matrix
390 //
391 // Pass 1 and 3 apply a sequence of criteria to each row of the matrix.
392
393 // TODO: We could merge pass 1 and 2.
394
395 // Compute matrix that is used for dropping
396 RCP<Matrix> A_drop;
397 if (threshold != zero) {
398 if ((socUsesMatrix == "A") || (socUsesMatrix == "MinvA")) {
399 // Get matrix used for dropping
400 if (socUsesMatrix == "A")
401 A_drop = A;
402 else if (socUsesMatrix == "MinvA") {
403 bool storeMinvOnLevel = false, storeMinvAOnLevel = false;
404 if (pL.isSublist("project auxiliary matrices")) {
405 auto projectList = pL.sublist("project auxiliary matrices");
406 if (projectList.isParameter("MinvA"))
407 storeMinvAOnLevel = true;
408 else {
409 if (projectList.isParameter("Minv"))
410 storeMinvOnLevel = true;
411 else
412 storeMinvAOnLevel = true; // nothing found in project list, so default to storing MinvA
413 }
414 } else
415 storeMinvAOnLevel = true; // no project list given, so default to storing MinvA
416
417 if (IsAvailable(currentLevel, "MinvA")) {
418 A_drop = Get<RCP<Matrix>>(currentLevel, "MinvA");
419 } else {
420 RCP<Matrix> Minv;
421 bool MueLu_Minv = IsAvailable(currentLevel, "Minv");
422 bool User_Minv = currentLevel.IsAvailable("Minv", NoFactory::get());
423 if (MueLu_Minv || User_Minv) {
424 if (MueLu_Minv)
425 Minv = Get<RCP<Matrix>>(currentLevel, "Minv");
426 else
427 Minv = currentLevel.Get<RCP<Matrix>>("Minv", NoFactory::get());
428 } else { // get M and create Minv
429
430 RCP<Matrix> M;
431 if (currentLevel.GetLevelID() == 0) {
432 M = currentLevel.Get<RCP<Matrix>>("M", NoFactory::get());
433 } else {
434 M = Get<RCP<Matrix>>(currentLevel, "M");
435 }
436 // Find Dirichlets in A to stick corresponding Dirichlets in M
437#ifdef moreExperimentsToSeeIfHelpful
438 auto boundaryNodes = MueLu::Utilities<SC, LO, GO, NO>::DetectDirichletRows_kokkos(*A, 8.0 * Teuchos::ScalarTraits<magnitudeType>::eps());
439 if (GetVerbLevel() & Statistics1) {
440 int nAbc = 0;
441 for (size_t iii = 0; iii < A->getLocalNumRows(); iii++)
442 if (boundaryNodes[iii]) nAbc++;
443 auto MbcBefore = MueLu::Utilities<SC, LO, GO, NO>::DetectDirichletRows_kokkos(*M, 8.0 * Teuchos::ScalarTraits<magnitudeType>::eps());
444 int nMbcBefore = 0;
445 for (size_t iii = 0; iii < M->getLocalNumRows(); iii++)
446 if (MbcBefore[iii]) nMbcBefore++;
447 GetOStream(Statistics1) << "MueLu_CoalesceDropFactory_kokkos_def: # A bcs = " << nAbc << ", # M bcs before MueLu enforcement = " << nMbcBefore;
448 }
450 if (GetVerbLevel() & Statistics1) {
451 auto MbcAfter = MueLu::Utilities<SC, LO, GO, NO>::DetectDirichletRows_kokkos(*M, 8.0 * Teuchos::ScalarTraits<magnitudeType>::eps());
452 int nMbcAfter = 0;
453 for (size_t iii = 0; iii < M->getLocalNumRows(); iii++)
454 if (MbcAfter[iii]) nMbcAfter++;
455 GetOStream(Statistics1) << ", # M bcs after MueLu enforcement = " << nMbcAfter << std::endl;
456 }
457#endif
458
459 // Create Minv via sparse approximate inverse
460
461 Minv = Utilities::SPAI(M, MinvScheme);
462
463 if (storeMinvOnLevel) currentLevel.Set("Minv", Minv);
464 } // finished if/else (currentLevel.IsAvailable("Minv", *mtf)
465
466 // build MinvA matrix with same sparsity pattern as A.
467 A_drop = Xpetra::MatrixFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::BuildCopy(A);
468 auto params = Teuchos::rcp(new Teuchos::ParameterList());
469 params->set("MM Throw For Non-Existent Entries", false);
470 A_drop = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*Minv, false, *A, false, A_drop, GetOStream(Statistics2), true, true, std::string("MinvA"), params);
471
472 // Enforce Dirichlet BCs by zeroing out off-diagonal rows and columns and putting a 1 on diag of MinvA
473 auto boundaryNodes = MueLu::Utilities<SC, LO, GO, NO>::DetectDirichletRows_kokkos(*A, 8.0 * Teuchos::ScalarTraits<magnitudeType>::eps());
474 auto dirichletCols = MueLu::Utilities<SC, LO, GO, NO>::DetectDirichletCols(*A, boundaryNodes);
476 MueLu::Utilities<SC, LO, GO, NO>::ZeroDirichletCols(A_drop, dirichletCols, Teuchos::ScalarTraits<SC>::zero(), true);
477
478 if (storeMinvAOnLevel) currentLevel.Set("MinvA", A_drop);
479 } // finished if/else (currentLevel.IsAvailable("MinvA", NoFactory::get()))
480 } // else if (socUsesMatrix == "MinvA") {
481 }
482 }
483
484 auto crsA = toCrsMatrix(A);
485 auto lclA = crsA->getLocalMatrixDevice();
486 auto range = range_type(0, lclA.numRows());
487
489 // Pass 1: Detect boundary nodes
490 //
491 // The following criteria are available:
492 // - BoundaryDetection::PointDirichletFunctor
493 // Marks rows as Dirichlet based on value threshold and number of off-diagonal entries
494 // - BoundaryDetection::RowSumFunctor
495 // Marks rows as Dirichlet bases on row-sum criterion
496
497 // Dirichlet nodes
498 auto boundaryNodes = boundary_nodes_type("boundaryNodes", lclA.numRows()); // initialized to false
499 {
500 SubFactoryMonitor mBoundary(*this, "Boundary detection", currentLevel);
501
502 // macro that applies boundary detection functors
503 auto dirichlet_detection = BoundaryDetection::PointDirichletFunctor(lclA, boundaryNodes, dirichletThreshold, dirichletNonzeroThreshold);
504
505 if (rowSumTol <= 0.) {
506 runBoundaryFunctors(lclA, boundaryNodes, dirichlet_detection);
507 } else {
508 auto apply_rowsum = BoundaryDetection::RowSumFunctor(lclA, boundaryNodes, rowSumTol);
509 runBoundaryFunctors(lclA, boundaryNodes, dirichlet_detection, apply_rowsum);
510 }
511 }
512 // In what follows, boundaryNodes can still still get modified if aggregationMayCreateDirichlet == true.
513 // Otherwise we're now done with it now.
514
516 // Pass 2 & 3: Diagonal extraction and determine dropping and construct
517 // rowptr of filtered matrix
518 //
519 // The following criteria are available:
520 // - Misc::PointwiseDropBoundaryFunctor
521 // Drop all rows that have been marked as Dirichlet
522 // - Misc::DropOffRankFunctor
523 // Drop all entries that are off-rank
524 // - ClassicalDropping::DropFunctor
525 // Classical dropping
526 // - DistanceLaplacian::DropFunctor
527 // Distance Laplacian dropping
528 // - Misc::KeepDiagonalFunctor
529 // Mark diagonal as KEEP
530 // - Misc::MarkSingletonFunctor
531 // Mark singletons after dropping as Dirichlet
532 // - Misc::BlockDiagonalizeFunctor
533 // Drop coupling between blocks
534 //
535 // For the block diagonal variants we first block diagonalized and then apply "blocksize = 1" algorithms.
536
537 // rowptr of filtered A
538 auto filtered_rowptr = rowptr_type("filtered_rowptr", lclA.numRows() + 1);
539 // Number of nonzeros of filtered A
540 LocalOrdinal nnz_filtered = 0;
541 // dropping decisions for each entry
542 auto results = results_view_type("results", lclA.nnz()); // initialized to UNDECIDED
543 {
544 SubFactoryMonitor mDropping(*this, "Dropping decisions", currentLevel);
545
546 if (threshold != zero) {
547 if ((socUsesMatrix == "A") || (socUsesMatrix == "MinvA")) {
548 if (socUsesMeasure == "unscaled") {
549 ScalarDroppingClassical<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::UnscaledMeasure>::runDroppingFunctors_on_A(*A_drop, results, filtered_rowptr, nnz_filtered, boundaryNodes, droppingMethod, threshold,
550 aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, currentLevel, *this);
551 } else if (socUsesMeasure == "smoothed aggregation") {
552 ScalarDroppingClassical<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::SmoothedAggregationMeasure>::runDroppingFunctors_on_A(*A_drop, results, filtered_rowptr, nnz_filtered, boundaryNodes, droppingMethod, threshold,
553 aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, currentLevel, *this);
554 } else if (socUsesMeasure == "signed ruge-stueben") {
555 ScalarDroppingClassical<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::SignedRugeStuebenMeasure>::runDroppingFunctors_on_A(*A_drop, results, filtered_rowptr, nnz_filtered, boundaryNodes, droppingMethod, threshold,
556 aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, currentLevel, *this);
557 } else if (socUsesMeasure == "signed smoothed aggregation") {
558 ScalarDroppingClassical<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::SignedSmoothedAggregationMeasure>::runDroppingFunctors_on_A(*A_drop, results, filtered_rowptr, nnz_filtered, boundaryNodes, droppingMethod, threshold,
559 aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, currentLevel, *this);
560 }
561 } else if (socUsesMatrix == "distance laplacian") {
562 auto coords = Get<RCP<doubleMultiVector>>(currentLevel, "Coordinates");
563 if (socUsesMeasure == "unscaled") {
564 ScalarDroppingDistanceLaplacian<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::UnscaledMeasure>::runDroppingFunctors_on_dlap(*A, results, filtered_rowptr, nnz_filtered, boundaryNodes, droppingMethod, threshold, aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, distanceLaplacianMetric, currentLevel, *this);
565 } else if (socUsesMeasure == "smoothed aggregation") {
566 ScalarDroppingDistanceLaplacian<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::SmoothedAggregationMeasure>::runDroppingFunctors_on_dlap(*A, results, filtered_rowptr, nnz_filtered, boundaryNodes, droppingMethod, threshold, aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, distanceLaplacianMetric, currentLevel, *this);
567 } else if (socUsesMeasure == "signed ruge-stueben") {
568 ScalarDroppingDistanceLaplacian<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::SignedRugeStuebenMeasure>::runDroppingFunctors_on_dlap(*A, results, filtered_rowptr, nnz_filtered, boundaryNodes, droppingMethod, threshold, aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, distanceLaplacianMetric, currentLevel, *this);
569 } else if (socUsesMeasure == "signed smoothed aggregation") {
570 ScalarDroppingDistanceLaplacian<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::SignedSmoothedAggregationMeasure>::runDroppingFunctors_on_dlap(*A, results, filtered_rowptr, nnz_filtered, boundaryNodes, droppingMethod, threshold, aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, distanceLaplacianMetric, currentLevel, *this);
571 }
572 }
573 } else {
574 Kokkos::deep_copy(results, KEEP);
575
576 if (symmetrizeDroppedGraph) {
577 auto drop_boundaries = Misc::PointwiseSymmetricDropBoundaryFunctor(*A, boundaryNodes, results);
578 ScalarDroppingBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::template runDroppingFunctors<>(*A, results, filtered_rowptr, nnz_filtered, useBlocking, currentLevel, *this, drop_boundaries);
579 } else {
580 auto no_op = Misc::NoOpFunctor<LocalOrdinal>();
581 ScalarDroppingBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::template runDroppingFunctors<>(*A, results, filtered_rowptr, nnz_filtered, useBlocking, currentLevel, *this, no_op);
582 }
583 }
584
585 if (symmetrizeDroppedGraph) {
586 auto symmetrize = Misc::SymmetrizeFunctor(lclA, results);
587 ScalarDroppingBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::template runDroppingFunctors<>(*A, results, filtered_rowptr, nnz_filtered, useBlocking, currentLevel, *this, symmetrize);
588 }
589 }
590 GO numDropped = lclA.nnz() - nnz_filtered;
591 GO numGlobalDropped;
592 Teuchos::reduceAll(*A->getRowMap()->getComm(), Teuchos::REDUCE_SUM, 1, &numDropped, &numGlobalDropped);
593 // We now know the number of entries of filtered A and have the final rowptr.
594
596 // Pass 4: Create local matrix for filtered A
597 //
598 // Dropped entries are optionally lumped to the diagonal.
599
600 RCP<LWGraph_kokkos> graph;
601 RCP<Matrix> filteredA;
602 if (numGlobalDropped > 0) {
603 SubFactoryMonitor mFill(*this, "Filtered matrix fill", currentLevel);
604
605 local_graph_type lclGraph;
606 local_matrix_type lclFilteredA;
607 auto colidx = entries_type("entries", nnz_filtered);
608 lclGraph = local_graph_type(colidx, filtered_rowptr);
609 if (reuseGraph) {
610 // needToBuildFilteredA is true
611 filteredA = MatrixFactory::BuildCopy(A);
612 lclFilteredA = filteredA->getLocalMatrixDevice();
613 } else if (needToBuildFilteredA) {
614 auto values = values_type("values", nnz_filtered);
615 lclFilteredA = local_matrix_type("filteredA", lclGraph, lclA.numCols());
616 }
617
618 if (lumpingChoice != MueLu::MatrixConstruction::no_lumping) {
619 if (reuseGraph) {
620 auto fillFunctor = MatrixConstruction::PointwiseFillReuseFunctor<local_matrix_type, local_graph_type, true>(lclA, results, lclFilteredA, lclGraph, filteringDirichletThreshold);
621 Kokkos::parallel_for("MueLu::CoalesceDrop::Fill_lumped_reuse", range, fillFunctor);
622 } else {
623 if (lumpingChoice == MueLu::MatrixConstruction::diag_lumping) {
624 auto fillFunctor = MatrixConstruction::PointwiseFillNoReuseFunctor<local_matrix_type, MueLu::MatrixConstruction::diag_lumping>(lclA, results, lclGraph, lclFilteredA, filteringDirichletThreshold);
625 Kokkos::parallel_for("MueLu::CoalesceDrop::Fill_lumped_noreuse", range, fillFunctor);
626 } else if (lumpingChoice == MueLu::MatrixConstruction::distributed_lumping) {
627 auto fillFunctor = MatrixConstruction::PointwiseFillNoReuseFunctor<local_matrix_type, MueLu::MatrixConstruction::distributed_lumping>(lclA, results, lclGraph, lclFilteredA, filteringDirichletThreshold);
628 Kokkos::parallel_for("MueLu::CoalesceDrop::Fill_lumped_noreuse", range, fillFunctor);
629 }
630 }
631 } else {
632 if (reuseGraph) {
633 auto fillFunctor = MatrixConstruction::PointwiseFillReuseFunctor<local_matrix_type, local_graph_type, false>(lclA, results, lclFilteredA, lclGraph, filteringDirichletThreshold);
634 Kokkos::parallel_for("MueLu::CoalesceDrop::Fill_unlumped_reuse", range, fillFunctor);
635 } else {
636 if (needToBuildFilteredA) {
637 auto fillFunctor = MatrixConstruction::PointwiseFillNoReuseFunctor<local_matrix_type, MueLu::MatrixConstruction::no_lumping>(lclA, results, lclGraph, lclFilteredA, filteringDirichletThreshold);
638 Kokkos::parallel_for("MueLu::CoalesceDrop::Fill_unlumped_noreuse", range, fillFunctor);
639 } else {
640 auto fillFunctor = MatrixConstruction::PointwiseFillNoReuseFunctor<local_matrix_type, MueLu::MatrixConstruction::no_lumping, /*constructFilteredA=*/false>(lclA, results, lclGraph, lclFilteredA, filteringDirichletThreshold);
641 Kokkos::parallel_for("MueLu::CoalesceDrop::Fill_unlumped_noreuse", range, fillFunctor);
642 }
643 }
644 }
645
646 if (needToBuildFilteredA) {
647 if (!reuseGraph)
648 filteredA = MatrixFactory::Build(lclFilteredA, A->getRowMap(), A->getColMap(), A->getDomainMap(), A->getRangeMap());
649 filteredA->SetFixedBlockSize(A->GetFixedBlockSize());
650
651 if (reuseEigenvalue) {
652 // Reuse max eigenvalue from A
653 // It is unclear what eigenvalue is the best for the smoothing, but we already may have
654 // the D^{-1}A estimate in A, may as well use it.
655 // NOTE: ML does that too
656 filteredA->SetMaxEigenvalueEstimate(A->GetMaxEigenvalueEstimate());
657 } else {
658 filteredA->SetMaxEigenvalueEstimate(-Teuchos::ScalarTraits<SC>::one());
659 }
660 }
661
662 graph = rcp(new LWGraph_kokkos(lclGraph, A->getRowMap(), A->getColMap(), "amalgamated graph of A"));
663 graph->SetBoundaryNodeMap(boundaryNodes);
664 } else {
665 if (needToBuildFilteredA)
666 filteredA = A;
667 graph = rcp(new LWGraph_kokkos(A->getCrsGraph()->getLocalGraphDevice(), A->getRowMap(), A->getColMap(), "amalgamated graph of A"));
668 graph->SetBoundaryNodeMap(boundaryNodes);
669 }
670
671 // Construct a second graph for coloring
672 if (generateColoringGraph) {
673 SubFactoryMonitor mColoringGraph(*this, "Construct coloring graph", currentLevel);
674
675 filtered_rowptr = rowptr_type("rowptr_coloring_graph", lclA.numRows() + 1);
676 if (localizeColoringGraph) {
677 auto drop_offrank = Misc::DropOffRankFunctor(lclA, results);
678 ScalarDroppingBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::template runDroppingFunctors<>(*A, results, filtered_rowptr, nnz_filtered, useBlocking, currentLevel, *this, drop_offrank);
679 }
680 if (symmetrizeColoringGraph) {
681 auto symmetrize = Misc::SymmetrizeFunctor(lclA, results);
682 ScalarDroppingBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::template runDroppingFunctors<>(*A, results, filtered_rowptr, nnz_filtered, useBlocking, currentLevel, *this, symmetrize);
683 }
684 auto colidx = entries_type("entries_coloring_graph", nnz_filtered);
685 auto lclGraph = local_graph_type(colidx, filtered_rowptr);
686 auto graphConstruction = MatrixConstruction::GraphConstruction<local_matrix_type, local_graph_type>(lclA, results, lclGraph);
687 Kokkos::parallel_for("MueLu::CoalesceDrop::Construct_coloring_graph", range, graphConstruction);
688
689 auto colorGraph = rcp(new LWGraph_kokkos(lclGraph, A->getRowMap(), A->getColMap(), "coloring graph"));
690 Set(currentLevel, "Coloring Graph", colorGraph);
691 }
692
693 if (needToBuildFilteredA && pL.get<bool>("filtered matrix: count negative diagonals")) {
694 // Count the negative diagonals (and display that information)
696 GetOStream(Runtime0) << "CoalesceDrop: Negative diagonals: " << neg_count << std::endl;
697 }
698
699 LO dofsPerNode = 1;
700 Set(currentLevel, "DofsPerNode", dofsPerNode);
701 Set(currentLevel, "Graph", graph);
702 if (needToBuildFilteredA)
703 Set(currentLevel, "A", filteredA);
704
705 return std::make_tuple(numDropped, (GlobalOrdinal)nnz_filtered, boundaryNodes);
706}
707
708template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
709std::tuple<GlobalOrdinal, GlobalOrdinal, typename MueLu::LWGraph_kokkos<LocalOrdinal, GlobalOrdinal, Node>::boundary_nodes_type> CoalesceDropFactory_kokkos<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
710 BuildVector(Level& currentLevel) const {
711 FactoryMonitor m(*this, "BuildVector", currentLevel);
712
713 using MatrixType = Xpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
714 using GraphType = Xpetra::CrsGraph<LocalOrdinal, GlobalOrdinal, Node>;
715 using local_matrix_type = typename MatrixType::local_matrix_device_type;
716 using local_graph_type = typename GraphType::local_graph_device_type;
717 using rowptr_type = typename local_graph_type::row_map_type::non_const_type;
718 using entries_type = typename local_graph_type::entries_type::non_const_type;
719 using values_type = typename local_matrix_type::values_type::non_const_type;
720 using device_type = typename Node::device_type;
721 using memory_space = typename device_type::memory_space;
722 using results_view_type = Kokkos::View<DecisionType*, memory_space>;
723 using magnitudeType = typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
724 using doubleMultiVector = Xpetra::MultiVector<magnitudeType, LO, GO, NO>;
725
726 typedef Teuchos::ScalarTraits<Scalar> STS;
727 const magnitudeType zero = Teuchos::ScalarTraits<magnitudeType>::zero();
728
729 auto A = Get<RCP<Matrix>>(currentLevel, "A");
730
731 const bool needToBuildFilteredA = currentLevel.IsRequested("A", this);
732
733 /* NOTE: storageblocksize (from GetStorageBlockSize()) is the size of a block in the chosen storage scheme.
734 blkSize is the number of storage blocks that must kept together during the amalgamation process.
735
736 Both of these quantities may be different than numPDEs (from GetFixedBlockSize()), but the following must always hold:
737
738 numPDEs = blkSize * storageblocksize.
739
740 If numPDEs==1
741 Matrix is point storage (classical CRS storage). storageblocksize=1 and blkSize=1
742 No other values makes sense.
743
744 If numPDEs>1
745 If matrix uses point storage, then storageblocksize=1 and blkSize=numPDEs.
746 If matrix uses block storage, with block size of n, then storageblocksize=n, and blkSize=numPDEs/n.
747 Thus far, only storageblocksize=numPDEs and blkSize=1 has been tested.
748 */
749
750 TEUCHOS_TEST_FOR_EXCEPTION(A->GetFixedBlockSize() % A->GetStorageBlockSize() != 0, Exceptions::RuntimeError, "A->GetFixedBlockSize() needs to be a multiple of A->GetStorageBlockSize()");
751 LO blkSize = A->GetFixedBlockSize() / A->GetStorageBlockSize();
752
753 auto amalInfo = Get<RCP<AmalgamationInfo>>(currentLevel, "UnAmalgamationInfo");
754
755 const RCP<const Map> rowMap = A->getRowMap();
756 const RCP<const Map> colMap = A->getColMap();
757
758 // build a node row map (uniqueMap = non-overlapping) and a node column map
759 // (nonUniqueMap = overlapping). The arrays rowTranslation and colTranslation
760 // stored in the AmalgamationInfo class container contain the local node id
761 // given a local dof id. The data is calculated in the AmalgamationFactory and
762 // stored in the variable "UnAmalgamationInfo" (which is of type AmalagamationInfo)
763 const RCP<const Map> uniqueMap = amalInfo->getNodeRowMap();
764 const RCP<const Map> nonUniqueMap = amalInfo->getNodeColMap();
765 Array<LO> rowTranslationArray = *(amalInfo->getRowTranslation()); // TAW should be transform that into a View?
766 Array<LO> colTranslationArray = *(amalInfo->getColTranslation());
767
768 Kokkos::View<LO*, Kokkos::MemoryUnmanaged>
769 rowTranslationView(rowTranslationArray.getRawPtr(), rowTranslationArray.size());
770 Kokkos::View<LO*, Kokkos::MemoryUnmanaged>
771 colTranslationView(colTranslationArray.getRawPtr(), colTranslationArray.size());
772
773 // get number of local nodes
774 LO numNodes = Teuchos::as<LocalOrdinal>(uniqueMap->getLocalNumElements());
775 typedef typename Kokkos::View<LocalOrdinal*, typename Node::device_type> id_translation_type;
776 id_translation_type rowTranslation("dofId2nodeId", rowTranslationArray.size());
777 id_translation_type colTranslation("ov_dofId2nodeId", colTranslationArray.size());
778 Kokkos::deep_copy(rowTranslation, rowTranslationView);
779 Kokkos::deep_copy(colTranslation, colTranslationView);
780
781 // extract striding information
782 blkSize = A->GetFixedBlockSize(); //< the full block size (number of dofs per node in strided map)
783 LocalOrdinal blkId = -1; //< the block id within a strided map or -1 if it is a full block map
784 LocalOrdinal blkPartSize = A->GetFixedBlockSize(); //< stores block size of part blkId (or the full block size)
785 if (A->IsView("stridedMaps") == true) {
786 const RCP<const Map> myMap = A->getRowMap("stridedMaps");
787 const RCP<const StridedMap> strMap = Teuchos::rcp_dynamic_cast<const StridedMap>(myMap);
788 TEUCHOS_TEST_FOR_EXCEPTION(strMap.is_null() == true, Exceptions::RuntimeError, "Map is not of type stridedMap");
789 blkSize = Teuchos::as<const LocalOrdinal>(strMap->getFixedBlockSize());
790 blkId = strMap->getStridedBlockId();
791 if (blkId > -1)
792 blkPartSize = Teuchos::as<LocalOrdinal>(strMap->getStridingData()[blkId]);
793 }
794
795 TEUCHOS_TEST_FOR_EXCEPTION(A->getRowMap()->getLocalNumElements() % blkPartSize != 0, MueLu::Exceptions::RuntimeError, "MueLu::CoalesceDropFactory: Number of local elements is " << A->getRowMap()->getLocalNumElements() << " but should be a multiple of " << blkPartSize);
796
798 // Process parameterlist
799 const ParameterList& pL = GetParameterList();
800
801 // Boundary detection
802 const magnitudeType dirichletThreshold = STS::magnitude(as<SC>(pL.get<double>("aggregation: Dirichlet threshold")));
803 const magnitudeType rowSumTol = as<magnitudeType>(pL.get<double>("aggregation: row sum drop tol"));
804 const LocalOrdinal dirichletNonzeroThreshold = 1;
805 const bool useGreedyDirichlet = pL.get<bool>("aggregation: greedy Dirichlet");
806 TEUCHOS_TEST_FOR_EXCEPTION(rowSumTol > zero, MueLu::Exceptions::RuntimeError, "MueLu::CoalesceDropFactory: RowSum is not implemented for vectorial problems.");
807
808 // Dropping
809 bool useBlocking = pL.get<bool>("aggregation: use blocking");
810 std::string droppingMethod = pL.get<std::string>("aggregation: drop scheme");
811 std::string socUsesMatrix = pL.get<std::string>("aggregation: strength-of-connection: matrix");
812 std::string socUsesMeasure = pL.get<std::string>("aggregation: strength-of-connection: measure");
813 std::string distanceLaplacianMetric = pL.get<std::string>("aggregation: distance laplacian metric");
814 bool symmetrizeDroppedGraph = pL.get<bool>("aggregation: symmetrize graph after dropping");
815 magnitudeType threshold;
816 // If we're doing the ML-style halving of the drop tol at each level, we do that here.
817 if (pL.get<bool>("aggregation: use ml scaling of drop tol"))
818 threshold = pL.get<double>("aggregation: drop tol") / pow(2.0, currentLevel.GetLevelID());
819 else
820 threshold = as<magnitudeType>(pL.get<double>("aggregation: drop tol"));
821 bool aggregationMayCreateDirichlet = pL.get<bool>("aggregation: dropping may create Dirichlet");
822
823 // Fill
824 const bool reuseGraph = pL.get<bool>("filtered matrix: reuse graph") && needToBuildFilteredA;
825 const bool reuseEigenvalue = pL.get<bool>("filtered matrix: reuse eigenvalue");
826
827 const bool useRootStencil = pL.get<bool>("filtered matrix: use root stencil");
828 const bool useSpreadLumping = pL.get<bool>("filtered matrix: use spread lumping");
829 const std::string lumpingChoiceString = pL.get<std::string>("filtered matrix: lumping choice");
831 if (needToBuildFilteredA) {
832 if (lumpingChoiceString == "diag lumping")
834 else if (lumpingChoiceString == "distributed lumping")
836 }
837
838 const magnitudeType filteringDirichletThreshold = as<magnitudeType>(pL.get<double>("filtered matrix: Dirichlet threshold"));
839
840 // coloring graph
841 bool generateColoringGraph = pL.get<bool>("aggregation: coloring: use color graph");
842 const bool localizeColoringGraph = pL.get<bool>("aggregation: coloring: localize color graph");
843 const bool symmetrizeColoringGraph = true;
844
845#ifdef HAVE_MUELU_COALESCEDROP_ALLOW_OLD_PARAMETERS
846 translateOldAlgoParam(pL, droppingMethod, useBlocking, socUsesMatrix, socUsesMeasure, symmetrizeDroppedGraph, generateColoringGraph, threshold, lumpingChoice);
847#endif
848 {
849 std::stringstream ss;
850 ss << "dropping scheme = \"" << droppingMethod << "\", strength-of-connection measure = \"" << socUsesMeasure << "\", strength-of-connection matrix = \"" << socUsesMatrix << "\", ";
851 if (socUsesMatrix == "distance laplacian")
852 ss << "distance laplacian metric = \"" << distanceLaplacianMetric << "\", ";
853 ss << "threshold = " << threshold << ", blocksize = " << A->GetFixedBlockSize() << ", useBlocking = " << useBlocking;
854 ss << ", symmetrizeDroppedGraph = " << symmetrizeDroppedGraph << std::endl;
855
856 GetOStream(Runtime0) << ss.str();
857 }
858
859 TEUCHOS_ASSERT(!useRootStencil);
860 TEUCHOS_ASSERT(!useSpreadLumping);
861 TEUCHOS_ASSERT((lumpingChoice != MueLu::MatrixConstruction::distributed_lumping) || !reuseGraph);
862 if (droppingMethod == "cut-drop")
863 TEUCHOS_TEST_FOR_EXCEPTION(threshold > 1.0, Exceptions::RuntimeError, "For cut-drop algorithms, \"aggregation: drop tol\" = " << threshold << ", needs to be <= 1.0");
864
866 // We perform four sweeps over the rows of A:
867 // Pass 1: detection of boundary nodes
868 // Pass 2: diagonal extraction
869 // Pass 3: drop decision for each entry and construction of the rowptr of the filtered matrix
870 // Pass 4: fill of the filtered matrix
871 //
872 // Pass 1 and 3 apply a sequence of criteria to each row of the matrix.
873
874 // TODO: We could merge pass 1 and 2.
875
876 auto crsA = toCrsMatrix(A);
877 auto lclA = crsA->getLocalMatrixDevice();
878 auto range = range_type(0, numNodes);
879
881 // Pass 1: Detect boundary nodes
882 //
883 // The following criteria are available:
884 // - BoundaryDetection::VectorDirichletFunctor
885 // Marks rows as Dirichlet based on value threshold and number of off-diagonal entries
886
887 // Dirichlet nodes
888 auto boundaryNodes = boundary_nodes_type("boundaryNodes", numNodes); // initialized to false
889 {
890 SubFactoryMonitor mBoundary(*this, "Boundary detection", currentLevel);
891
892 if (useGreedyDirichlet) {
893 auto dirichlet_detection = BoundaryDetection::VectorDirichletFunctor<local_matrix_type, true>(lclA, blkPartSize, boundaryNodes, dirichletThreshold, dirichletNonzeroThreshold);
894 runBoundaryFunctors(lclA, boundaryNodes, dirichlet_detection);
895 } else {
896 auto dirichlet_detection = BoundaryDetection::VectorDirichletFunctor<local_matrix_type, false>(lclA, blkPartSize, boundaryNodes, dirichletThreshold, dirichletNonzeroThreshold);
897 runBoundaryFunctors(lclA, boundaryNodes, dirichlet_detection);
898 }
899 }
900 // In what follows, boundaryNodes can still still get modified if aggregationMayCreateDirichlet == true.
901 // Otherwise we're now done with it now.
902
904 // Pass 2 & 3: Diagonal extraction and determine dropping and construct
905 // rowptr of filtered matrix
906 //
907 // The following criteria are available:
908 // - Misc::VectorDropBoundaryFunctor
909 // Drop all rows that have been marked as Dirichlet
910 // - Misc::DropOffRankFunctor
911 // Drop all entries that are off-rank
912 // - ClassicalDropping::DropFunctor
913 // Classical dropping
914 // - DistanceLaplacian::VectorDropFunctor
915 // Distance Laplacian dropping
916 // - Misc::KeepDiagonalFunctor
917 // Mark diagonal as KEEP
918 // - Misc::MarkSingletonFunctor
919 // Mark singletons after dropping as Dirichlet
920
921 // rowptr of filtered A
922 auto filtered_rowptr = rowptr_type("rowptr", lclA.numRows() + 1);
923 auto graph_rowptr = rowptr_type("rowptr", numNodes + 1);
924 // Number of nonzeros of filtered A and graph
925 Kokkos::pair<LocalOrdinal, LocalOrdinal> nnz = {0, 0};
926
927 // dropping decisions for each entry
928 auto results = results_view_type("results", lclA.nnz()); // initialized to UNDECIDED
929
930 RCP<Matrix> mergedA;
931 {
932 SubFactoryMonitor mDropping(*this, "Dropping decisions", currentLevel);
933
934 {
935 // Construct merged A.
936
937 auto merged_rowptr = rowptr_type("rowptr", numNodes + 1);
938 LocalOrdinal nnz_merged = 0;
939
940 auto functor = MatrixConstruction::MergeCountFunctor(lclA, blkPartSize, colTranslation, merged_rowptr);
941 Kokkos::parallel_scan("MergeCount", range, functor, nnz_merged);
942
943 local_graph_type lclMergedGraph;
944 auto colidx_merged = entries_type("entries", nnz_merged);
945 auto values_merged = values_type("values", nnz_merged);
946
947 local_matrix_type lclMergedA = local_matrix_type("mergedA",
948 numNodes, nonUniqueMap->getLocalNumElements(),
949 nnz_merged,
950 values_merged, merged_rowptr, colidx_merged);
951
952 auto fillFunctor = MatrixConstruction::MergeFillFunctor<local_matrix_type>(lclA, blkSize, colTranslation, lclMergedA);
953 Kokkos::parallel_for("MueLu::CoalesceDrop::MergeFill", range, fillFunctor);
954
955 mergedA = Xpetra::MatrixFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(lclMergedA, uniqueMap, nonUniqueMap, uniqueMap, uniqueMap);
956 }
957
958 if (threshold != zero) {
959 if (socUsesMatrix == "A") {
960 if (socUsesMeasure == "unscaled") {
961 VectorDroppingClassical<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::UnscaledMeasure>::runDroppingFunctors_on_A(*A, *mergedA, blkPartSize, rowTranslation, colTranslation, results, filtered_rowptr, graph_rowptr, nnz, boundaryNodes, droppingMethod, threshold, aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, currentLevel, *this);
962 } else if (socUsesMeasure == "smoothed aggregation") {
963 VectorDroppingClassical<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::SmoothedAggregationMeasure>::runDroppingFunctors_on_A(*A, *mergedA, blkPartSize, rowTranslation, colTranslation, results, filtered_rowptr, graph_rowptr, nnz, boundaryNodes, droppingMethod, threshold, aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, currentLevel, *this);
964 } else if (socUsesMeasure == "signed ruge-stueben") {
965 VectorDroppingClassical<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::SignedRugeStuebenMeasure>::runDroppingFunctors_on_A(*A, *mergedA, blkPartSize, rowTranslation, colTranslation, results, filtered_rowptr, graph_rowptr, nnz, boundaryNodes, droppingMethod, threshold, aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, currentLevel, *this);
966 } else if (socUsesMeasure == "signed smoothed aggregation") {
967 VectorDroppingClassical<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::SignedSmoothedAggregationMeasure>::runDroppingFunctors_on_A(*A, *mergedA, blkPartSize, rowTranslation, colTranslation, results, filtered_rowptr, graph_rowptr, nnz, boundaryNodes, droppingMethod, threshold, aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, currentLevel, *this);
968 }
969 } else if (socUsesMatrix == "distance laplacian") {
970 auto coords = Get<RCP<doubleMultiVector>>(currentLevel, "Coordinates");
971
972 Array<double> dlap_weights = pL.get<Array<double>>("aggregation: distance laplacian directional weights");
973 LocalOrdinal interleaved_blocksize = as<LocalOrdinal>(pL.get<int>("aggregation: block diagonal: interleaved blocksize"));
974 if (socUsesMeasure == "distance laplacian") {
975 LO dim = (LO)coords->getNumVectors();
976 // If anything isn't 1.0 we need to turn on the weighting
977 bool non_unity = false;
978 for (LO i = 0; !non_unity && i < (LO)dlap_weights.size(); i++) {
979 if (dlap_weights[i] != 1.0) {
980 non_unity = true;
981 }
982 }
983 if (non_unity) {
984 if ((LO)dlap_weights.size() == dim) {
985 distanceLaplacianMetric = "weighted";
986 } else if ((LO)dlap_weights.size() == interleaved_blocksize * dim)
987 distanceLaplacianMetric = "block weighted";
988 else {
989 TEUCHOS_TEST_FOR_EXCEPTION(1, Exceptions::RuntimeError,
990 "length of 'aggregation: distance laplacian directional weights' must equal the coordinate dimension OR the coordinate dimension times the blocksize");
991 }
992 if (GetVerbLevel() & Statistics1)
993 GetOStream(Statistics1) << "Using distance laplacian weights: " << dlap_weights << std::endl;
994 }
995 }
996
997 if (socUsesMeasure == "unscaled") {
998 VectorDroppingDistanceLaplacian<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::UnscaledMeasure>::runDroppingFunctors_on_dlap(*A, *mergedA, blkPartSize, rowTranslation, colTranslation, results, filtered_rowptr, graph_rowptr, nnz, boundaryNodes, droppingMethod, threshold, aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, distanceLaplacianMetric, dlap_weights, interleaved_blocksize, currentLevel, *this);
999 } else if (socUsesMeasure == "smoothed aggregation") {
1000 VectorDroppingDistanceLaplacian<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::SmoothedAggregationMeasure>::runDroppingFunctors_on_dlap(*A, *mergedA, blkPartSize, rowTranslation, colTranslation, results, filtered_rowptr, graph_rowptr, nnz, boundaryNodes, droppingMethod, threshold, aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, distanceLaplacianMetric, dlap_weights, interleaved_blocksize, currentLevel, *this);
1001 } else if (socUsesMeasure == "signed ruge-stueben") {
1002 VectorDroppingDistanceLaplacian<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::SignedRugeStuebenMeasure>::runDroppingFunctors_on_dlap(*A, *mergedA, blkPartSize, rowTranslation, colTranslation, results, filtered_rowptr, graph_rowptr, nnz, boundaryNodes, droppingMethod, threshold, aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, distanceLaplacianMetric, dlap_weights, interleaved_blocksize, currentLevel, *this);
1003 } else if (socUsesMeasure == "signed smoothed aggregation") {
1004 VectorDroppingDistanceLaplacian<Scalar, LocalOrdinal, GlobalOrdinal, Node, Misc::SignedSmoothedAggregationMeasure>::runDroppingFunctors_on_dlap(*A, *mergedA, blkPartSize, rowTranslation, colTranslation, results, filtered_rowptr, graph_rowptr, nnz, boundaryNodes, droppingMethod, threshold, aggregationMayCreateDirichlet, symmetrizeDroppedGraph, useBlocking, distanceLaplacianMetric, dlap_weights, interleaved_blocksize, currentLevel, *this);
1005 }
1006 }
1007 } else {
1008 Kokkos::deep_copy(results, KEEP);
1009
1010 auto no_op = Misc::NoOpFunctor<LocalOrdinal>();
1011 VectorDroppingBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::template runDroppingFunctors<>(*A, *mergedA, blkPartSize, rowTranslation, colTranslation, results, filtered_rowptr, graph_rowptr, nnz, useBlocking, currentLevel, *this, no_op);
1012 }
1013
1014 if (symmetrizeDroppedGraph) {
1015 auto symmetrize = Misc::SymmetrizeFunctor(lclA, results);
1016 VectorDroppingBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::template runDroppingFunctors<>(*A, *mergedA, blkPartSize, rowTranslation, colTranslation, results, filtered_rowptr, graph_rowptr, nnz, useBlocking, currentLevel, *this, symmetrize);
1017 }
1018 }
1019 LocalOrdinal nnz_filtered = nnz.first;
1020 LocalOrdinal nnz_graph = nnz.second;
1021 GO numTotal = mergedA->getLocalNumEntries();
1022 GO numDropped = numTotal - nnz_graph;
1023 GO numGlobalDropped;
1024 Teuchos::reduceAll(*A->getRowMap()->getComm(), Teuchos::REDUCE_SUM, 1, &numDropped, &numGlobalDropped);
1025 // We now know the number of entries of filtered A and have the final rowptr.
1026
1028 // Pass 4: Create local matrix for filtered A
1029 //
1030 // Dropped entries are optionally lumped to the diagonal.
1031
1032 RCP<LWGraph_kokkos> graph;
1033 RCP<Matrix> filteredA;
1034 if (numGlobalDropped > 0) {
1035 SubFactoryMonitor mFill(*this, "Filtered matrix fill", currentLevel);
1036
1037 local_graph_type lclGraph;
1038 {
1039 auto colidx = entries_type("entries", nnz_graph);
1040 lclGraph = local_graph_type(colidx, graph_rowptr);
1041 }
1042
1043 local_matrix_type lclFilteredA;
1044 if (reuseGraph) {
1045 // needToBuildFilteredA is true
1046 lclFilteredA = local_matrix_type("filteredA", lclA.graph, lclA.numCols());
1047 } else if (needToBuildFilteredA) {
1048 auto colidx = entries_type("entries", nnz_filtered);
1049 auto values = values_type("values", nnz_filtered);
1050 lclFilteredA = local_matrix_type("filteredA",
1051 lclA.numRows(), lclA.numCols(),
1052 nnz_filtered,
1053 values, filtered_rowptr, colidx);
1054 }
1055
1056 if (lumpingChoice != MueLu::MatrixConstruction::no_lumping) {
1057 if (reuseGraph) {
1058 auto fillFunctor = MatrixConstruction::VectorFillFunctor<local_matrix_type, true, true>(lclA, blkPartSize, colTranslation, results, lclFilteredA, lclGraph, filteringDirichletThreshold);
1059 Kokkos::parallel_for("MueLu::CoalesceDrop::Fill_lumped_reuse", range, fillFunctor);
1060 } else {
1061 auto fillFunctor = MatrixConstruction::VectorFillFunctor<local_matrix_type, true, false>(lclA, blkPartSize, colTranslation, results, lclFilteredA, lclGraph, filteringDirichletThreshold);
1062 Kokkos::parallel_for("MueLu::CoalesceDrop::Fill_lumped_noreuse", range, fillFunctor);
1063 }
1064 } else {
1065 if (reuseGraph) {
1066 auto fillFunctor = MatrixConstruction::VectorFillFunctor<local_matrix_type, false, true>(lclA, blkSize, colTranslation, results, lclFilteredA, lclGraph, filteringDirichletThreshold);
1067 Kokkos::parallel_for("MueLu::CoalesceDrop::Fill_unlumped_reuse", range, fillFunctor);
1068 } else {
1069 if (needToBuildFilteredA) {
1070 auto fillFunctor = MatrixConstruction::VectorFillFunctor<local_matrix_type, false, false>(lclA, blkSize, colTranslation, results, lclFilteredA, lclGraph, filteringDirichletThreshold);
1071 Kokkos::parallel_for("MueLu::CoalesceDrop::Fill_unlumped_noreuse", range, fillFunctor);
1072 } else {
1073 auto fillFunctor = MatrixConstruction::VectorFillFunctor<local_matrix_type, false, false, /*constructFilteredA=*/false>(lclA, blkSize, colTranslation, results, lclFilteredA, lclGraph, filteringDirichletThreshold);
1074 Kokkos::parallel_for("MueLu::CoalesceDrop::Fill_unlumped_noreuse", range, fillFunctor);
1075 }
1076 }
1077 }
1078
1079 if (needToBuildFilteredA) {
1080 filteredA = Xpetra::MatrixFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(lclFilteredA, A->getRowMap(), A->getColMap(), A->getDomainMap(), A->getRangeMap());
1081 filteredA->SetFixedBlockSize(blkSize);
1082
1083 if (reuseEigenvalue) {
1084 // Reuse max eigenvalue from A
1085 // It is unclear what eigenvalue is the best for the smoothing, but we already may have
1086 // the D^{-1}A estimate in A, may as well use it.
1087 // NOTE: ML does that too
1088 filteredA->SetMaxEigenvalueEstimate(A->GetMaxEigenvalueEstimate());
1089 } else {
1090 filteredA->SetMaxEigenvalueEstimate(-Teuchos::ScalarTraits<SC>::one());
1091 }
1092 }
1093
1094 graph = rcp(new LWGraph_kokkos(lclGraph, uniqueMap, nonUniqueMap, "amalgamated graph of A"));
1095 graph->SetBoundaryNodeMap(boundaryNodes);
1096 } else {
1097 if (needToBuildFilteredA)
1098 filteredA = A;
1099 graph = rcp(new LWGraph_kokkos(mergedA->getCrsGraph()->getLocalGraphDevice(), uniqueMap, nonUniqueMap, "amalgamated graph of A"));
1100 graph->SetBoundaryNodeMap(boundaryNodes);
1101 }
1102
1103 // Construct a second graph for coloring
1104 if (generateColoringGraph) {
1105 SubFactoryMonitor mColoringGraph(*this, "Construct coloring graph", currentLevel);
1106
1107 filtered_rowptr = rowptr_type("rowptr_coloring_graph", lclA.numRows() + 1);
1108 graph_rowptr = rowptr_type("rowptr", numNodes + 1);
1109 if (localizeColoringGraph) {
1110 auto drop_offrank = Misc::DropOffRankFunctor(lclA, results);
1111 VectorDroppingBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::template runDroppingFunctors<>(*A, *mergedA, blkPartSize, rowTranslation, colTranslation, results, filtered_rowptr, graph_rowptr, nnz, useBlocking, currentLevel, *this, drop_offrank);
1112 }
1113 if (symmetrizeColoringGraph) {
1114 auto symmetrize = Misc::SymmetrizeFunctor(lclA, results);
1115 VectorDroppingBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::template runDroppingFunctors<>(*A, *mergedA, blkPartSize, rowTranslation, colTranslation, results, filtered_rowptr, graph_rowptr, nnz, useBlocking, currentLevel, *this, symmetrize);
1116 }
1117 auto colidx = entries_type("entries_coloring_graph", nnz_filtered);
1118 auto lclGraph = local_graph_type(colidx, filtered_rowptr);
1119 auto graphConstruction = MatrixConstruction::GraphConstruction<local_matrix_type, local_graph_type>(lclA, results, lclGraph);
1120 Kokkos::parallel_for("MueLu::CoalesceDrop::Construct_coloring_graph", range, graphConstruction);
1121
1122 auto colorGraph = rcp(new LWGraph_kokkos(lclGraph, A->getRowMap(), A->getColMap(), "coloring graph"));
1123 Set(currentLevel, "Coloring Graph", colorGraph);
1124 }
1125
1126 LO dofsPerNode = blkSize;
1127
1128 Set(currentLevel, "DofsPerNode", dofsPerNode);
1129 Set(currentLevel, "Graph", graph);
1130 if (needToBuildFilteredA)
1131 Set(currentLevel, "A", filteredA);
1132
1133 return std::make_tuple(numDropped, (GlobalOrdinal)nnz_graph, boundaryNodes);
1134}
1135
1136} // namespace MueLu
1137#endif // MUELU_COALESCEDROPFACTORY_KOKKOS_DEF_HPP
#define SET_VALID_ENTRY(name)
MueLu::DefaultLocalOrdinal LocalOrdinal
MueLu::DefaultGlobalOrdinal GlobalOrdinal
Functor that serially applies sub-functors to rows.
Functor for marking nodes as Dirichlet based on rowsum.
Functor for marking nodes as Dirichlet in a block operator.
void DeclareInput(Level &currentLevel) const
Input.
std::tuple< GlobalOrdinal, GlobalOrdinal, boundary_nodes_type > BuildScalar(Level &currentLevel) const
Kokkos::RangePolicy< local_ordinal_type, execution_space > range_type
void Build(Level &currentLevel) const
Build an object with this factory.
typename MueLu::LWGraph_kokkos< LocalOrdinal, GlobalOrdinal, Node >::boundary_nodes_type boundary_nodes_type
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
std::tuple< GlobalOrdinal, GlobalOrdinal, boundary_nodes_type > BuildVector(Level &currentLevel) const
Exception throws to report errors in the internal logical of the program.
Timer to be used in factories. Similar to Monitor but with additional timers.
Lightweight MueLu representation of a compressed row storage graph.
Class that holds all level-specific information.
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need's value has been saved.
int GetLevelID() const
Return level number.
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access)....
void Set(const std::string &ename, const T &entry, const FactoryBase *factory=NoFactory::get())
bool IsRequested(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need has been requested. Note: this tells nothing about whether the need's value exist...
Functor does not reuse the graph of the matrix for a problem with blockSize == 1.
Functor that fills the filtered matrix while reusing the graph of the matrix before dropping,...
Functor that drops off-rank entries.
Functor that drops boundary nodes for a blockSize == 1 problem.
Functor that symmetrizes the dropping decisions.
static const NoFactory * get()
static void runDroppingFunctors_on_A(matrix_type &A, results_view &results, rowptr_type &filtered_rowptr, LocalOrdinal &nnz_filtered, boundary_nodes_type &boundaryNodes, const std::string &droppingMethod, const magnitudeType threshold, const bool aggregationMayCreateDirichlet, const bool symmetrizeDroppedGraph, const bool useBlocking, Level &level, const Factory &factory)
static void runDroppingFunctors_on_dlap(matrix_type &A, results_view &results, rowptr_type &filtered_rowptr, LocalOrdinal &nnz_filtered, boundary_nodes_type &boundaryNodes, const std::string &droppingMethod, const magnitudeType threshold, const bool aggregationMayCreateDirichlet, const bool symmetrizeDroppedGraph, const bool useBlocking, const std::string &distanceLaplacianMetric, Level &level, const Factory &factory)
Timer to be used in factories. Similar to SubMonitor but adds a timer level by level.
static void ZeroDirichletCols(Teuchos::RCP< Matrix > &A, const Teuchos::ArrayRCP< const bool > &dirichletCols, Scalar replaceWith=Teuchos::ScalarTraits< Scalar >::zero())
static Kokkos::View< bool *, typename NO::device_type::memory_space > DetectDirichletRows_kokkos(const Matrix &A, const Magnitude &tol=Teuchos::ScalarTraits< typename Teuchos::ScalarTraits< SC >::magnitudeType >::zero(), const bool count_twos_as_dirichlet=false)
Detect Dirichlet rows.
static void ApplyOAZToMatrixRows(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, const std::vector< LocalOrdinal > &dirichletRows)
static RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > SPAI(const RCP< Matrix > &original, const std::string &MinvScheme)
Creates a sparse approximate inverse of a matrix with the same nonzero pattern as the input matrix.
static Teuchos::ArrayRCP< const bool > DetectDirichletCols(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Teuchos::ArrayRCP< const bool > &dirichletRows)
Detect Dirichlet columns based on Dirichlet rows.
static GlobalOrdinal CountNegativeDiagonalEntries(const Matrix &A)
Counts the number of negative diagonal entries.
static void runDroppingFunctors_on_A(matrix_type &A, matrix_type &mergedA, LocalOrdinal blkPartSize, block_indices_view_type &rowTranslation, block_indices_view_type &colTranslation, results_view &results, rowptr_type &filtered_rowptr, rowptr_type &graph_rowptr, nnz_count_type &nnz, boundary_nodes_type &boundaryNodes, const std::string &droppingMethod, const magnitudeType threshold, const bool aggregationMayCreateDirichlet, const bool symmetrizeDroppedGraph, const bool useBlocking, Level &level, const Factory &factory)
static void runDroppingFunctors_on_dlap(matrix_type &A, matrix_type &mergedA, LocalOrdinal blkPartSize, block_indices_view_type &rowTranslation, block_indices_view_type &colTranslation, results_view &results, rowptr_type &filtered_rowptr, rowptr_type &graph_rowptr, nnz_count_type &nnz, boundary_nodes_type &boundaryNodes, const std::string &droppingMethod, const magnitudeType threshold, const bool aggregationMayCreateDirichlet, const bool symmetrizeDroppedGraph, const bool useBlocking, const std::string &distanceLaplacianMetric, Teuchos::Array< double > &dlap_weights, LocalOrdinal interleaved_blocksize, Level &level, const Factory &factory)
Namespace for MueLu classes and methods.
@ Statistics2
Print even more statistics.
@ Statistics1
Print more statistics.
@ Runtime0
One-liner description of what is happening.
void runBoundaryFunctors(local_matrix_type &lclA, boundary_nodes_view &boundaryNodes, Functors &... functors)
void translateOldAlgoParam(const Teuchos::ParameterList &pL, std::string &droppingMethod, bool &useBlocking, std::string &socUsesMatrix, std::string &socUsesMeasure, bool &symmetrizeDroppedGraph, bool &generateColoringGraph, magnitudeType &threshold, MueLu::MatrixConstruction::lumpingType &lumpingChoice)