MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_RefMaxwell_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_REFMAXWELL_DEF_HPP
11#define MUELU_REFMAXWELL_DEF_HPP
12
13#include <sstream>
14
15#include "MueLu_ConfigDefs.hpp"
16
17#include "Teuchos_CompilerCodeTweakMacros.hpp"
18#include "Tpetra_CrsMatrix.hpp"
19#include "Xpetra_CrsMatrix.hpp"
20#include "Xpetra_Map.hpp"
21#include "Xpetra_MatrixMatrix.hpp"
22#include "Xpetra_MultiVector.hpp"
23#include "Xpetra_TripleMatrixMultiply.hpp"
24#include "Xpetra_CrsMatrixUtils.hpp"
25#include "Xpetra_MatrixUtils.hpp"
26
28
29#include "MueLu_AmalgamationFactory.hpp"
30#include "MueLu_RAPFactory.hpp"
31#include "MueLu_SmootherFactory.hpp"
32
33#include "MueLu_CoalesceDropFactory.hpp"
34#include "MueLu_CoarseMapFactory.hpp"
35#include "MueLu_CoordinatesTransferFactory.hpp"
36#include "MueLu_UncoupledAggregationFactory.hpp"
37#include "MueLu_TentativePFactory.hpp"
38#include "MueLu_SaPFactory.hpp"
39#include "MueLu_AggregationExportFactory.hpp"
40#include "MueLu_Utilities.hpp"
41#include "MueLu_Maxwell_Utils.hpp"
42
43#include "MueLu_CoalesceDropFactory_kokkos.hpp"
44#include "MueLu_TentativePFactory_kokkos.hpp"
45#include <Kokkos_Core.hpp>
46#include <KokkosSparse_CrsMatrix.hpp>
47
48#include "MueLu_ZoltanInterface.hpp"
49#include "MueLu_Zoltan2Interface.hpp"
50#include "MueLu_RepartitionHeuristicFactory.hpp"
51#include "MueLu_RepartitionFactory.hpp"
52#include "MueLu_RebalanceAcFactory.hpp"
53#include "MueLu_RebalanceTransferFactory.hpp"
54
56
59
60#ifdef HAVE_MUELU_CUDA
61#include "cuda_profiler_api.h"
62#endif
63
64// Stratimikos
65#if defined(HAVE_MUELU_STRATIMIKOS) && defined(HAVE_MUELU_THYRA)
67#endif
68
69namespace MueLu {
70
71template <typename T>
72T pop(Teuchos::ParameterList &pl, std::string const &name_in) {
73 T result = pl.get<T>(name_in);
74 pl.remove(name_in, true);
75 return result;
76}
77
78template <typename T>
79T pop(Teuchos::ParameterList &pl, std::string const &name_in, T def_value) {
80 T result = pl.get<T>(name_in, def_value);
81 pl.remove(name_in, false);
82 return result;
83}
84
85template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
86const Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getDomainMap() const {
87 return SM_Matrix_->getDomainMap();
88}
89
90template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
91const Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getRangeMap() const {
92 return SM_Matrix_->getRangeMap();
93}
94
95template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
96Teuchos::RCP<Teuchos::ParameterList>
99 bool useKokkosDefault = !Node::is_serial;
100
101 RCP<ParameterList> params = rcp(new ParameterList("RefMaxwell"));
102
103 params->set<RCP<Matrix>>("Dk_1", Teuchos::null);
104 params->set<RCP<Matrix>>("Dk_2", Teuchos::null);
105 params->set<RCP<Matrix>>("D0", Teuchos::null);
106
107 params->set<RCP<Matrix>>("M1_beta", Teuchos::null);
108 params->set<RCP<Matrix>>("M1_alpha", Teuchos::null);
109 // for backwards compatibility
110 params->set<RCP<Matrix>>("Ms", Teuchos::null);
111
112 params->set<RCP<Matrix>>("Mk_one", Teuchos::null);
113 params->set<RCP<Matrix>>("Mk_1_one", Teuchos::null);
114 // for backwards compatibility
115 params->set<RCP<Matrix>>("M1", Teuchos::null);
116
117 params->set<RCP<Matrix>>("invMk_1_invBeta", Teuchos::null);
118 params->set<RCP<Matrix>>("invMk_2_invAlpha", Teuchos::null);
119 // for backwards compatibility
120 params->set<RCP<Matrix>>("M0inv", Teuchos::null);
121
122 params->set<RCP<MultiVector>>("Nullspace", Teuchos::null);
123 params->set<RCP<RealValuedMultiVector>>("Coordinates", Teuchos::null);
124
125 auto spaceValidator = rcp(new Teuchos::EnhancedNumberValidator<int>(1, 2));
126 params->set("refmaxwell: space number", 1, "", spaceValidator);
127 params->set("verbosity", MasterList::getDefault<std::string>("verbosity"));
128 params->set("use kokkos refactor", useKokkosDefault);
129 params->set("half precision", false);
130 params->set("parameterlist: syntax", MasterList::getDefault<std::string>("parameterlist: syntax"));
131 params->set("output filename", MasterList::getDefault<std::string>("output filename"));
132 params->set("print initial parameters", MasterList::getDefault<bool>("print initial parameters"));
133 params->set("refmaxwell: disable addon", MasterList::getDefault<bool>("refmaxwell: disable addon"));
134 params->set("refmaxwell: disable addon 22", true);
135 params->set("refmaxwell: mode", MasterList::getDefault<std::string>("refmaxwell: mode"));
136 params->set("refmaxwell: use as preconditioner", MasterList::getDefault<bool>("refmaxwell: use as preconditioner"));
137 params->set("refmaxwell: dump matrices", MasterList::getDefault<bool>("refmaxwell: dump matrices"));
138 params->set("refmaxwell: enable reuse", MasterList::getDefault<bool>("refmaxwell: enable reuse"));
139 params->set("refmaxwell: skip first (1,1) level", MasterList::getDefault<bool>("refmaxwell: skip first (1,1) level"));
140 params->set("refmaxwell: skip first (2,2) level", false);
141 params->set("multigrid algorithm", "Unsmoothed");
142 params->set("transpose: use implicit", MasterList::getDefault<bool>("transpose: use implicit"));
143 params->set("rap: triple product", MasterList::getDefault<bool>("rap: triple product"));
144 params->set("rap: fix zero diagonals", true);
145 params->set("rap: fix zero diagonals threshold", MasterList::getDefault<double>("rap: fix zero diagonals threshold"));
146 params->set("fuse prolongation and update", MasterList::getDefault<bool>("fuse prolongation and update"));
147 params->set("refmaxwell: async transfers", Node::is_gpu);
148 params->set("refmaxwell: subsolves on subcommunicators", MasterList::getDefault<bool>("refmaxwell: subsolves on subcommunicators"));
149 params->set("refmaxwell: subsolves striding", 1);
150 params->set("refmaxwell: row sum drop tol (1,1)", MasterList::getDefault<double>("aggregation: row sum drop tol"));
151 params->set("sync timers", false);
152 params->set("refmaxwell: num iters coarse 11", 1);
153 params->set("refmaxwell: num iters 22", 1);
154 params->set("refmaxwell: apply BCs to Anodal", false);
155 params->set("refmaxwell: apply BCs to coarse 11", true);
156 params->set("refmaxwell: apply BCs to 22", true);
157 params->set("refmaxwell: max coarse size", 1);
158
159 ParameterList &precList11 = params->sublist("refmaxwell: 11list");
160 precList11.disableRecursiveValidation();
161 ParameterList &precList22 = params->sublist("refmaxwell: 22list");
162 precList22.disableRecursiveValidation();
163
164 params->set("smoother: type", "CHEBYSHEV");
165 ParameterList &smootherList = params->sublist("smoother: params");
166 smootherList.disableRecursiveValidation();
167 params->set("smoother: pre type", "NONE");
168 ParameterList &preSmootherList = params->sublist("smoother: pre params");
169 preSmootherList.disableRecursiveValidation();
170 params->set("smoother: post type", "NONE");
171 ParameterList &postSmootherList = params->sublist("smoother: post params");
172 postSmootherList.disableRecursiveValidation();
173
174 ParameterList &matvecParams = params->sublist("matvec params");
175 matvecParams.disableRecursiveValidation();
176
177 params->set("multigrid algorithm", "unsmoothed");
178 params->set("aggregation: type", MasterList::getDefault<std::string>("aggregation: type"));
179 params->set("aggregation: drop tol", MasterList::getDefault<double>("aggregation: drop tol"));
180 params->set("aggregation: drop scheme", MasterList::getDefault<std::string>("aggregation: drop scheme"));
181 params->set("aggregation: distance laplacian algo", MasterList::getDefault<std::string>("aggregation: distance laplacian algo"));
182 params->set("aggregation: min agg size", MasterList::getDefault<int>("aggregation: min agg size"));
183 params->set("aggregation: max agg size", MasterList::getDefault<int>("aggregation: max agg size"));
184 params->set("aggregation: match ML phase1", MasterList::getDefault<bool>("aggregation: match ML phase1"));
185 params->set("aggregation: match ML phase2a", MasterList::getDefault<bool>("aggregation: match ML phase2a"));
186 params->set("aggregation: match ML phase2b", MasterList::getDefault<bool>("aggregation: match ML phase2b"));
187 params->set("aggregation: export visualization data", MasterList::getDefault<bool>("aggregation: export visualization data"));
188
189 return params;
190}
191
192template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
194 if (list.isType<std::string>("parameterlist: syntax") && list.get<std::string>("parameterlist: syntax") == "ml") {
195 Teuchos::ParameterList newList;
196 {
197 Teuchos::ParameterList newList2 = *Teuchos::getParametersFromXmlString(MueLu::ML2MueLuParameterTranslator::translate(list, "refmaxwell"));
198 RCP<Teuchos::ParameterList> validateParameters = getValidParamterList();
199 for (auto it = newList2.begin(); it != newList2.end(); ++it) {
200 const std::string &entry_name = it->first;
201 if (validateParameters->isParameter(entry_name)) {
202 ParameterEntry theEntry = newList2.getEntry(entry_name);
203 newList.setEntry(entry_name, theEntry);
204 }
205 }
206 }
207
208 if (list.isSublist("refmaxwell: 11list") && list.sublist("refmaxwell: 11list").isSublist("edge matrix free: coarse"))
209 newList.sublist("refmaxwell: 11list") = *Teuchos::getParametersFromXmlString(MueLu::ML2MueLuParameterTranslator::translate(list.sublist("refmaxwell: 11list").sublist("edge matrix free: coarse"), "SA"));
210 if (list.isSublist("refmaxwell: 22list"))
211 newList.sublist("refmaxwell: 22list") = *Teuchos::getParametersFromXmlString(MueLu::ML2MueLuParameterTranslator::translate(list.sublist("refmaxwell: 22list"), "SA"));
212 list = newList;
213 }
214
215 parameterList_ = list;
216 parameterList_.validateParametersAndSetDefaults(*getValidParamterList());
217 std::string verbosityLevel = parameterList_.get<std::string>("verbosity");
219 std::string outputFilename = parameterList_.get<std::string>("output filename");
220 if (outputFilename != "")
222 if (parameterList_.isType<Teuchos::RCP<Teuchos::FancyOStream>>("output stream"))
223 VerboseObject::SetMueLuOStream(parameterList_.get<Teuchos::RCP<Teuchos::FancyOStream>>("output stream"));
224
225 if (parameterList_.get<bool>("print initial parameters"))
226 GetOStream(static_cast<MsgType>(Runtime1), 0) << parameterList_ << std::endl;
227 disable_addon_ = parameterList_.get<bool>("refmaxwell: disable addon");
228 disable_addon_22_ = parameterList_.get<bool>("refmaxwell: disable addon 22");
229 mode_ = parameterList_.get<std::string>("refmaxwell: mode");
230 use_as_preconditioner_ = parameterList_.get<bool>("refmaxwell: use as preconditioner");
231 dump_matrices_ = parameterList_.get<bool>("refmaxwell: dump matrices");
232 enable_reuse_ = parameterList_.get<bool>("refmaxwell: enable reuse");
233 implicitTranspose_ = parameterList_.get<bool>("transpose: use implicit");
234 fuseProlongationAndUpdate_ = parameterList_.get<bool>("fuse prolongation and update");
235 skipFirst11Level_ = parameterList_.get<bool>("refmaxwell: skip first (1,1) level");
236 skipFirst22Level_ = parameterList_.get<bool>("refmaxwell: skip first (2,2) level");
237 if (spaceNumber_ == 1)
238 skipFirst22Level_ = false;
239 syncTimers_ = parameterList_.get<bool>("sync timers");
240 useKokkos_ = parameterList_.get<bool>("use kokkos refactor");
241 numItersCoarse11_ = parameterList_.get<int>("refmaxwell: num iters coarse 11");
242 numIters22_ = parameterList_.get<int>("refmaxwell: num iters 22");
243 applyBCsToAnodal_ = parameterList_.get<bool>("refmaxwell: apply BCs to Anodal");
244 applyBCsToCoarse11_ = parameterList_.get<bool>("refmaxwell: apply BCs to coarse 11");
245 applyBCsTo22_ = parameterList_.get<bool>("refmaxwell: apply BCs to 22");
246
247 precList11_ = parameterList_.sublist("refmaxwell: 11list");
248 if (!precList11_.isType<std::string>("Preconditioner Type") &&
249 !precList11_.isType<std::string>("smoother: type") &&
250 !precList11_.isType<std::string>("smoother: pre type") &&
251 !precList11_.isType<std::string>("smoother: post type")) {
252 precList11_.set("smoother: type", "CHEBYSHEV");
253 precList11_.sublist("smoother: params").set("chebyshev: degree", 2);
254 precList11_.sublist("smoother: params").set("chebyshev: ratio eigenvalue", 5.4);
255 precList11_.sublist("smoother: params").set("chebyshev: eigenvalue max iterations", 30);
256 }
257
258 precList22_ = parameterList_.sublist("refmaxwell: 22list");
259 if (!precList22_.isType<std::string>("Preconditioner Type") &&
260 !precList22_.isType<std::string>("smoother: type") &&
261 !precList22_.isType<std::string>("smoother: pre type") &&
262 !precList22_.isType<std::string>("smoother: post type")) {
263 precList22_.set("smoother: type", "CHEBYSHEV");
264 precList22_.sublist("smoother: params").set("chebyshev: degree", 2);
265 precList22_.sublist("smoother: params").set("chebyshev: ratio eigenvalue", 7.0);
266 precList22_.sublist("smoother: params").set("chebyshev: eigenvalue max iterations", 30);
267 }
268
269 if (!parameterList_.isType<std::string>("smoother: type") && !parameterList_.isType<std::string>("smoother: pre type") && !parameterList_.isType<std::string>("smoother: post type")) {
270 list.set("smoother: type", "CHEBYSHEV");
271 list.sublist("smoother: params").set("chebyshev: degree", 2);
272 list.sublist("smoother: params").set("chebyshev: ratio eigenvalue", 20.0);
273 list.sublist("smoother: params").set("chebyshev: eigenvalue max iterations", 30);
274 }
275
276 if (enable_reuse_ &&
277 !precList11_.isType<std::string>("Preconditioner Type") &&
278 !precList11_.isParameter("reuse: type"))
279 precList11_.set("reuse: type", "full");
280 if (enable_reuse_ &&
281 !precList22_.isType<std::string>("Preconditioner Type") &&
282 !precList22_.isParameter("reuse: type"))
283 precList22_.set("reuse: type", "full");
284}
285
286template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
288 using memory_space = typename Node::device_type::memory_space;
289
290#ifdef HAVE_MUELU_CUDA
291 if (parameterList_.get<bool>("refmaxwell: cuda profile setup", false)) cudaProfilerStart();
292#endif
293
294 std::string timerLabel;
295 if (reuse)
296 timerLabel = "compute (reuse)";
297 else
298 timerLabel = "compute";
299 RCP<Teuchos::TimeMonitor> tmCompute = getTimer(timerLabel);
300
302 // COMMENTED OUT SINCE WE SHOULD NOT NEED THIS ANYMORE.
303 // Remove explicit zeros from matrices
304 // Maxwell_Utils<SC,LO,GO,NO>::removeExplicitZeros(parameterList_,D0_,SM_Matrix_,Mk_one_,M1_beta_);
305 // if (!Dk_1_.is_null())
306 // Dk_1_ = Maxwell_Utils<SC,LO,GO,NO>::removeExplicitZeros(Dk_1_, 1e-10, false);
307
308 if (IsPrint(Statistics2)) {
309 RCP<ParameterList> params = rcp(new ParameterList());
310 params->set("printLoadBalancingInfo", true);
311 params->set("printCommInfo", true);
313 }
314
316 // Detect Dirichlet boundary conditions
317 if (!reuse) {
318 magnitudeType rowSumTol = parameterList_.get<double>("refmaxwell: row sum drop tol (1,1)");
324 if (spaceNumber_ == 2) {
325 Kokkos::View<bool *, memory_space> BCcolsEdge = Kokkos::View<bool *, memory_space>(Kokkos::ViewAllocateWithoutInitializing("dirichletCols"), Dk_1_->getColMap()->getLocalNumElements());
326 Kokkos::View<bool *, memory_space> BCdomainEdge = Kokkos::View<bool *, memory_space>(Kokkos::ViewAllocateWithoutInitializing("dirichletDomains"), Dk_1_->getDomainMap()->getLocalNumElements());
327 Utilities::DetectDirichletColsAndDomains(*Dk_1_, BCrows11_, BCcolsEdge, BCdomainEdge);
328
329 Kokkos::View<bool *, memory_space> BCcolsNode = Kokkos::View<bool *, memory_space>(Kokkos::ViewAllocateWithoutInitializing("dirichletCols"), D0_->getColMap()->getLocalNumElements());
330 Kokkos::View<bool *, memory_space> BCdomainNode = Kokkos::View<bool *, memory_space>(Kokkos::ViewAllocateWithoutInitializing("dirichletDomains"), D0_->getDomainMap()->getLocalNumElements());
331 Utilities::DetectDirichletColsAndDomains(*D0_, BCdomainEdge, BCcolsNode, BCdomainNode);
332 BCdomain22_ = BCdomainNode;
333 }
334 if (IsPrint(Statistics2)) {
335 GetOStream(Statistics2) << solverName_ + "::compute(): Detected " << globalNumberBoundaryUnknowns11_ << " BC rows and " << globalNumberBoundaryUnknowns22_ << " BC columns." << std::endl;
336 }
337 dump(BCrows11_, "BCrows11.m");
338 dump(BCcols22_, "BCcols22.m");
339 dump(BCdomain22_, "BCdomain22.m");
340 }
341
342 if (onlyBoundary11_) {
343 // All unknowns of the (1,1) block have been detected as boundary unknowns.
344 // Do not attempt to construct sub-hierarchies, but just set up a single level preconditioner.
345 GetOStream(Warnings0) << "All unknowns of the (1,1) block have been detected as boundary unknowns!" << std::endl;
346 mode_ = "none";
348 return;
349 }
350
352
353 dim_ = NodalCoords_->getNumVectors();
354
356 // build special prolongators
357 if (!reuse) {
359 // build nullspace for (1,1)-block (if necessary)
360 if (Nullspace11_ != null) { // no need to do anything - nullspace is built
361 TEUCHOS_ASSERT(Nullspace11_->getMap()->isCompatible(*(SM_Matrix_->getRowMap())));
362 } else if (NodalCoords_ != null) {
364 } else {
365 GetOStream(Errors) << solverName_ + "::compute(): either the nullspace or the nodal coordinates must be provided." << std::endl;
366 }
367
368 // build special prolongator for (1,1)-block
369 {
370 RCP<Matrix> A11_nodal;
371 if (skipFirst11Level_) {
372 // Form A11_nodal = D0^T * M1_beta * D0 (aka TMT_agg)
373 std::string label("D0^T*M1_beta*D0");
375
376 if (applyBCsToAnodal_) {
377 // Apply boundary conditions to A11_nodal
379 }
380 A11_nodal->setObjectLabel(solverName_ + " (1,1) A_nodal");
381 dump(A11_nodal, "A11_nodal.m");
382 }
383 // release it because we won't need it anymore
384 M1_beta_ = Teuchos::null;
385
386 // build special prolongator
388
389 dump(P11_, "P11.m");
390 }
391
393 // build nullspace for (2,2)-block (if necessary)
394 if (Nullspace22_ != null) {
395 TEUCHOS_ASSERT(Nullspace22_->getMap()->isCompatible(*(Dk_1_->getDomainMap())));
396 } else if (NodalCoords_ != null)
398 else {
399 GetOStream(Errors) << solverName_ + "::compute(): either the nullspace or the nodal coordinates must be provided." << std::endl;
400 }
401
402 // build special prolongator for (2,2)-block
403 {
404 RCP<Matrix> A22_nodal;
405 if (skipFirst22Level_) {
406 // Form A22_nodal = D0^T * M1_alpha * D0
407 std::string label("D0^T*M1_alpha*D0");
409
410 if (applyBCsToAnodal_) {
411 // Apply boundary conditions to A22_nodal
413 }
414 A22_nodal->setObjectLabel(solverName_ + " (2,2) A_nodal");
415 dump(A22_nodal, "A22_nodal.m");
416 }
417 // release it because we won't need it anymore
418 M1_alpha_ = Teuchos::null;
419
420 // build special prolongator
422
423 dump(P22_, "P22.m");
424 }
425 }
426
428 // build coarse grid operator for (1,1)-block
430
432 // determine the communicator sizes for (1,1)- and (2,2)-blocks
433 bool doRebalancing;
434 int rebalanceStriding, numProcsCoarseA11, numProcsA22;
435 if (!reuse)
436 this->determineSubHierarchyCommSizes(doRebalancing, rebalanceStriding, numProcsCoarseA11, numProcsA22);
437 else
438 doRebalancing = false;
439
440 // rebalance the coarse A11 matrix, as well as P11, CoordsCoarse11 and Addon11
441 if (!reuse && doRebalancing)
442 rebalanceCoarse11Matrix(rebalanceStriding, numProcsCoarseA11);
443 if (!coarseA11_.is_null()) {
444 dump(coarseA11_, "coarseA11.m");
445 if (!reuse) {
446 dumpCoords(CoordsCoarse11_, "CoordsCoarse11.m");
447 dump(NullspaceCoarse11_, "NullspaceCoarse11.m");
448 }
449 }
450
451 if (!reuse) {
452 if (!implicitTranspose_) {
454 dump(R11_, "R11.m");
455 }
456 }
458 // build multigrid for coarse (1,1)-block
459 if (!coarseA11_.is_null()) {
461 std::string label("coarseA11");
464 }
465
467 // Apply BCs to columns of Dk_1
468 if (!reuse && applyBCsTo22_) {
469 GetOStream(Runtime0) << solverName_ + "::compute(): nuking BC columns of Dk_1" << std::endl;
470
471 Dk_1_->resumeFill();
472 Scalar replaceWith = (Dk_1_->getRowMap()->lib() == Xpetra::UseEpetra) ? Teuchos::ScalarTraits<SC>::eps() : Teuchos::ScalarTraits<SC>::zero();
474 Dk_1_->fillComplete(Dk_1_->getDomainMap(), Dk_1_->getRangeMap());
475 }
476
478 // Build A22 = Dk_1^T SM Dk_1 and hierarchy for A22
479 if (!onlyBoundary22_) {
480 GetOStream(Runtime0) << solverName_ + "::compute(): building MG for (2,2)-block" << std::endl;
481
482 // Build A22 = Dk_1^T * SM * Dk_1 and rebalance it, as well as Dk_1_ and P22_ and Coords22_
483 build22Matrix(reuse, doRebalancing, rebalanceStriding, numProcsA22);
484
485 if (!P22_.is_null()) {
486 std::string label("P22^T*A22*P22");
488 coarseA22_->SetFixedBlockSize(A22_->GetFixedBlockSize());
489 coarseA22_->setObjectLabel(solverName_ + " coarse (2, 2)");
490 dump(coarseA22_, "coarseA22.m");
491 }
492
493 if (!reuse && !implicitTranspose_) {
495 if (!P22_.is_null())
497 }
498
499 if (!A22_.is_null()) {
501 std::string label("A22");
502 if (!P22_.is_null()) {
503 precList22_.sublist("level 1 user data").set("A", coarseA22_);
504 precList22_.sublist("level 1 user data").set("P", P22_);
506 precList22_.sublist("level 1 user data").set("R", R22_);
507 precList22_.sublist("level 1 user data").set("Nullspace", CoarseNullspace22_);
508 precList22_.sublist("level 1 user data").set("Coordinates", Coords22_);
509 // A22 is singular, we want to coarsen at least once.
510 // So we make sure coarseA22 is not just ignored.
511 int maxCoarseSize = precList22_.get("coarse: max size", MasterList::getDefault<int>("coarse: max size"));
512 int numRows = Teuchos::as<int>(coarseA22_->getGlobalNumRows());
513 if (maxCoarseSize > numRows)
514 precList22_.set("coarse: max size", numRows);
515 int maxLevels = precList22_.get("max levels", MasterList::getDefault<int>("max levels"));
516 if (maxLevels < 2)
517 precList22_.set("max levels", 2);
518 setupSubSolve(Hierarchy22_, thyraPrecOp22_, A22_, Teuchos::null, Teuchos::null, Material_alpha_, precList22_, label, reuse, /*isSingular=*/globalNumberBoundaryUnknowns11_ == 0);
519 } else
521
523 }
524 }
525
527 // Apply BCs to rows of Dk_1
528 if (!reuse && !onlyBoundary22_ && applyBCsTo22_) {
529 GetOStream(Runtime0) << solverName_ + "::compute(): nuking BC rows of Dk_1" << std::endl;
530
531 Dk_1_->resumeFill();
532 Scalar replaceWith = (Dk_1_->getRowMap()->lib() == Xpetra::UseEpetra) ? Teuchos::ScalarTraits<SC>::eps() : Teuchos::ScalarTraits<SC>::zero();
534 Dk_1_->fillComplete(Dk_1_->getDomainMap(), Dk_1_->getRangeMap());
535 dump(Dk_1_, "Dk_1_nuked.m");
536 }
537
539 // Set up the smoother on the finest level
541
542 if (!reuse) {
543 if (!ImporterCoarse11_.is_null()) {
544 RCP<const Import> ImporterP11 = ImportFactory::Build(ImporterCoarse11_->getTargetMap(), P11_->getColMap());
545 toCrsMatrix(P11_)->replaceDomainMapAndImporter(ImporterCoarse11_->getTargetMap(), ImporterP11);
546 }
547
548 if (!Importer22_.is_null()) {
549 if (enable_reuse_) {
550 DorigDomainMap_ = Dk_1_->getDomainMap();
551 DorigImporter_ = toCrsMatrix(Dk_1_)->getCrsGraph()->getImporter();
552 }
553 RCP<const Import> ImporterD = ImportFactory::Build(Importer22_->getTargetMap(), Dk_1_->getColMap());
554 toCrsMatrix(Dk_1_)->replaceDomainMapAndImporter(Importer22_->getTargetMap(), ImporterD);
555 }
556
557#ifdef HAVE_MUELU_TPETRA
558 if ((!Dk_1_T_.is_null()) &&
559 (!R11_.is_null()) &&
560 (!toCrsMatrix(Dk_1_T_)->getCrsGraph()->getImporter().is_null()) &&
561 (!toCrsMatrix(R11_)->getCrsGraph()->getImporter().is_null()) &&
562 (Dk_1_T_->getColMap()->lib() == Xpetra::UseTpetra) &&
563 (R11_->getColMap()->lib() == Xpetra::UseTpetra))
564 Dk_1_T_R11_colMapsMatch_ = Dk_1_T_->getColMap()->isSameAs(*R11_->getColMap());
565 else
566#endif
569 GetOStream(Runtime0) << solverName_ + "::compute(): Dk_1_T and R11 have matching colMaps" << std::endl;
570
571 asyncTransfers_ = parameterList_.get<bool>("refmaxwell: async transfers");
572
573 // Allocate MultiVectors for solve
575
576 // apply matvec params
577 if (parameterList_.isSublist("matvec params")) {
578 RCP<ParameterList> matvecParams = rcpFromRef(parameterList_.sublist("matvec params"));
582 if (!Dk_1_T_.is_null()) Maxwell_Utils<SC, LO, GO, NO>::setMatvecParams(*Dk_1_T_, matvecParams);
583 if (!R11_.is_null()) Maxwell_Utils<SC, LO, GO, NO>::setMatvecParams(*R11_, matvecParams);
584 if (!ImporterCoarse11_.is_null()) ImporterCoarse11_->setDistributorParameters(matvecParams);
585 if (!Importer22_.is_null()) Importer22_->setDistributorParameters(matvecParams);
586 }
587 if (!ImporterCoarse11_.is_null() && parameterList_.isSublist("refmaxwell: ImporterCoarse11 params")) {
588 RCP<ParameterList> importerParams = rcpFromRef(parameterList_.sublist("refmaxwell: ImporterCoarse11 params"));
589 ImporterCoarse11_->setDistributorParameters(importerParams);
590 }
591 if (!Importer22_.is_null() && parameterList_.isSublist("refmaxwell: Importer22 params")) {
592 RCP<ParameterList> importerParams = rcpFromRef(parameterList_.sublist("refmaxwell: Importer22 params"));
593 Importer22_->setDistributorParameters(importerParams);
594 }
595 }
596
598
599#ifdef HAVE_MUELU_CUDA
600 if (parameterList_.get<bool>("refmaxwell: cuda profile setup", false)) cudaProfilerStop();
601#endif
602}
603
604template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
606 determineSubHierarchyCommSizes(bool &doRebalancing, int &rebalanceStriding, int &numProcsCoarseA11, int &numProcsA22) {
607 doRebalancing = parameterList_.get<bool>("refmaxwell: subsolves on subcommunicators");
608 rebalanceStriding = parameterList_.get<int>("refmaxwell: subsolves striding", -1);
609 int numProcs = SM_Matrix_->getDomainMap()->getComm()->getSize();
610 if (numProcs == 1) {
611 doRebalancing = false;
612 return;
613 }
614
615#ifdef HAVE_MPI
616 if (doRebalancing) {
617 {
618 // decide on number of ranks for coarse (1, 1) problem
619
620 Level level;
621 level.SetFactoryManager(null);
622 level.SetLevelID(0);
623 level.Set("A", coarseA11_);
624
625 auto repartheurFactory = rcp(new RepartitionHeuristicFactory());
626 ParameterList repartheurParams;
627 repartheurParams.set("repartition: start level", 0);
628 // Setting min == target on purpose.
629 int defaultTargetRows = 10000;
630 repartheurParams.set("repartition: min rows per proc", precList11_.get<int>("repartition: target rows per proc", defaultTargetRows));
631 repartheurParams.set("repartition: target rows per proc", precList11_.get<int>("repartition: target rows per proc", defaultTargetRows));
632 repartheurParams.set("repartition: min rows per thread", precList11_.get<int>("repartition: target rows per thread", defaultTargetRows));
633 repartheurParams.set("repartition: target rows per thread", precList11_.get<int>("repartition: target rows per thread", defaultTargetRows));
634 repartheurParams.set("repartition: max imbalance", precList11_.get<double>("repartition: max imbalance", 1.1));
635 repartheurFactory->SetParameterList(repartheurParams);
636
637 level.Request("number of partitions", repartheurFactory.get());
638 repartheurFactory->Build(level);
639 numProcsCoarseA11 = level.Get<int>("number of partitions", repartheurFactory.get());
640 numProcsCoarseA11 = std::min(numProcsCoarseA11, numProcs);
641 }
642
643 {
644 // decide on number of ranks for (2, 2) problem
645
646 Level level;
647 level.SetFactoryManager(null);
648 level.SetLevelID(0);
649
650 level.Set("Map", Dk_1_->getDomainMap());
651
652 auto repartheurFactory = rcp(new RepartitionHeuristicFactory());
653 ParameterList repartheurParams;
654 repartheurParams.set("repartition: start level", 0);
655 repartheurParams.set("repartition: use map", true);
656 // Setting min == target on purpose.
657 int defaultTargetRows = 10000;
658 repartheurParams.set("repartition: min rows per proc", precList22_.get<int>("repartition: target rows per proc", defaultTargetRows));
659 repartheurParams.set("repartition: target rows per proc", precList22_.get<int>("repartition: target rows per proc", defaultTargetRows));
660 repartheurParams.set("repartition: min rows per thread", precList22_.get<int>("repartition: target rows per thread", defaultTargetRows));
661 repartheurParams.set("repartition: target rows per thread", precList22_.get<int>("repartition: target rows per thread", defaultTargetRows));
662 // repartheurParams.set("repartition: max imbalance", precList22_.get<double>("repartition: max imbalance", 1.1));
663 repartheurFactory->SetParameterList(repartheurParams);
664
665 level.Request("number of partitions", repartheurFactory.get());
666 repartheurFactory->Build(level);
667 numProcsA22 = level.Get<int>("number of partitions", repartheurFactory.get());
668 numProcsA22 = std::min(numProcsA22, numProcs);
669 }
670
671 if (rebalanceStriding >= 1) {
672 TEUCHOS_ASSERT(rebalanceStriding * numProcsCoarseA11 <= numProcs);
673 TEUCHOS_ASSERT(rebalanceStriding * numProcsA22 <= numProcs);
674 if (rebalanceStriding * (numProcsCoarseA11 + numProcsA22) > numProcs) {
675 GetOStream(Warnings0) << solverName_ + "::compute(): Disabling striding = " << rebalanceStriding << ", since coarseA11 needs " << numProcsCoarseA11
676 << " procs and A22 needs " << numProcsA22 << " procs." << std::endl;
677 rebalanceStriding = -1;
678 }
679 int lclBadMatrixDistribution = (coarseA11_->getLocalNumEntries() == 0) || (Dk_1_->getDomainMap()->getLocalNumElements() == 0);
680 int gblBadMatrixDistribution = false;
681 MueLu_maxAll(SM_Matrix_->getDomainMap()->getComm(), lclBadMatrixDistribution, gblBadMatrixDistribution);
682 if (gblBadMatrixDistribution) {
683 GetOStream(Warnings0) << solverName_ + "::compute(): Disabling striding = " << rebalanceStriding << ", since coarseA11 has no entries on at least one rank or Dk_1's domain map has no entries on at least one rank." << std::endl;
684 rebalanceStriding = -1;
685 }
686 }
687
688 if ((numProcsCoarseA11 < 0) || (numProcsA22 < 0) || (numProcsCoarseA11 + numProcsA22 > numProcs)) {
689 GetOStream(Warnings0) << solverName_ + "::compute(): Disabling rebalancing of subsolves, since partition heuristic resulted "
690 << "in undesirable number of partitions: " << numProcsCoarseA11 << ", " << numProcsA22 << std::endl;
691 doRebalancing = false;
692 }
693 }
694#else
695 doRebalancing = false;
696#endif // HAVE_MPI
697}
698
699template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
700RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>> RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
701 buildAddon(const int spaceNumber) {
702 if (spaceNumber == 0)
703 return Teuchos::null;
704
705 std::string timerLabel;
706 if (spaceNumber == spaceNumber_) {
708 timerLabel = "Build coarse addon matrix 11";
709 else
710 timerLabel = "Build addon matrix 11";
711 } else
712 timerLabel = "Build addon matrix 22";
713
714 RCP<Teuchos::TimeMonitor> tmAddon = getTimer(timerLabel);
715
716 RCP<Matrix> addon;
717 RCP<Matrix> Z;
718 RCP<Matrix> lumpedInverse;
719 if (spaceNumber == spaceNumber_) {
720 // catch a failure
721 TEUCHOS_TEST_FOR_EXCEPTION(invMk_1_invBeta_ == Teuchos::null, std::invalid_argument,
723 "::buildCoarse11Matrix(): Inverse of "
724 "lumped mass matrix required for add-on (i.e. invMk_1_invBeta_ is null)");
725 lumpedInverse = invMk_1_invBeta_;
726
727 if (skipFirst11Level_) {
728 // construct Zaux = M1 P11
729 RCP<Matrix> Zaux;
730 Zaux = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*Mk_one_, false, *P11_, false, Zaux, GetOStream(Runtime0), true, true);
731 // construct Z = D* M1 P11 = D^T Zaux
732 Z = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*Dk_1_, true, *Zaux, false, Z, GetOStream(Runtime0), true, true);
733 } else {
734 // construct Z = D* M1 P11 = D^T Zaux
735 Z = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*Dk_1_, true, *Mk_one_, false, Z, GetOStream(Runtime0), true, true);
736 }
737
738 } else if (spaceNumber == spaceNumber_ - 1) {
739 // catch a failure
740 TEUCHOS_TEST_FOR_EXCEPTION(invMk_2_invAlpha_ == Teuchos::null, std::invalid_argument,
742 "::buildCoarse11Matrix(): Inverse of "
743 "lumped mass matrix required for add-on (i.e. invMk_2_invAlpha_ is null)");
744 lumpedInverse = invMk_2_invAlpha_;
745
746 // construct Z = Dk_2^T Mk_1_one
747 Z = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*Dk_2_, true, *Mk_1_one_, false, Z, GetOStream(Runtime0), true, true);
748 }
749
750 // construct Z^T lumpedInverse Z
751 if (lumpedInverse->getGlobalMaxNumRowEntries() <= 1) {
752 // We assume that if lumpedInverse has at most one entry per row then
753 // these are all diagonal entries.
754 RCP<Vector> diag = VectorFactory::Build(lumpedInverse->getRowMap());
755 lumpedInverse->getLocalDiagCopy(*diag);
756 {
757 ArrayRCP<Scalar> diagVals = diag->getDataNonConst(0);
758 for (size_t j = 0; j < diag->getMap()->getLocalNumElements(); j++) {
759 diagVals[j] = Teuchos::ScalarTraits<Scalar>::squareroot(diagVals[j]);
760 }
761 }
762 if (Z->getRowMap()->isSameAs(*(diag->getMap())))
763 Z->leftScale(*diag);
764 else {
765 RCP<Import> importer = ImportFactory::Build(diag->getMap(), Z->getRowMap());
766 RCP<Vector> diag2 = VectorFactory::Build(Z->getRowMap());
767 diag2->doImport(*diag, *importer, Xpetra::INSERT);
768 Z->leftScale(*diag2);
769 }
770 addon = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*Z, true, *Z, false, addon, GetOStream(Runtime0), true, true);
771 } else if (parameterList_.get<bool>("rap: triple product", false) == false) {
772 RCP<Matrix> C2;
773 // construct C2 = lumpedInverse Z
774 C2 = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*lumpedInverse, false, *Z, false, C2, GetOStream(Runtime0), true, true);
775 // construct Matrix2 = Z* M0inv Z = Z* C2
776 addon = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*Z, true, *C2, false, addon, GetOStream(Runtime0), true, true);
777 } else {
778 addon = MatrixFactory::Build(Z->getDomainMap());
779 // construct Matrix2 = Z^T lumpedInverse Z
780 Xpetra::TripleMatrixMultiply<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
781 MultiplyRAP(*Z, true, *lumpedInverse, false, *Z, false, *addon, true, true);
782 }
783 return addon;
784}
785
786template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
788 RCP<Teuchos::TimeMonitor> tm = getTimer("Build coarse (1,1) matrix");
789
790 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
791
792 // coarse matrix for P11* (M1 + D1* M2 D1) P11
793 RCP<Matrix> temp;
794 temp = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*SM_Matrix_, false, *P11_, false, temp, GetOStream(Runtime0), true, true);
795 if (ImporterCoarse11_.is_null())
796 coarseA11_ = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*P11_, true, *temp, false, coarseA11_, GetOStream(Runtime0), true, true);
797 else {
798 RCP<Matrix> temp2;
799 temp2 = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*P11_, true, *temp, false, temp2, GetOStream(Runtime0), true, true);
800
801 RCP<const Map> map = ImporterCoarse11_->getTargetMap()->removeEmptyProcesses();
802 temp2->removeEmptyProcessesInPlace(map);
803 if (!temp2.is_null() && temp2->getRowMap().is_null())
804 temp2 = Teuchos::null;
805 coarseA11_ = temp2;
806 }
807
808 if (!disable_addon_) {
809 RCP<Matrix> addon;
810
811 if (!coarseA11_.is_null() && Addon11_.is_null()) {
812 addon = buildAddon(spaceNumber_);
813 // Should we keep the addon for next setup?
814 if (enable_reuse_)
815 Addon11_ = addon;
816 } else
817 addon = Addon11_;
818
819 if (!coarseA11_.is_null()) {
820 // add matrices together
821 RCP<Matrix> newCoarseA11;
822 Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::TwoMatrixAdd(*coarseA11_, false, one, *addon, false, one, newCoarseA11, GetOStream(Runtime0));
823 newCoarseA11->fillComplete();
824 coarseA11_ = newCoarseA11;
825 }
826 }
827
828 if (!coarseA11_.is_null() && !skipFirst11Level_) {
829 ArrayRCP<bool> coarseA11BCrows;
830 coarseA11BCrows.resize(coarseA11_->getRowMap()->getLocalNumElements());
831 for (size_t i = 0; i < BCdomain22_.size(); i++)
832 for (size_t k = 0; k < dim_; k++)
833 coarseA11BCrows[i * dim_ + k] = BCdomain22_(i);
834 magnitudeType rowSumTol = parameterList_.get<double>("refmaxwell: row sum drop tol (1,1)");
835 if (rowSumTol > 0.)
836 Utilities::ApplyRowSumCriterion(*coarseA11_, rowSumTol, coarseA11BCrows);
839 }
840
841 if (!coarseA11_.is_null()) {
842 // If we already applied BCs to A_nodal, we likely do not need
843 // to fix up coarseA11.
844 // If we did not apply BCs to A_nodal, we now need to correct
845 // the zero diagonals of coarseA11, since we did nuke the nullspace.
846
847 bool fixZeroDiagonal = !applyBCsToAnodal_;
848 if (precList11_.isParameter("rap: fix zero diagonals"))
849 fixZeroDiagonal = precList11_.get<bool>("rap: fix zero diagonals");
850
851 if (fixZeroDiagonal) {
852 magnitudeType threshold = 1e-16;
853 Scalar replacement = 1.0;
854 if (precList11_.isType<magnitudeType>("rap: fix zero diagonals threshold"))
855 threshold = precList11_.get<magnitudeType>("rap: fix zero diagonals threshold");
856 else if (precList11_.isType<double>("rap: fix zero diagonals threshold"))
857 threshold = Teuchos::as<magnitudeType>(precList11_.get<double>("rap: fix zero diagonals threshold"));
858 if (precList11_.isType<double>("rap: fix zero diagonals replacement"))
859 replacement = Teuchos::as<Scalar>(precList11_.get<double>("rap: fix zero diagonals replacement"));
860 Xpetra::MatrixUtils<SC, LO, GO, NO>::CheckRepairMainDiagonal(coarseA11_, true, GetOStream(Warnings1), threshold, replacement);
861 }
862
863 // Set block size
864 coarseA11_->SetFixedBlockSize(dim_);
866 coarseA11_->setObjectLabel(solverName_ + " coarse (1,1)");
867 else
868 coarseA11_->setObjectLabel(solverName_ + " (1,1)");
869 }
870}
871
872template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
874 rebalanceCoarse11Matrix(const int rebalanceStriding, const int numProcsCoarseA11) {
875#ifdef HAVE_MPI
876 // rebalance coarseA11
877 RCP<Teuchos::TimeMonitor> tm = getTimer("Rebalance coarseA11");
878
879 Level fineLevel, coarseLevel;
880 fineLevel.SetFactoryManager(null);
881 coarseLevel.SetFactoryManager(null);
882 coarseLevel.SetPreviousLevel(rcpFromRef(fineLevel));
883 fineLevel.SetLevelID(0);
884 coarseLevel.SetLevelID(1);
885 coarseLevel.Set("A", coarseA11_);
886 coarseLevel.Set("P", P11_);
887 coarseLevel.Set("Coordinates", CoordsCoarse11_);
888 if (!NullspaceCoarse11_.is_null())
889 coarseLevel.Set("Nullspace", NullspaceCoarse11_);
890 coarseLevel.Set("number of partitions", numProcsCoarseA11);
891 coarseLevel.Set("repartition: heuristic target rows per process", 1000);
892
893 coarseLevel.setlib(coarseA11_->getDomainMap()->lib());
894 fineLevel.setlib(coarseA11_->getDomainMap()->lib());
895 coarseLevel.setObjectLabel(solverName_ + " coarse (1,1)");
896 fineLevel.setObjectLabel(solverName_ + " coarse (1,1)");
897
898 std::string partName = precList11_.get<std::string>("repartition: partitioner", "zoltan2");
899 RCP<Factory> partitioner;
900 if (partName == "zoltan") {
901#ifdef HAVE_MUELU_ZOLTAN
902 partitioner = rcp(new ZoltanInterface());
903 // NOTE: ZoltanInteface ("zoltan") does not support external parameters through ParameterList
904 // partitioner->SetFactory("number of partitions", repartheurFactory);
905#else
906 throw Exceptions::RuntimeError("Zoltan interface is not available");
907#endif
908 } else if (partName == "zoltan2") {
909#ifdef HAVE_MUELU_ZOLTAN2
910 partitioner = rcp(new Zoltan2Interface());
911 ParameterList partParams;
912 RCP<const ParameterList> partpartParams = rcp(new ParameterList(precList11_.sublist("repartition: params", false)));
913 partParams.set("ParameterList", partpartParams);
914 partitioner->SetParameterList(partParams);
915 // partitioner->SetFactory("number of partitions", repartheurFactory);
916#else
917 throw Exceptions::RuntimeError("Zoltan2 interface is not available");
918#endif
919 }
920
921 auto repartFactory = rcp(new RepartitionFactory());
922 ParameterList repartParams;
923 repartParams.set("repartition: print partition distribution", precList11_.get<bool>("repartition: print partition distribution", false));
924 repartParams.set("repartition: remap parts", precList11_.get<bool>("repartition: remap parts", true));
925 if (rebalanceStriding >= 1) {
926 bool acceptPart = (SM_Matrix_->getDomainMap()->getComm()->getRank() % rebalanceStriding) == 0;
927 if (SM_Matrix_->getDomainMap()->getComm()->getRank() >= numProcsCoarseA11 * rebalanceStriding)
928 acceptPart = false;
929 repartParams.set("repartition: remap accept partition", acceptPart);
930 }
931 repartFactory->SetParameterList(repartParams);
932 // repartFactory->SetFactory("number of partitions", repartheurFactory);
933 repartFactory->SetFactory("Partition", partitioner);
934
935 auto newP = rcp(new RebalanceTransferFactory());
936 ParameterList newPparams;
937 newPparams.set("type", "Interpolation");
938 newPparams.set("repartition: rebalance P and R", precList11_.get<bool>("repartition: rebalance P and R", false));
939 newPparams.set("repartition: use subcommunicators", true);
940 newPparams.set("repartition: rebalance Nullspace", !NullspaceCoarse11_.is_null());
941 newP->SetFactory("Coordinates", NoFactory::getRCP());
942 if (!NullspaceCoarse11_.is_null())
943 newP->SetFactory("Nullspace", NoFactory::getRCP());
944 newP->SetParameterList(newPparams);
945 newP->SetFactory("Importer", repartFactory);
946
947 auto newA = rcp(new RebalanceAcFactory());
948 ParameterList rebAcParams;
949 rebAcParams.set("repartition: use subcommunicators", true);
950 newA->SetParameterList(rebAcParams);
951 newA->SetFactory("Importer", repartFactory);
952
953 coarseLevel.Request("P", newP.get());
954 coarseLevel.Request("Importer", repartFactory.get());
955 coarseLevel.Request("A", newA.get());
956 coarseLevel.Request("Coordinates", newP.get());
957 if (!NullspaceCoarse11_.is_null())
958 coarseLevel.Request("Nullspace", newP.get());
959 repartFactory->Build(coarseLevel);
960
961 if (!precList11_.get<bool>("repartition: rebalance P and R", false))
962 ImporterCoarse11_ = coarseLevel.Get<RCP<const Import>>("Importer", repartFactory.get());
963 P11_ = coarseLevel.Get<RCP<Matrix>>("P", newP.get());
964 coarseA11_ = coarseLevel.Get<RCP<Matrix>>("A", newA.get());
965 CoordsCoarse11_ = coarseLevel.Get<RCP<RealValuedMultiVector>>("Coordinates", newP.get());
966 if (!NullspaceCoarse11_.is_null())
967 NullspaceCoarse11_ = coarseLevel.Get<RCP<MultiVector>>("Nullspace", newP.get());
968
969 if (!coarseA11_.is_null()) {
970 // Set block size
971 coarseA11_->SetFixedBlockSize(dim_);
973 coarseA11_->setObjectLabel(solverName_ + " coarse (1,1)");
974 else
975 coarseA11_->setObjectLabel(solverName_ + " (1,1)");
976 }
977
978 coarseA11_AP_reuse_data_ = Teuchos::null;
979 coarseA11_RAP_reuse_data_ = Teuchos::null;
980
982 // Rebalance the addon for next setup
983 RCP<const Import> ImporterCoarse11 = coarseLevel.Get<RCP<const Import>>("Importer", repartFactory.get());
984 RCP<const Map> targetMap = ImporterCoarse11->getTargetMap();
985 ParameterList XpetraList;
986 XpetraList.set("Restrict Communicator", true);
987 Addon11_ = MatrixFactory::Build(Addon11_, *ImporterCoarse11, *ImporterCoarse11, targetMap, targetMap, rcp(&XpetraList, false));
988 }
989#endif
990}
991
992template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
993void RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::build22Matrix(const bool reuse, const bool doRebalancing, const int rebalanceStriding, const int numProcsA22) {
994 if (!reuse) { // build fine grid operator for (2,2)-block, Dk_1^T SM Dk_1 (aka TMT)
995 RCP<Teuchos::TimeMonitor> tm = getTimer("Build A22");
996
997 Level fineLevel, coarseLevel;
998 fineLevel.SetFactoryManager(null);
999 coarseLevel.SetFactoryManager(null);
1000 coarseLevel.SetPreviousLevel(rcpFromRef(fineLevel));
1001 fineLevel.SetLevelID(0);
1002 coarseLevel.SetLevelID(1);
1003 fineLevel.Set("A", SM_Matrix_);
1004 coarseLevel.Set("P", Dk_1_);
1005 coarseLevel.Set("Coordinates", Coords22_);
1006
1007 coarseLevel.setlib(SM_Matrix_->getDomainMap()->lib());
1008 fineLevel.setlib(SM_Matrix_->getDomainMap()->lib());
1009 coarseLevel.setObjectLabel(solverName_ + " (2,2)");
1010 fineLevel.setObjectLabel(solverName_ + " (2,2)");
1011
1012 RCP<RAPFactory> rapFact = rcp(new RAPFactory());
1013 ParameterList rapList = *(rapFact->GetValidParameterList());
1014 rapList.set("transpose: use implicit", true);
1015 rapList.set("rap: fix zero diagonals", parameterList_.get<bool>("rap: fix zero diagonals", true));
1016 rapList.set("rap: fix zero diagonals threshold", parameterList_.get<double>("rap: fix zero diagonals threshold", Teuchos::ScalarTraits<double>::eps()));
1017 rapList.set("rap: triple product", parameterList_.get<bool>("rap: triple product", false));
1018 rapFact->SetParameterList(rapList);
1019
1020 if (!A22_AP_reuse_data_.is_null()) {
1021 coarseLevel.AddKeepFlag("AP reuse data", rapFact.get());
1022 coarseLevel.Set<Teuchos::RCP<Teuchos::ParameterList>>("AP reuse data", A22_AP_reuse_data_, rapFact.get());
1023 }
1024 if (!A22_RAP_reuse_data_.is_null()) {
1025 coarseLevel.AddKeepFlag("RAP reuse data", rapFact.get());
1026 coarseLevel.Set<Teuchos::RCP<Teuchos::ParameterList>>("RAP reuse data", A22_RAP_reuse_data_, rapFact.get());
1027 }
1028
1029#ifdef HAVE_MPI
1030 if (doRebalancing) {
1031 coarseLevel.Set("number of partitions", numProcsA22);
1032 coarseLevel.Set("repartition: heuristic target rows per process", 1000);
1033
1034 std::string partName = precList22_.get<std::string>("repartition: partitioner", "zoltan2");
1035 RCP<Factory> partitioner;
1036 if (partName == "zoltan") {
1037#ifdef HAVE_MUELU_ZOLTAN
1038 partitioner = rcp(new ZoltanInterface());
1039 partitioner->SetFactory("A", rapFact);
1040 // partitioner->SetFactory("number of partitions", repartheurFactory);
1041 // NOTE: ZoltanInteface ("zoltan") does not support external parameters through ParameterList
1042#else
1043 throw Exceptions::RuntimeError("Zoltan interface is not available");
1044#endif
1045 } else if (partName == "zoltan2") {
1046#ifdef HAVE_MUELU_ZOLTAN2
1047 partitioner = rcp(new Zoltan2Interface());
1048 ParameterList partParams;
1049 RCP<const ParameterList> partpartParams = rcp(new ParameterList(precList22_.sublist("repartition: params", false)));
1050 partParams.set("ParameterList", partpartParams);
1051 partitioner->SetParameterList(partParams);
1052 partitioner->SetFactory("A", rapFact);
1053 // partitioner->SetFactory("number of partitions", repartheurFactory);
1054#else
1055 throw Exceptions::RuntimeError("Zoltan2 interface is not available");
1056#endif
1057 }
1058
1059 auto repartFactory = rcp(new RepartitionFactory());
1060 ParameterList repartParams;
1061 repartParams.set("repartition: print partition distribution", precList22_.get<bool>("repartition: print partition distribution", false));
1062 repartParams.set("repartition: remap parts", precList22_.get<bool>("repartition: remap parts", true));
1063 if (rebalanceStriding >= 1) {
1064 bool acceptPart = ((SM_Matrix_->getDomainMap()->getComm()->getSize() - 1 - SM_Matrix_->getDomainMap()->getComm()->getRank()) % rebalanceStriding) == 0;
1065 if (SM_Matrix_->getDomainMap()->getComm()->getSize() - 1 - SM_Matrix_->getDomainMap()->getComm()->getRank() >= numProcsA22 * rebalanceStriding)
1066 acceptPart = false;
1067 if (acceptPart)
1068 TEUCHOS_ASSERT(coarseA11_.is_null());
1069 repartParams.set("repartition: remap accept partition", acceptPart);
1070 } else
1071 repartParams.set("repartition: remap accept partition", coarseA11_.is_null());
1072 repartFactory->SetParameterList(repartParams);
1073 repartFactory->SetFactory("A", rapFact);
1074 // repartFactory->SetFactory("number of partitions", repartheurFactory);
1075 repartFactory->SetFactory("Partition", partitioner);
1076
1077 auto newP = rcp(new RebalanceTransferFactory());
1078 ParameterList newPparams;
1079 newPparams.set("type", "Interpolation");
1080 newPparams.set("repartition: rebalance P and R", precList22_.get<bool>("repartition: rebalance P and R", false));
1081 newPparams.set("repartition: use subcommunicators", true);
1082 newPparams.set("repartition: rebalance Nullspace", false);
1083 newP->SetFactory("Coordinates", NoFactory::getRCP());
1084 newP->SetParameterList(newPparams);
1085 newP->SetFactory("Importer", repartFactory);
1086
1087 auto newA = rcp(new RebalanceAcFactory());
1088 ParameterList rebAcParams;
1089 rebAcParams.set("repartition: use subcommunicators", true);
1090 newA->SetParameterList(rebAcParams);
1091 newA->SetFactory("A", rapFact);
1092 newA->SetFactory("Importer", repartFactory);
1093
1094 coarseLevel.Request("P", newP.get());
1095 coarseLevel.Request("Importer", repartFactory.get());
1096 coarseLevel.Request("A", newA.get());
1097 coarseLevel.Request("Coordinates", newP.get());
1098 rapFact->Build(fineLevel, coarseLevel);
1099 repartFactory->Build(coarseLevel);
1100
1101 if (!precList22_.get<bool>("repartition: rebalance P and R", false))
1102 Importer22_ = coarseLevel.Get<RCP<const Import>>("Importer", repartFactory.get());
1103 Dk_1_ = coarseLevel.Get<RCP<Matrix>>("P", newP.get());
1104 A22_ = coarseLevel.Get<RCP<Matrix>>("A", newA.get());
1105 Coords22_ = coarseLevel.Get<RCP<RealValuedMultiVector>>("Coordinates", newP.get());
1106
1107 if (!P22_.is_null()) {
1108 // Todo
1109 }
1110
1111 } else
1112#endif // HAVE_MPI
1113 {
1114 coarseLevel.Request("A", rapFact.get());
1115 if (enable_reuse_) {
1116 coarseLevel.Request("AP reuse data", rapFact.get());
1117 coarseLevel.Request("RAP reuse data", rapFact.get());
1118 }
1119
1120 A22_ = coarseLevel.Get<RCP<Matrix>>("A", rapFact.get());
1121
1122 if (enable_reuse_) {
1123 if (coarseLevel.IsAvailable("AP reuse data", rapFact.get()))
1124 A22_AP_reuse_data_ = coarseLevel.Get<RCP<ParameterList>>("AP reuse data", rapFact.get());
1125 if (coarseLevel.IsAvailable("RAP reuse data", rapFact.get()))
1126 A22_RAP_reuse_data_ = coarseLevel.Get<RCP<ParameterList>>("RAP reuse data", rapFact.get());
1127 }
1128 }
1129 } else {
1130 RCP<Teuchos::TimeMonitor> tm = getTimer("Build A22");
1131 if (Importer22_.is_null()) {
1132 RCP<Matrix> temp;
1133 temp = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*SM_Matrix_, false, *Dk_1_, false, temp, GetOStream(Runtime0), true, true);
1134 if (!implicitTranspose_)
1135 A22_ = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*Dk_1_T_, false, *temp, false, A22_, GetOStream(Runtime0), true, true);
1136 else
1137 A22_ = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*Dk_1_, true, *temp, false, A22_, GetOStream(Runtime0), true, true);
1138 } else {
1139 // we replaced domain map and importer on D, reverse that
1140 RCP<const Import> Dimporter = toCrsMatrix(Dk_1_)->getCrsGraph()->getImporter();
1141 toCrsMatrix(Dk_1_)->replaceDomainMapAndImporter(DorigDomainMap_, DorigImporter_);
1142
1143 RCP<Matrix> temp, temp2;
1144 temp = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*SM_Matrix_, false, *Dk_1_, false, temp, GetOStream(Runtime0), true, true);
1145 if (!implicitTranspose_)
1146 temp2 = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*Dk_1_T_, false, *temp, false, temp2, GetOStream(Runtime0), true, true);
1147 else
1148 temp2 = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*Dk_1_, true, *temp, false, temp2, GetOStream(Runtime0), true, true);
1149
1150 // and back again
1151 toCrsMatrix(Dk_1_)->replaceDomainMapAndImporter(Importer22_->getTargetMap(), Dimporter);
1152
1153 ParameterList XpetraList;
1154 XpetraList.set("Restrict Communicator", true);
1155 XpetraList.set("Timer Label", "MueLu::RebalanceA22");
1156 RCP<const Map> targetMap = Importer22_->getTargetMap();
1157 A22_ = MatrixFactory::Build(temp2, *Importer22_, *Importer22_, targetMap, targetMap, rcp(&XpetraList, false));
1158 }
1159 }
1160
1161 if (not A22_.is_null() and not disable_addon_22_ and spaceNumber_ > 1) {
1162 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1163
1164 RCP<Matrix> addon22 = buildAddon(spaceNumber_ - 1);
1165
1166 // add matrices together
1167 RCP<Matrix> newA22;
1168 Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::TwoMatrixAdd(*A22_, false, one, *addon22, false, one, newA22, GetOStream(Runtime0));
1169 newA22->fillComplete();
1170 A22_ = newA22;
1171 }
1172
1173 if (!A22_.is_null()) {
1174 dump(A22_, "A22.m");
1175 A22_->setObjectLabel(solverName_ + " (2,2)");
1176 // Set block size
1177 if (spaceNumber_ - 1 == 0)
1178 A22_->SetFixedBlockSize(1);
1179 else
1180 A22_->SetFixedBlockSize(dim_);
1181 }
1182}
1183
1184template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1186 Level level;
1187 RCP<MueLu::FactoryManagerBase> factoryHandler = rcp(new FactoryManager());
1188 level.SetFactoryManager(factoryHandler);
1189 level.SetLevelID(0);
1190 level.setObjectLabel(solverName_ + " (1,1)");
1191 level.Set("A", SM_Matrix_);
1192 level.setlib(SM_Matrix_->getDomainMap()->lib());
1193 // For Hiptmair
1194 level.Set("NodeMatrix", A22_);
1195 level.Set("D0", Dk_1_);
1196
1197 if ((parameterList_.get<std::string>("smoother: pre type") != "NONE") && (parameterList_.get<std::string>("smoother: post type") != "NONE")) {
1198 std::string preSmootherType = parameterList_.get<std::string>("smoother: pre type");
1199 std::string postSmootherType = parameterList_.get<std::string>("smoother: post type");
1200
1201 ParameterList preSmootherList, postSmootherList;
1202 if (parameterList_.isSublist("smoother: pre params"))
1203 preSmootherList = parameterList_.sublist("smoother: pre params");
1204 if (parameterList_.isSublist("smoother: post params"))
1205 postSmootherList = parameterList_.sublist("smoother: post params");
1206
1207 RCP<SmootherPrototype> preSmootherPrototype = rcp(new TrilinosSmoother(preSmootherType, preSmootherList));
1208 RCP<SmootherPrototype> postSmootherPrototype = rcp(new TrilinosSmoother(postSmootherType, postSmootherList));
1209 RCP<SmootherFactory> smootherFact = rcp(new SmootherFactory(preSmootherPrototype, postSmootherPrototype));
1210
1211 level.Request("PreSmoother", smootherFact.get());
1212 level.Request("PostSmoother", smootherFact.get());
1213 if (enable_reuse_) {
1214 ParameterList smootherFactoryParams;
1215 smootherFactoryParams.set("keep smoother data", true);
1216 smootherFact->SetParameterList(smootherFactoryParams);
1217 level.Request("PreSmoother data", smootherFact.get());
1218 level.Request("PostSmoother data", smootherFact.get());
1219 if (!PreSmootherData11_.is_null())
1220 level.Set("PreSmoother data", PreSmootherData11_, smootherFact.get());
1221 if (!PostSmootherData11_.is_null())
1222 level.Set("PostSmoother data", PostSmootherData11_, smootherFact.get());
1223 }
1224 smootherFact->Build(level);
1225 PreSmoother11_ = level.Get<RCP<SmootherBase>>("PreSmoother", smootherFact.get());
1226 PostSmoother11_ = level.Get<RCP<SmootherBase>>("PostSmoother", smootherFact.get());
1227 if (enable_reuse_) {
1228 PreSmootherData11_ = level.Get<RCP<SmootherPrototype>>("PreSmoother data", smootherFact.get());
1229 PostSmootherData11_ = level.Get<RCP<SmootherPrototype>>("PostSmoother data", smootherFact.get());
1230 }
1231 } else {
1232 std::string smootherType = parameterList_.get<std::string>("smoother: type");
1233
1234 ParameterList smootherList;
1235 if (parameterList_.isSublist("smoother: params"))
1236 smootherList = parameterList_.sublist("smoother: params");
1237
1238 RCP<SmootherPrototype> smootherPrototype = rcp(new TrilinosSmoother(smootherType, smootherList));
1239 RCP<SmootherFactory> smootherFact = rcp(new SmootherFactory(smootherPrototype));
1240 level.Request("PreSmoother", smootherFact.get());
1241 if (enable_reuse_) {
1242 ParameterList smootherFactoryParams;
1243 smootherFactoryParams.set("keep smoother data", true);
1244 smootherFact->SetParameterList(smootherFactoryParams);
1245 level.Request("PreSmoother data", smootherFact.get());
1246 if (!PreSmootherData11_.is_null())
1247 level.Set("PreSmoother data", PreSmootherData11_, smootherFact.get());
1248 }
1249 smootherFact->Build(level);
1250 PreSmoother11_ = level.Get<RCP<SmootherBase>>("PreSmoother", smootherFact.get());
1252 if (enable_reuse_)
1253 PreSmootherData11_ = level.Get<RCP<SmootherPrototype>>("PreSmoother data", smootherFact.get());
1254 }
1255}
1256
1257template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1259 RCP<Teuchos::TimeMonitor> tmAlloc = getTimer("Allocate MVs");
1260
1261 // 11 block
1262 if (!R11_.is_null())
1263 P11res_ = MultiVectorFactory::Build(R11_->getRangeMap(), numVectors);
1264 else
1265 P11res_ = MultiVectorFactory::Build(P11_->getDomainMap(), numVectors);
1266 P11res_->setObjectLabel("P11res");
1267
1269 DTR11Tmp_ = MultiVectorFactory::Build(R11_->getColMap(), numVectors);
1270 DTR11Tmp_->setObjectLabel("DTR11Tmp");
1271 }
1272 if (!ImporterCoarse11_.is_null()) {
1273 P11resTmp_ = MultiVectorFactory::Build(ImporterCoarse11_->getTargetMap(), numVectors);
1274 P11resTmp_->setObjectLabel("P11resTmp");
1275 P11x_ = MultiVectorFactory::Build(ImporterCoarse11_->getTargetMap(), numVectors);
1276 } else
1277 P11x_ = MultiVectorFactory::Build(P11_->getDomainMap(), numVectors);
1278 P11x_->setObjectLabel("P11x");
1279
1280 // 22 block
1281 if (!Dk_1_T_.is_null())
1282 Dres_ = MultiVectorFactory::Build(Dk_1_T_->getRangeMap(), numVectors);
1283 else
1284 Dres_ = MultiVectorFactory::Build(Dk_1_->getDomainMap(), numVectors);
1285 Dres_->setObjectLabel("Dres");
1286
1287 if (!Importer22_.is_null()) {
1288 DresTmp_ = MultiVectorFactory::Build(Importer22_->getTargetMap(), numVectors);
1289 DresTmp_->setObjectLabel("DresTmp");
1290 Dx_ = MultiVectorFactory::Build(Importer22_->getTargetMap(), numVectors);
1291 } else if (!onlyBoundary22_)
1292 Dx_ = MultiVectorFactory::Build(A22_->getDomainMap(), numVectors);
1293 if (!Dx_.is_null())
1294 Dx_->setObjectLabel("Dx");
1295
1296 if (!coarseA11_.is_null()) {
1297 if (!ImporterCoarse11_.is_null() && !implicitTranspose_)
1298 P11resSubComm_ = MultiVectorFactory::Build(P11resTmp_, Teuchos::View);
1299 else
1300 P11resSubComm_ = MultiVectorFactory::Build(P11res_, Teuchos::View);
1301 P11resSubComm_->replaceMap(coarseA11_->getRangeMap());
1302 P11resSubComm_->setObjectLabel("P11resSubComm");
1303
1304 P11xSubComm_ = MultiVectorFactory::Build(P11x_, Teuchos::View);
1305 P11xSubComm_->replaceMap(coarseA11_->getDomainMap());
1306 P11xSubComm_->setObjectLabel("P11xSubComm");
1307 }
1308
1309 if (!A22_.is_null()) {
1310 if (!Importer22_.is_null() && !implicitTranspose_)
1311 DresSubComm_ = MultiVectorFactory::Build(DresTmp_, Teuchos::View);
1312 else
1313 DresSubComm_ = MultiVectorFactory::Build(Dres_, Teuchos::View);
1314 DresSubComm_->replaceMap(A22_->getRangeMap());
1315 DresSubComm_->setObjectLabel("DresSubComm");
1316
1317 DxSubComm_ = MultiVectorFactory::Build(Dx_, Teuchos::View);
1318 DxSubComm_->replaceMap(A22_->getDomainMap());
1319 DxSubComm_->setObjectLabel("DxSubComm");
1320 }
1321
1322 if (asyncTransfers_) {
1323 if (!toCrsMatrix(P11_)->getCrsGraph()->getImporter().is_null())
1324 P11x_colmap_ = MultiVectorFactory::Build(P11_->getColMap(), numVectors);
1325 if (!toCrsMatrix(Dk_1_)->getCrsGraph()->getImporter().is_null())
1326 Dx_colmap_ = MultiVectorFactory::Build(Dk_1_->getColMap(), numVectors);
1327 }
1328
1329 residual_ = MultiVectorFactory::Build(SM_Matrix_->getDomainMap(), numVectors);
1330 residual_->setObjectLabel("residual");
1331}
1332
1333template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1334void RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dump(const RCP<Matrix> &A, std::string name) const {
1335 if (dump_matrices_ && !A.is_null()) {
1336 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
1337 Xpetra::IO<SC, LO, GO, NO>::Write(name, *A);
1338 }
1339}
1340
1341template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1342void RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dump(const RCP<MultiVector> &X, std::string name) const {
1343 if (dump_matrices_ && !X.is_null()) {
1344 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
1345 Xpetra::IO<SC, LO, GO, NO>::Write(name, *X);
1346 }
1347}
1348
1349template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1350void RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dumpCoords(const RCP<RealValuedMultiVector> &X, std::string name) const {
1351 if (dump_matrices_ && !X.is_null()) {
1352 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
1353 Xpetra::IO<coordinateType, LO, GO, NO>::Write(name, *X);
1354 }
1355}
1356
1357template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1358void RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dump(const Teuchos::ArrayRCP<bool> &v, std::string name) const {
1359 if (dump_matrices_) {
1360 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
1361 std::ofstream out(name);
1362 for (size_t i = 0; i < Teuchos::as<size_t>(v.size()); i++)
1363 out << v[i] << "\n";
1364 }
1365}
1366
1367template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1368void RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dump(const Kokkos::View<bool *, typename Node::device_type> &v, std::string name) const {
1369 if (dump_matrices_) {
1370 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
1371 std::ofstream out(name);
1372 auto vH = Kokkos::create_mirror_view(v);
1373 Kokkos::deep_copy(vH, v);
1374 out << "%%MatrixMarket matrix array real general\n"
1375 << vH.extent(0) << " 1\n";
1376 for (size_t i = 0; i < vH.size(); i++)
1377 out << vH[i] << "\n";
1378 }
1379}
1380
1381template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1382Teuchos::RCP<Teuchos::TimeMonitor> RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getTimer(std::string name, RCP<const Teuchos::Comm<int>> comm) const {
1383 if (IsPrint(Timings)) {
1384 if (!syncTimers_)
1385 return Teuchos::rcp(new Teuchos::TimeMonitor(*Teuchos::TimeMonitor::getNewTimer("MueLu " + solverName_ + ": " + name)));
1386 else {
1387 if (comm.is_null()) {
1388 {
1389 Teuchos::rcp(new Teuchos::TimeMonitor(*Teuchos::TimeMonitor::getNewTimer("MueLu " + solverName_ + ": " + name + "_barrier")));
1390 SM_Matrix_->getRowMap()->getComm()->barrier();
1391 }
1392 return Teuchos::rcp(new Teuchos::TimeMonitor(*Teuchos::TimeMonitor::getNewTimer("MueLu " + solverName_ + ": " + name)));
1393 } else {
1394 {
1395 Teuchos::rcp(new Teuchos::TimeMonitor(*Teuchos::TimeMonitor::getNewTimer("MueLu " + solverName_ + ": " + name + "_barrier")));
1396 comm->barrier();
1397 }
1398 return Teuchos::rcp(new Teuchos::TimeMonitor(*Teuchos::TimeMonitor::getNewTimer("MueLu " + solverName_ + ": " + name)));
1399 }
1400 }
1401 } else
1402 return Teuchos::null;
1403}
1404
1405template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1406RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1407 buildNullspace(const int spaceNumber, const Kokkos::View<bool *, typename Node::device_type> &bcs, const bool applyBCs) {
1408 std::string spaceLabel;
1409 if (spaceNumber == 0)
1410 spaceLabel = "nodal";
1411 else if (spaceNumber == 1)
1412 spaceLabel = "edge";
1413 else if (spaceNumber == 2)
1414 spaceLabel = "face";
1415 else {
1416 TEUCHOS_ASSERT(false);
1417 TEUCHOS_UNREACHABLE_RETURN(Teuchos::null);
1418 }
1419
1420 RCP<Teuchos::TimeMonitor> tm;
1421 if (spaceNumber > 0) {
1422 tm = getTimer("nullspace " + spaceLabel);
1423 GetOStream(Runtime0) << solverName_ + "::compute(): building " + spaceLabel + " nullspace" << std::endl;
1424 }
1425
1426 if (spaceNumber == 0) {
1427 return Teuchos::null;
1428
1429 } else if (spaceNumber == 1) {
1430 RCP<MultiVector> CoordsSC;
1432 RCP<MultiVector> Nullspace = MultiVectorFactory::Build(D0_->getRowMap(), NodalCoords_->getNumVectors());
1433 D0_->apply(*CoordsSC, *Nullspace);
1434
1435 bool normalize = parameterList_.get<bool>("refmaxwell: normalize nullspace", MasterList::getDefault<bool>("refmaxwell: normalize nullspace"));
1436
1437 coordinateType minLen, maxLen, meanLen;
1438 if (IsPrint(Statistics2) || normalize) {
1439 // compute edge lengths
1440 ArrayRCP<ArrayRCP<const Scalar>> localNullspace(dim_);
1441 for (size_t i = 0; i < dim_; i++)
1442 localNullspace[i] = Nullspace->getData(i);
1443 coordinateType localMinLen = Teuchos::ScalarTraits<coordinateType>::rmax();
1444 coordinateType localMeanLen = Teuchos::ScalarTraits<coordinateType>::zero();
1445 coordinateType localMaxLen = Teuchos::ScalarTraits<coordinateType>::zero();
1446 for (size_t j = 0; j < Nullspace->getMap()->getLocalNumElements(); j++) {
1447 Scalar lenSC = Teuchos::ScalarTraits<Scalar>::zero();
1448 for (size_t i = 0; i < dim_; i++)
1449 lenSC += localNullspace[i][j] * localNullspace[i][j];
1450 coordinateType len = Teuchos::as<coordinateType>(Teuchos::ScalarTraits<Scalar>::real(Teuchos::ScalarTraits<Scalar>::squareroot(lenSC)));
1451 localMinLen = std::min(localMinLen, len);
1452 localMaxLen = std::max(localMaxLen, len);
1453 localMeanLen += len;
1454 }
1455
1456 RCP<const Teuchos::Comm<int>> comm = Nullspace->getMap()->getComm();
1457 MueLu_minAll(comm, localMinLen, minLen);
1458 MueLu_sumAll(comm, localMeanLen, meanLen);
1459 MueLu_maxAll(comm, localMaxLen, maxLen);
1460 meanLen /= Nullspace->getMap()->getGlobalNumElements();
1461 }
1462
1463 if (IsPrint(Statistics2)) {
1464 GetOStream(Statistics2) << "Edge length (min/mean/max): " << minLen << " / " << meanLen << " / " << maxLen << std::endl;
1465 }
1466
1467 if (normalize) {
1468 // normalize the nullspace
1469 GetOStream(Runtime0) << solverName_ + "::compute(): normalizing nullspace" << std::endl;
1470
1471 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1472
1473 Array<Scalar> normsSC(NodalCoords_->getNumVectors(), one / Teuchos::as<Scalar>(meanLen));
1474 Nullspace->scale(normsSC());
1475 }
1476
1477 if (applyBCs) {
1478 // Nuke the BC edges in nullspace
1479 Utilities::ZeroDirichletRows(Nullspace, bcs);
1480 }
1481 dump(Nullspace, "nullspaceEdge.m");
1482
1483 return Nullspace;
1484
1485 } else if (spaceNumber == 2) {
1486 using ATS = Kokkos::ArithTraits<Scalar>;
1487 using impl_Scalar = typename ATS::val_type;
1488 using impl_ATS = Kokkos::ArithTraits<impl_Scalar>;
1489 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
1490
1491 RCP<Matrix> facesToNodes;
1492 {
1493 RCP<Matrix> edgesToNodes = Xpetra::MatrixFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::BuildCopy(D0_);
1495
1496 // dump(edgesToNodes, "edgesToNodes.m");
1497
1498 RCP<Matrix> facesToEdges = Xpetra::MatrixFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::BuildCopy(Dk_1_);
1500 facesToEdges = Maxwell_Utils<SC, LO, GO, NO>::removeExplicitZeros(facesToEdges, 1e-3, false);
1501
1502 // dump(facesToEdges, "facesToEdges.m");
1503
1504 facesToNodes = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*facesToEdges, false, *edgesToNodes, false, facesToNodes, GetOStream(Runtime0), true, true);
1506 facesToNodes = Maxwell_Utils<SC, LO, GO, NO>::removeExplicitZeros(facesToNodes, 1e-3, false);
1507 }
1508
1509 // dump(facesToNodes, "facesToNodes.m");
1510
1511 RCP<RealValuedMultiVector> ghostedNodalCoordinates;
1512 auto importer = facesToNodes->getCrsGraph()->getImporter();
1513 if (!importer.is_null()) {
1514 ghostedNodalCoordinates = Xpetra::MultiVectorFactory<coordinateType, LocalOrdinal, GlobalOrdinal, Node>::Build(importer->getTargetMap(), dim_);
1515 ghostedNodalCoordinates->doImport(*NodalCoords_, *importer, Xpetra::INSERT);
1516 } else
1517 ghostedNodalCoordinates = NodalCoords_;
1518
1519 RCP<MultiVector> Nullspace = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(facesToNodes->getRangeMap(), dim_);
1520 {
1521 auto facesToNodesLocal = facesToNodes->getLocalMatrixDevice();
1522 auto localNodalCoordinates = ghostedNodalCoordinates->getDeviceLocalView(Xpetra::Access::ReadOnly);
1523 auto localFaceNullspace = Nullspace->getDeviceLocalView(Xpetra::Access::ReadWrite);
1524
1525 // enter values
1526 Kokkos::parallel_for(
1527 solverName_ + "::buildFaceProjection_nullspace",
1528 range_type(0, Nullspace->getMap()->getLocalNumElements()),
1529 KOKKOS_LAMBDA(const size_t f) {
1530 size_t n0 = facesToNodesLocal.graph.entries(facesToNodesLocal.graph.row_map(f));
1531 size_t n1 = facesToNodesLocal.graph.entries(facesToNodesLocal.graph.row_map(f) + 1);
1532 size_t n2 = facesToNodesLocal.graph.entries(facesToNodesLocal.graph.row_map(f) + 2);
1533 impl_Scalar elementNullspace00 = localNodalCoordinates(n1, 0) - localNodalCoordinates(n0, 0);
1534 impl_Scalar elementNullspace10 = localNodalCoordinates(n2, 0) - localNodalCoordinates(n0, 0);
1535 impl_Scalar elementNullspace01 = localNodalCoordinates(n1, 1) - localNodalCoordinates(n0, 1);
1536 impl_Scalar elementNullspace11 = localNodalCoordinates(n2, 1) - localNodalCoordinates(n0, 1);
1537 impl_Scalar elementNullspace02 = localNodalCoordinates(n1, 2) - localNodalCoordinates(n0, 2);
1538 impl_Scalar elementNullspace12 = localNodalCoordinates(n2, 2) - localNodalCoordinates(n0, 2);
1539
1540 localFaceNullspace(f, 0) = impl_ATS::magnitude(elementNullspace01 * elementNullspace12 - elementNullspace02 * elementNullspace11) / 6.0;
1541 localFaceNullspace(f, 1) = impl_ATS::magnitude(elementNullspace02 * elementNullspace10 - elementNullspace00 * elementNullspace12) / 6.0;
1542 localFaceNullspace(f, 2) = impl_ATS::magnitude(elementNullspace00 * elementNullspace11 - elementNullspace01 * elementNullspace10) / 6.0;
1543 });
1544 }
1545
1546 if (applyBCs) {
1547 // Nuke the BC faces in nullspace
1548 Utilities::ZeroDirichletRows(Nullspace, bcs);
1549 }
1550
1551 dump(Nullspace, "nullspaceFace.m");
1552
1553 return Nullspace;
1554
1555 } else {
1556 TEUCHOS_ASSERT(false);
1557 TEUCHOS_UNREACHABLE_RETURN(Teuchos::null);
1558 }
1559}
1560
1561template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1562Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
1563RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::buildProjection(const int spaceNumber, const RCP<MultiVector> &Nullspace) const {
1564 using ATS = Kokkos::ArithTraits<Scalar>;
1565 using impl_Scalar = typename ATS::val_type;
1566 using impl_ATS = Kokkos::ArithTraits<impl_Scalar>;
1567 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
1568
1569 typedef typename Matrix::local_matrix_type KCRS;
1570 typedef typename KCRS::StaticCrsGraphType graph_t;
1571 typedef typename graph_t::row_map_type::non_const_type lno_view_t;
1572 typedef typename graph_t::entries_type::non_const_type lno_nnz_view_t;
1573 typedef typename KCRS::values_type::non_const_type scalar_view_t;
1574
1575 const impl_Scalar impl_SC_ONE = impl_ATS::one();
1576 const impl_Scalar impl_SC_ZERO = impl_ATS::zero();
1577 const impl_Scalar impl_half = impl_SC_ONE / (impl_SC_ONE + impl_SC_ONE);
1578
1579 std::string spaceLabel;
1580 if (spaceNumber == 0)
1581 spaceLabel = "nodal";
1582 else if (spaceNumber == 1)
1583 spaceLabel = "edge";
1584 else if (spaceNumber == 2)
1585 spaceLabel = "face";
1586 else
1587 TEUCHOS_ASSERT(false);
1588
1589 RCP<Teuchos::TimeMonitor> tm;
1590 if (spaceNumber > 0) {
1591 tm = getTimer("projection " + spaceLabel);
1592 GetOStream(Runtime0) << solverName_ + "::compute(): building " + spaceLabel + " projection" << std::endl;
1593 }
1594
1595 RCP<Matrix> incidence;
1596 if (spaceNumber == 0) {
1597 // identity projection
1598 return Teuchos::null;
1599
1600 } else if (spaceNumber == 1) {
1601 // D0 is incidence from nodes to edges
1602 incidence = D0_;
1603
1604 } else if (spaceNumber == 2) {
1605 // get incidence from nodes to faces by multiplying D0 and D1
1606
1607 TEUCHOS_ASSERT(spaceNumber_ == 2);
1608
1609 RCP<Matrix> facesToNodes;
1610 {
1611 RCP<Matrix> edgesToNodes = Xpetra::MatrixFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::BuildCopy(D0_);
1613
1614 dump(edgesToNodes, "edgesToNodes.m");
1615
1616 RCP<Matrix> facesToEdges = Xpetra::MatrixFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::BuildCopy(Dk_1_);
1618 // facesToEdges = Maxwell_Utils<SC,LO,GO,NO>::removeExplicitZeros(facesToEdges, 1e-2, false);
1619
1620 dump(facesToEdges, "facesToEdges.m");
1621
1622 facesToNodes = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*facesToEdges, false, *edgesToNodes, false, facesToNodes, GetOStream(Runtime0), true, true);
1624 facesToNodes = Maxwell_Utils<SC, LO, GO, NO>::removeExplicitZeros(facesToNodes, 1e-2, false);
1625 }
1626
1627 dump(facesToNodes, "facesToNodes.m");
1628
1629 incidence = facesToNodes;
1630
1631 } else
1632 TEUCHOS_ASSERT(false);
1633
1634 size_t dim = dim_;
1635
1636 // Create maps
1637 RCP<const Map> rowMap = incidence->getRowMap();
1638 RCP<const Map> blockColMap = MapFactory::Build(incidence->getColMap(), dim);
1639 RCP<const Map> blockDomainMap = MapFactory::Build(incidence->getDomainMap(), dim);
1640
1641 auto localIncidence = incidence->getLocalMatrixDevice();
1642 size_t numLocalRows = rowMap->getLocalNumElements();
1643 size_t numLocalColumns = dim * incidence->getColMap()->getLocalNumElements();
1644 size_t nnzEstimate = dim * localIncidence.graph.entries.size();
1645 lno_view_t rowptr(Kokkos::ViewAllocateWithoutInitializing("projection_rowptr_" + spaceLabel), numLocalRows + 1);
1646 lno_nnz_view_t colind(Kokkos::ViewAllocateWithoutInitializing("projection_colind_" + spaceLabel), nnzEstimate);
1647 scalar_view_t vals("projection_vals_" + spaceLabel, nnzEstimate);
1648
1649 // set rowpointer
1650 Kokkos::parallel_for(
1651 solverName_ + "::buildProjection_adjustRowptr_" + spaceLabel,
1652 range_type(0, numLocalRows + 1),
1653 KOKKOS_LAMBDA(const size_t i) {
1654 rowptr(i) = dim * localIncidence.graph.row_map(i);
1655 });
1656
1657 auto localNullspace = Nullspace->getDeviceLocalView(Xpetra::Access::ReadOnly);
1658
1659 // set column indices and values
1660 magnitudeType tol = 1e-5;
1661 Kokkos::parallel_for(
1662 solverName_ + "::buildProjection_enterValues_" + spaceLabel,
1663 range_type(0, numLocalRows),
1664 KOKKOS_LAMBDA(const size_t f) {
1665 for (size_t jj = localIncidence.graph.row_map(f); jj < localIncidence.graph.row_map(f + 1); jj++) {
1666 for (size_t k = 0; k < dim; k++) {
1667 colind(dim * jj + k) = dim * localIncidence.graph.entries(jj) + k;
1668 if (impl_ATS::magnitude(localIncidence.values(jj)) > tol)
1669 vals(dim * jj + k) = impl_half * localNullspace(f, k);
1670 else
1671 vals(dim * jj + k) = impl_SC_ZERO;
1672 }
1673 }
1674 });
1675
1676 // Create matrix
1677 typename CrsMatrix::local_matrix_type lclProjection("local projection " + spaceLabel,
1678 numLocalRows, numLocalColumns, nnzEstimate,
1679 vals, rowptr, colind);
1680 RCP<Matrix> projection = MatrixFactory::Build(lclProjection,
1681 rowMap, blockColMap,
1682 blockDomainMap, rowMap);
1683
1684 return projection;
1685}
1686
1687template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1689 Teuchos::RCP<Matrix> &P_nodal,
1690 Teuchos::RCP<MultiVector> &Nullspace_nodal,
1691 Teuchos::RCP<RealValuedMultiVector> &CoarseCoords_nodal) const {
1692 RCP<Teuchos::TimeMonitor> tm = getTimer("nodal prolongator");
1693 GetOStream(Runtime0) << solverName_ + "::compute(): building nodal prolongator" << std::endl;
1694
1695 // build prolongator: algorithm 1 in the reference paper
1696 // First, build nodal unsmoothed prolongator using the matrix A_nodal
1697
1698 const SC SC_ONE = Teuchos::ScalarTraits<SC>::one();
1699
1700 {
1701 Level fineLevel, coarseLevel;
1702 fineLevel.SetFactoryManager(null);
1703 coarseLevel.SetFactoryManager(null);
1704 coarseLevel.SetPreviousLevel(rcpFromRef(fineLevel));
1705 fineLevel.SetLevelID(0);
1706 coarseLevel.SetLevelID(1);
1707 fineLevel.Set("A", A_nodal);
1708 fineLevel.Set("Coordinates", NodalCoords_);
1709 fineLevel.Set("DofsPerNode", 1);
1710 coarseLevel.setlib(A_nodal->getDomainMap()->lib());
1711 fineLevel.setlib(A_nodal->getDomainMap()->lib());
1712 coarseLevel.setObjectLabel(A_nodal->getObjectLabel());
1713 fineLevel.setObjectLabel(A_nodal->getObjectLabel());
1714
1715 LocalOrdinal NSdim = 1;
1716 RCP<MultiVector> nullSpace = MultiVectorFactory::Build(A_nodal->getRowMap(), NSdim);
1717 nullSpace->putScalar(SC_ONE);
1718 fineLevel.Set("Nullspace", nullSpace);
1719
1720 std::string algo = parameterList_.get<std::string>("multigrid algorithm");
1721
1722 RCP<Factory> amalgFact, dropFact, UncoupledAggFact, coarseMapFact, TentativePFact, Tfact, SaPFact;
1723 amalgFact = rcp(new AmalgamationFactory());
1724 coarseMapFact = rcp(new CoarseMapFactory());
1725 Tfact = rcp(new CoordinatesTransferFactory());
1726 UncoupledAggFact = rcp(new UncoupledAggregationFactory());
1727 if (useKokkos_) {
1728 dropFact = rcp(new CoalesceDropFactory_kokkos());
1729 TentativePFact = rcp(new TentativePFactory_kokkos());
1730 } else {
1731 dropFact = rcp(new CoalesceDropFactory());
1732 TentativePFact = rcp(new TentativePFactory());
1733 }
1734 if (algo == "sa")
1735 SaPFact = rcp(new SaPFactory());
1736 dropFact->SetFactory("UnAmalgamationInfo", amalgFact);
1737
1738 double dropTol = parameterList_.get<double>("aggregation: drop tol");
1739 std::string dropScheme = parameterList_.get<std::string>("aggregation: drop scheme");
1740 std::string distLaplAlgo = parameterList_.get<std::string>("aggregation: distance laplacian algo");
1741 dropFact->SetParameter("aggregation: drop tol", Teuchos::ParameterEntry(dropTol));
1742 dropFact->SetParameter("aggregation: drop scheme", Teuchos::ParameterEntry(dropScheme));
1743 dropFact->SetParameter("aggregation: distance laplacian algo", Teuchos::ParameterEntry(distLaplAlgo));
1744
1745 UncoupledAggFact->SetFactory("Graph", dropFact);
1746 int minAggSize = parameterList_.get<int>("aggregation: min agg size");
1747 UncoupledAggFact->SetParameter("aggregation: min agg size", Teuchos::ParameterEntry(minAggSize));
1748 int maxAggSize = parameterList_.get<int>("aggregation: max agg size");
1749 UncoupledAggFact->SetParameter("aggregation: max agg size", Teuchos::ParameterEntry(maxAggSize));
1750 bool matchMLbehavior1 = parameterList_.get<bool>("aggregation: match ML phase1");
1751 UncoupledAggFact->SetParameter("aggregation: match ML phase1", Teuchos::ParameterEntry(matchMLbehavior1));
1752 bool matchMLbehavior2a = parameterList_.get<bool>("aggregation: match ML phase2a");
1753 UncoupledAggFact->SetParameter("aggregation: match ML phase2a", Teuchos::ParameterEntry(matchMLbehavior2a));
1754 bool matchMLbehavior2b = parameterList_.get<bool>("aggregation: match ML phase2b");
1755 UncoupledAggFact->SetParameter("aggregation: match ML phase2b", Teuchos::ParameterEntry(matchMLbehavior2b));
1756
1757 coarseMapFact->SetFactory("Aggregates", UncoupledAggFact);
1758
1759 TentativePFact->SetFactory("Aggregates", UncoupledAggFact);
1760 TentativePFact->SetFactory("UnAmalgamationInfo", amalgFact);
1761 TentativePFact->SetFactory("CoarseMap", coarseMapFact);
1762
1763 Tfact->SetFactory("Aggregates", UncoupledAggFact);
1764 Tfact->SetFactory("CoarseMap", coarseMapFact);
1765
1766 if (algo == "sa") {
1767 SaPFact->SetFactory("P", TentativePFact);
1768 coarseLevel.Request("P", SaPFact.get());
1769 } else
1770 coarseLevel.Request("P", TentativePFact.get());
1771 coarseLevel.Request("Nullspace", TentativePFact.get());
1772 coarseLevel.Request("Coordinates", Tfact.get());
1773
1774 RCP<AggregationExportFactory> aggExport;
1775 bool exportVizData = parameterList_.get<bool>("aggregation: export visualization data");
1776 if (exportVizData) {
1777 aggExport = rcp(new AggregationExportFactory());
1778 ParameterList aggExportParams;
1779 aggExportParams.set("aggregation: output filename", "aggs.vtk");
1780 aggExportParams.set("aggregation: output file: agg style", "Jacks");
1781 aggExport->SetParameterList(aggExportParams);
1782
1783 aggExport->SetFactory("Aggregates", UncoupledAggFact);
1784 aggExport->SetFactory("UnAmalgamationInfo", amalgFact);
1785 fineLevel.Request("Aggregates", UncoupledAggFact.get());
1786 fineLevel.Request("UnAmalgamationInfo", amalgFact.get());
1787 }
1788
1789 if (algo == "sa")
1790 coarseLevel.Get("P", P_nodal, SaPFact.get());
1791 else
1792 coarseLevel.Get("P", P_nodal, TentativePFact.get());
1793 coarseLevel.Get("Nullspace", Nullspace_nodal, TentativePFact.get());
1794 coarseLevel.Get("Coordinates", CoarseCoords_nodal, Tfact.get());
1795
1796 if (exportVizData)
1797 aggExport->Build(fineLevel, coarseLevel);
1798 }
1799}
1800
1801template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1802Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
1804 RCP<Teuchos::TimeMonitor> tm = getTimer("vectorial nodal prolongator");
1805 GetOStream(Runtime0) << solverName_ + "::compute(): building vectorial nodal prolongator" << std::endl;
1806
1807 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
1808
1809 typedef typename Matrix::local_matrix_type KCRS;
1810 typedef typename KCRS::StaticCrsGraphType graph_t;
1811 typedef typename graph_t::row_map_type::non_const_type lno_view_t;
1812 typedef typename graph_t::entries_type::non_const_type lno_nnz_view_t;
1813 typedef typename KCRS::values_type::non_const_type scalar_view_t;
1814
1815 size_t dim = dim_;
1816
1817 // Create the matrix object
1818 RCP<Map> blockRowMap = MapFactory::Build(P_nodal->getRowMap(), dim);
1819 RCP<Map> blockColMap = MapFactory::Build(P_nodal->getColMap(), dim);
1820 RCP<Map> blockDomainMap = MapFactory::Build(P_nodal->getDomainMap(), dim);
1821
1822 // Get data out of P_nodal.
1823 auto localP_nodal = P_nodal->getLocalMatrixDevice();
1824
1825 size_t numLocalRows = blockRowMap->getLocalNumElements();
1826 size_t numLocalColumns = blockColMap->getLocalNumElements();
1827 size_t nnzEstimate = dim * localP_nodal.graph.entries.size();
1828 lno_view_t rowptr(Kokkos::ViewAllocateWithoutInitializing("vectorPNodal_rowptr"), numLocalRows + 1);
1829 lno_nnz_view_t colind(Kokkos::ViewAllocateWithoutInitializing("vectorPNodal_colind"), nnzEstimate);
1830 scalar_view_t vals(Kokkos::ViewAllocateWithoutInitializing("vectorPNodal_vals"), nnzEstimate);
1831
1832 // fill rowpointer
1833 Kokkos::parallel_for(
1834 solverName_ + "::buildVectorNodalProlongator_adjustRowptr",
1835 range_type(0, localP_nodal.numRows() + 1),
1836 KOKKOS_LAMBDA(const LocalOrdinal i) {
1837 if (i < localP_nodal.numRows()) {
1838 for (size_t k = 0; k < dim; k++) {
1839 rowptr(dim * i + k) = dim * localP_nodal.graph.row_map(i) + k;
1840 }
1841 } else
1842 rowptr(dim * localP_nodal.numRows()) = dim * localP_nodal.graph.row_map(i);
1843 });
1844
1845 // fill column indices and values
1846 Kokkos::parallel_for(
1847 solverName_ + "::buildVectorNodalProlongator_adjustColind",
1848 range_type(0, localP_nodal.graph.entries.size()),
1849 KOKKOS_LAMBDA(const size_t jj) {
1850 for (size_t k = 0; k < dim; k++) {
1851 colind(dim * jj + k) = dim * localP_nodal.graph.entries(jj) + k;
1852 // vals(dim*jj+k) = localP_nodal.values(jj);
1853 vals(dim * jj + k) = 1.;
1854 }
1855 });
1856
1857 typename CrsMatrix::local_matrix_type lclVectorNodalP("local vector nodal prolongator",
1858 numLocalRows, numLocalColumns, nnzEstimate,
1859 vals, rowptr, colind);
1860 RCP<Matrix> vectorNodalP = MatrixFactory::Build(lclVectorNodalP,
1861 blockRowMap, blockColMap,
1862 blockDomainMap, blockRowMap);
1863
1864 return vectorNodalP;
1865}
1866
1867template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1869 buildProlongator(const int spaceNumber,
1870 const Teuchos::RCP<Matrix> &A_nodal,
1871 const Teuchos::RCP<MultiVector> &Nullspace,
1872 Teuchos::RCP<Matrix> &Prolongator,
1873 Teuchos::RCP<MultiVector> &coarseNullspace,
1874 Teuchos::RCP<RealValuedMultiVector> &coarseNodalCoords) const {
1875 using ATS = Kokkos::ArithTraits<Scalar>;
1876 using impl_Scalar = typename ATS::val_type;
1877 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1878
1879 std::string typeStr;
1880 switch (spaceNumber) {
1881 case 0:
1882 typeStr = "node";
1883 TEUCHOS_ASSERT(A_nodal.is_null());
1884 break;
1885 case 1:
1886 typeStr = "edge";
1887 break;
1888 case 2:
1889 typeStr = "face";
1890 break;
1891 default:
1892 TEUCHOS_ASSERT(false);
1893 }
1894
1895 const bool skipFirstLevel = !A_nodal.is_null();
1896
1897 RCP<Teuchos::TimeMonitor> tm;
1898 if (spaceNumber > 0) {
1899 tm = getTimer("special prolongator " + typeStr);
1900 GetOStream(Runtime0) << solverName_ + "::compute(): building special " + typeStr + " prolongator" << std::endl;
1901 }
1902
1903 RCP<Matrix> projection = buildProjection(spaceNumber, Nullspace);
1904 dump(projection, typeStr + "Projection.m");
1905
1906 if (skipFirstLevel) {
1907 RCP<Matrix> P_nodal;
1908 RCP<MultiVector> coarseNodalNullspace;
1909
1910 buildNodalProlongator(A_nodal, P_nodal, coarseNodalNullspace, coarseNodalCoords);
1911
1912 dump(P_nodal, "P_nodal_" + typeStr + ".m");
1913 dump(coarseNodalNullspace, "coarseNullspace_nodal_" + typeStr + ".m");
1914
1915 RCP<Matrix> vectorP_nodal = buildVectorNodalProlongator(P_nodal);
1916
1917 dump(vectorP_nodal, "vectorP_nodal_" + typeStr + ".m");
1918
1919 Prolongator = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*projection, false, *vectorP_nodal, false, Prolongator, GetOStream(Runtime0), true, true);
1920
1921 // This is how ML computes P22 for Darcy.
1922 // The difference is the scaling by nonzeros. I don't think that that is actually needed.
1923 //
1924 // if (spaceNumber==2) {
1925
1926 // RCP<Matrix> facesToNodes, aggsToFaces;
1927 // {
1928 // RCP<Matrix> edgesToNodes = Xpetra::MatrixFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::BuildCopy(D0_);
1929 // Maxwell_Utils<SC,LO,GO,NO>::thresholdedAbs(edgesToNodes, 1e-10);
1930
1931 // dump(edgesToNodes, "edgesToNodes.m");
1932
1933 // RCP<Matrix> facesToEdges = Xpetra::MatrixFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::BuildCopy(Dk_1_);
1934 // Maxwell_Utils<SC,LO,GO,NO>::thresholdedAbs(facesToEdges, 1e-10);
1935 // // facesToEdges = Maxwell_Utils<SC,LO,GO,NO>::removeExplicitZeros(facesToEdges, 1e-2, false);
1936
1937 // dump(facesToEdges, "facesToEdges.m");
1938
1939 // facesToNodes = Xpetra::MatrixMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Multiply(*facesToEdges,false,*edgesToNodes,false,facesToNodes,GetOStream(Runtime0),true,true);
1940 // Maxwell_Utils<SC,LO,GO,NO>::thresholdedAbs(facesToNodes, 1e-10);
1941 // facesToNodes = Maxwell_Utils<SC,LO,GO,NO>::removeExplicitZeros(facesToNodes, 1e-2, false);
1942 // }
1943 // aggsToFaces = Xpetra::MatrixMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Multiply(*facesToNodes,false,*P_nodal,false,aggsToFaces,GetOStream(Runtime0),true,true);
1944
1945 // auto localP = Prolongator->getLocalMatrixDevice();
1946 // auto localAggsToFaces = aggsToFaces->getLocalMatrixDevice();
1947 // auto localNullspace = Nullspace->getDeviceLocalView(Xpetra::Access::ReadOnly);
1948
1949 // size_t dim = dim_;
1950 // Kokkos::parallel_for(solverName_+"::buildVectorNodalProlongator_adjustRowptr",
1951 // range_type(0,localP.numRows()),
1952 // KOKKOS_LAMBDA(const LocalOrdinal i) {
1953 // LocalOrdinal nonzeros = localAggsToFaces.graph.row_map(i+1)-localAggsToFaces.graph.row_map(i);
1954 // for (LocalOrdinal jj = localAggsToFaces.graph.row_map(i); jj < localAggsToFaces.graph.row_map(i+1); jj++ ) {
1955 // LocalOrdinal j = localAggsToFaces.graph.entries(jj);
1956 // for (LocalOrdinal k = 0; k<dim; k++)
1957 // for (LocalOrdinal kk = localP.graph.row_map(i); kk < localP.graph.row_map(i+1); kk++)
1958 // if (localP.graph.entries(kk) == (dim * j+k)) {
1959 // localP.values(kk) = localNullspace(i, k) / nonzeros;
1960 // break;
1961 // }
1962 // }
1963 // });
1964 // }
1965 //
1966
1967 size_t dim = dim_;
1968 coarseNullspace = MultiVectorFactory::Build(vectorP_nodal->getDomainMap(), dim);
1969
1970 auto localNullspace_nodal = coarseNodalNullspace->getDeviceLocalView(Xpetra::Access::ReadOnly);
1971 auto localNullspace_coarse = coarseNullspace->getDeviceLocalView(Xpetra::Access::ReadWrite);
1972 Kokkos::parallel_for(
1973 solverName_ + "::buildProlongator_nullspace_" + typeStr,
1974 range_type(0, coarseNodalNullspace->getLocalLength()),
1975 KOKKOS_LAMBDA(const size_t i) {
1976 impl_Scalar val = localNullspace_nodal(i, 0);
1977 for (size_t j = 0; j < dim; j++)
1978 localNullspace_coarse(dim * i + j, j) = val;
1979 });
1980
1981 } else {
1982 Prolongator = projection;
1983 coarseNodalCoords = NodalCoords_;
1984
1985 if (spaceNumber == 0) {
1986 // nothing, just use the default constant vector
1987 } else if (spaceNumber >= 1) {
1988 size_t dim = dim_;
1989 coarseNullspace = MultiVectorFactory::Build(projection->getDomainMap(), dim);
1990 auto localNullspace_coarse = coarseNullspace->getDeviceLocalView(Xpetra::Access::ReadWrite);
1991 Kokkos::parallel_for(
1992 solverName_ + "::buildProlongator_nullspace_" + typeStr,
1993 range_type(0, coarseNullspace->getLocalLength() / dim),
1994 KOKKOS_LAMBDA(const size_t i) {
1995 for (size_t j = 0; j < dim; j++)
1996 localNullspace_coarse(dim * i + j, j) = 1.0;
1997 });
1998 }
1999 }
2000}
2001
2002template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2004 Teuchos::RCP<Operator> &thyraPrecOp,
2005 const Teuchos::RCP<Matrix> &A,
2006 const Teuchos::RCP<MultiVector> &Nullspace,
2007 const Teuchos::RCP<RealValuedMultiVector> &Coords,
2008 const Teuchos::RCP<MultiVector> &Material,
2009 Teuchos::ParameterList &params,
2010 std::string &label,
2011 const bool reuse,
2012 const bool isSingular) {
2013 int oldRank = SetProcRankVerbose(A->getDomainMap()->getComm()->getRank());
2014 if (IsPrint(Statistics2)) {
2015 RCP<ParameterList> pl = rcp(new ParameterList());
2016 pl->set("printLoadBalancingInfo", true);
2017 pl->set("printCommInfo", true);
2019 }
2020#if defined(HAVE_MUELU_STRATIMIKOS) && defined(HAVE_MUELU_THYRA)
2021 if (params.isType<std::string>("Preconditioner Type")) {
2022 TEUCHOS_ASSERT(!reuse);
2023 // build a Stratimikos preconditioner
2024 if (params.get<std::string>("Preconditioner Type") == "MueLu") {
2025 ParameterList &userParamList = params.sublist("Preconditioner Types").sublist("MueLu").sublist("user data");
2026 if (!Nullspace.is_null())
2027 userParamList.set<RCP<MultiVector>>("Nullspace", Nullspace);
2028 if (!Material.is_null())
2029 userParamList.set<RCP<MultiVector>>("Material", Material);
2030 userParamList.set<RCP<RealValuedMultiVector>>("Coordinates", Coords);
2031 }
2032 thyraPrecOp = rcp(new XpetraThyraLinearOp<Scalar, LocalOrdinal, GlobalOrdinal, Node>(coarseA11_, rcp(&params, false)));
2033 } else
2034#endif
2035 {
2036 // build a MueLu hierarchy
2037
2038 if (!reuse) {
2039 ParameterList &userParamList = params.sublist("user data");
2040 if (!Coords.is_null())
2041 userParamList.set<RCP<RealValuedMultiVector>>("Coordinates", Coords);
2042 if (!Nullspace.is_null())
2043 userParamList.set<RCP<MultiVector>>("Nullspace", Nullspace);
2044 if (!Material.is_null())
2045 userParamList.set<RCP<MultiVector>>("Material", Material);
2046
2047 if (isSingular) {
2048 std::string coarseType = "";
2049 if (params.isParameter("coarse: type")) {
2050 coarseType = params.get<std::string>("coarse: type");
2051 // Transform string to "Abcde" notation
2052 std::transform(coarseType.begin(), coarseType.end(), coarseType.begin(), ::tolower);
2053 std::transform(coarseType.begin(), ++coarseType.begin(), coarseType.begin(), ::toupper);
2054 }
2055 if ((coarseType == "" ||
2056 coarseType == "Klu" ||
2057 coarseType == "Klu2" ||
2058 coarseType == "Superlu" ||
2059 coarseType == "Superlu_dist" ||
2060 coarseType == "Superludist" ||
2061 coarseType == "Basker" ||
2062 coarseType == "Cusolver" ||
2063 coarseType == "Tacho") &&
2064 (!params.isSublist("coarse: params") ||
2065 !params.sublist("coarse: params").isParameter("fix nullspace")))
2066 params.sublist("coarse: params").set("fix nullspace", true);
2067 }
2068
2069 hierarchy = MueLu::CreateXpetraPreconditioner(A, params);
2070 } else {
2071 RCP<MueLu::Level> level0 = hierarchy->GetLevel(0);
2072 level0->Set("A", A);
2073 hierarchy->SetupRe();
2074 }
2075 }
2076 SetProcRankVerbose(oldRank);
2077}
2078
2079template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2080void RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::resetMatrix(RCP<Matrix> SM_Matrix_new, bool ComputePrec) {
2081 bool reuse = !SM_Matrix_.is_null();
2082 SM_Matrix_ = SM_Matrix_new;
2083 dump(SM_Matrix_, "SM.m");
2084 if (ComputePrec)
2085 compute(reuse);
2086}
2087
2088template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2090 // residual(SM_Matrix_, X, RHS, residual_)
2091 //
2092 // P11res_ = P11_^T*residual_ or P11res_ = R11_*residual_
2093 //
2094 // Dres_ = Dk_1_^T*residual or Dres_ = Dk_1_T_*residual
2095 //
2096 // if ImporterCoarse11_ is not null
2097 // ImporterCoarse11: P11res_ -> P11resTmp_
2098 // if Importer22_ is not null
2099 // Importer22: Dres_ -> DresTmp_
2100 //
2101 // if coarseA11 is not null
2102 //
2103 // Hierarchy11(P11resSubComm, P11xSubComm) P11resSubComm aliases P11res or P11resTmp
2104 // P11xSubComm aliases P11x
2105 //
2106 // if A22 is not null
2107 //
2108 // Hierarchy22(DresSubComm, DxSubComm) DresSubComm aliases Dres or DresTmp
2109 // DxSubComm aliases Dx
2110 //
2111 // if ImporterCoarse11_ is not null
2112 // ImporterCoarse11: P11xTmp_ -> P11x
2113 // if Importer22_ is not null
2114 // Importer22: DxTmp_ -> Dx_
2115 //
2116 // if fuse
2117 // X += P11*P11x
2118 // X += P11*Dx
2119 // else
2120 // residual = P11*P11x
2121 // residual += Dk_1*Dx
2122 // X += residual
2123
2124 Scalar one = Teuchos::ScalarTraits<Scalar>::one();
2125
2126 { // compute residual
2127
2128 RCP<Teuchos::TimeMonitor> tmRes = getTimer("residual calculation");
2130 }
2131
2132 { // restrict residual to sub-hierarchies
2133
2134 if (implicitTranspose_) {
2135 {
2136 RCP<Teuchos::TimeMonitor> tmRes = getTimer("restriction coarse (1,1) (implicit)");
2137 P11_->apply(*residual_, *P11res_, Teuchos::TRANS);
2138 }
2139 if (!onlyBoundary22_) {
2140 RCP<Teuchos::TimeMonitor> tmD = getTimer("restriction (2,2) (implicit)");
2141 Dk_1_->apply(*residual_, *Dres_, Teuchos::TRANS);
2142 }
2143 } else {
2145 // Column maps of D_T and R11 match, and we're running Tpetra
2146 {
2147 RCP<Teuchos::TimeMonitor> tmD = getTimer("restrictions import");
2148 DTR11Tmp_->doImport(*residual_, *toCrsMatrix(R11_)->getCrsGraph()->getImporter(), Xpetra::INSERT);
2149 }
2150 if (!onlyBoundary22_) {
2151 RCP<Teuchos::TimeMonitor> tmD = getTimer("restriction (2,2) (explicit)");
2152 toTpetra(Dk_1_T_)->localApply(toTpetra(*DTR11Tmp_), toTpetra(*Dres_), Teuchos::NO_TRANS);
2153 }
2154 {
2155 RCP<Teuchos::TimeMonitor> tmP11 = getTimer("restriction coarse (1,1) (explicit)");
2156 toTpetra(R11_)->localApply(toTpetra(*DTR11Tmp_), toTpetra(*P11res_), Teuchos::NO_TRANS);
2157 }
2158 } else {
2159 {
2160 RCP<Teuchos::TimeMonitor> tmP11 = getTimer("restriction coarse (1,1) (explicit)");
2161 R11_->apply(*residual_, *P11res_, Teuchos::NO_TRANS);
2162 }
2163 if (!onlyBoundary22_) {
2164 RCP<Teuchos::TimeMonitor> tmD = getTimer("restriction (2,2) (explicit)");
2165 Dk_1_T_->apply(*residual_, *Dres_, Teuchos::NO_TRANS);
2166 }
2167 }
2168 }
2169 }
2170
2171 {
2172 RCP<Teuchos::TimeMonitor> tmSubSolves = getTimer("subsolves");
2173
2174 // block diagonal preconditioner on 2x2 (V-cycle for diagonal blocks)
2175
2176 if (!ImporterCoarse11_.is_null() && !implicitTranspose_) {
2177 RCP<Teuchos::TimeMonitor> tmH = getTimer("import coarse (1,1)");
2178 P11resTmp_->beginImport(*P11res_, *ImporterCoarse11_, Xpetra::INSERT);
2179 }
2180 if (!onlyBoundary22_ && !Importer22_.is_null() && !implicitTranspose_) {
2181 RCP<Teuchos::TimeMonitor> tm22 = getTimer("import (2,2)");
2182 DresTmp_->beginImport(*Dres_, *Importer22_, Xpetra::INSERT);
2183 }
2184
2185 // iterate on coarse (1, 1) block
2186 if (!coarseA11_.is_null()) {
2187 if (!ImporterCoarse11_.is_null() && !implicitTranspose_)
2188 P11resTmp_->endImport(*P11res_, *ImporterCoarse11_, Xpetra::INSERT);
2189
2190 RCP<Teuchos::TimeMonitor> tmH = getTimer("solve coarse (1,1)", coarseA11_->getRowMap()->getComm());
2191
2192#if defined(HAVE_MUELU_STRATIMIKOS) && defined(HAVE_MUELU_THYRA)
2193 if (!thyraPrecOpH_.is_null()) {
2194 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
2195 thyraPrecOpH_->apply(*P11resSubComm_, *P11xSubComm_, Teuchos::NO_TRANS, one, zero);
2196 } else
2197#endif
2199 }
2200
2201 // iterate on (2, 2) block
2202 if (!A22_.is_null()) {
2203 if (!onlyBoundary22_ && !Importer22_.is_null() && !implicitTranspose_)
2204 DresTmp_->endImport(*Dres_, *Importer22_, Xpetra::INSERT);
2205
2206 RCP<Teuchos::TimeMonitor> tm22 = getTimer("solve (2,2)", A22_->getRowMap()->getComm());
2207#if defined(HAVE_MUELU_STRATIMIKOS) && defined(HAVE_MUELU_THYRA)
2208 if (!thyraPrecOp22_.is_null()) {
2209 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
2210 thyraPrecOp22_->apply(*DresSubComm_, *DxSubComm_, Teuchos::NO_TRANS, one, zero);
2211 } else
2212#endif
2213 Hierarchy22_->Iterate(*DresSubComm_, *DxSubComm_, numIters22_, true);
2214 }
2215
2216 if (coarseA11_.is_null() && !ImporterCoarse11_.is_null() && !implicitTranspose_)
2217 P11resTmp_->endImport(*P11res_, *ImporterCoarse11_, Xpetra::INSERT);
2218 if (A22_.is_null() && !onlyBoundary22_ && !Importer22_.is_null() && !implicitTranspose_)
2219 DresTmp_->endImport(*Dres_, *Importer22_, Xpetra::INSERT);
2220 }
2221
2222 {
2223 RCP<Teuchos::TimeMonitor> tmProlongations = getTimer("prolongations");
2224
2225 if (asyncTransfers_) {
2226 using Tpetra_Multivector = Tpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
2227 using Tpetra_Import = Tpetra::Import<LocalOrdinal, GlobalOrdinal, Node>;
2228
2229 auto tpP11 = toTpetra(P11_);
2230 auto tpDk_1 = toTpetra(Dk_1_);
2231
2232 RCP<Tpetra_Multivector> tpP11x = toTpetra(P11x_);
2233 RCP<Tpetra_Multivector> tpP11x_colmap;
2234 RCP<Tpetra_Multivector> tpX = toTpetra(Teuchos::rcpFromRef(X));
2235 RCP<Tpetra_Multivector> tpResidual = toTpetra(residual_);
2236 RCP<Tpetra_Multivector> tpDx = toTpetra(Dx_);
2237 RCP<Tpetra_Multivector> tpDx_colmap;
2238
2239 unsigned completedImports = 0;
2240 std::vector<bool> completedImport(2, false);
2241 auto tpP11importer = tpP11->getCrsGraph()->getImporter();
2242 if (!tpP11importer.is_null()) {
2243 tpP11x_colmap = toTpetra(P11x_colmap_);
2244 tpP11x_colmap->beginImport(*tpP11x, *tpP11importer, Tpetra::INSERT);
2245 }
2246
2247 RCP<const Tpetra_Import> tpDk_1importer;
2248 if (!onlyBoundary22_) {
2249 tpDk_1importer = tpDk_1->getCrsGraph()->getImporter();
2250 if (!tpDk_1importer.is_null()) {
2251 tpDx_colmap = toTpetra(Dx_colmap_);
2252 tpDx_colmap->beginImport(*tpDx, *tpDk_1importer, Tpetra::INSERT);
2253 }
2254 } else {
2255 completedImport[1] = true;
2256 completedImports++;
2257 }
2258
2260 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
2261 tpResidual->putScalar(zero);
2262 }
2263
2264 while (completedImports < completedImport.size()) {
2265 for (unsigned i = 0; i < completedImport.size(); i++) {
2266 if (completedImport[i]) continue;
2267
2268 if (i == 0) {
2269 if (!tpP11importer.is_null()) {
2270 if (tpP11x_colmap->transferArrived()) {
2271 tpP11x_colmap->endImport(*tpP11x, *tpP11importer, Tpetra::INSERT);
2272 completedImport[i] = true;
2273 completedImports++;
2274
2276 RCP<Teuchos::TimeMonitor> tmP11 = getTimer("prolongation coarse (1,1) (fused, local)");
2277 tpP11->localApply(*tpP11x_colmap, *tpX, Teuchos::NO_TRANS, one, one);
2278 } else {
2279 RCP<Teuchos::TimeMonitor> tmP11 = getTimer("prolongation coarse (1,1) (unfused, local)");
2280 tpP11->localApply(*tpP11x_colmap, *tpResidual, Teuchos::NO_TRANS, one, one);
2281 }
2282 }
2283 } else {
2284 completedImport[i] = true;
2285 completedImports++;
2286
2288 RCP<Teuchos::TimeMonitor> tmP11 = getTimer("prolongation coarse (1,1) (fused, local)");
2289 tpP11->localApply(*tpP11x, *tpX, Teuchos::NO_TRANS, one, one);
2290 } else {
2291 RCP<Teuchos::TimeMonitor> tmP11 = getTimer("prolongation coarse (1,1) (unfused, local)");
2292 tpP11->localApply(*tpP11x, *tpResidual, Teuchos::NO_TRANS, one, one);
2293 }
2294 }
2295 } else {
2296 if (!tpDk_1importer.is_null()) {
2297 if (tpDx_colmap->transferArrived()) {
2298 tpDx_colmap->endImport(*tpDx, *tpDk_1importer, Tpetra::INSERT);
2299 completedImport[i] = true;
2300 completedImports++;
2301
2303 RCP<Teuchos::TimeMonitor> tmD = getTimer("prolongation (2,2) (fused, local)");
2304 tpDk_1->localApply(*tpDx_colmap, *tpX, Teuchos::NO_TRANS, one, one);
2305 } else {
2306 RCP<Teuchos::TimeMonitor> tmD = getTimer("prolongation (2,2) (unfused, local)");
2307 tpDk_1->localApply(*tpDx_colmap, *tpResidual, Teuchos::NO_TRANS, one, one);
2308 }
2309 }
2310 } else {
2311 completedImport[i] = true;
2312 completedImports++;
2313
2315 RCP<Teuchos::TimeMonitor> tmD = getTimer("prolongation (2,2) (fused, local)");
2316 tpDk_1->localApply(*tpDx, *tpX, Teuchos::NO_TRANS, one, one);
2317 } else {
2318 RCP<Teuchos::TimeMonitor> tmD = getTimer("prolongation (2,2) (unfused, local)");
2319 tpDk_1->localApply(*tpDx, *tpResidual, Teuchos::NO_TRANS, one, one);
2320 }
2321 }
2322 }
2323 }
2324 }
2325
2326 if (!fuseProlongationAndUpdate_) { // update current solution
2327 RCP<Teuchos::TimeMonitor> tmUpdate = getTimer("update");
2328 X.update(one, *residual_, one);
2329 }
2330 } else {
2332 { // prolongate (1,1) block
2333 RCP<Teuchos::TimeMonitor> tmP11 = getTimer("prolongation coarse (1,1) (fused)");
2334 P11_->apply(*P11x_, X, Teuchos::NO_TRANS, one, one);
2335 }
2336
2337 if (!onlyBoundary22_) { // prolongate (2,2) block
2338 RCP<Teuchos::TimeMonitor> tmD = getTimer("prolongation (2,2) (fused)");
2339 Dk_1_->apply(*Dx_, X, Teuchos::NO_TRANS, one, one);
2340 }
2341 } else {
2342 { // prolongate (1,1) block
2343 RCP<Teuchos::TimeMonitor> tmP11 = getTimer("prolongation coarse (1,1) (unfused)");
2344 P11_->apply(*P11x_, *residual_, Teuchos::NO_TRANS);
2345 }
2346
2347 if (!onlyBoundary22_) { // prolongate (2,2) block
2348 RCP<Teuchos::TimeMonitor> tmD = getTimer("prolongation (2,2) (unfused)");
2349 Dk_1_->apply(*Dx_, *residual_, Teuchos::NO_TRANS, one, one);
2350 }
2351
2352 { // update current solution
2353 RCP<Teuchos::TimeMonitor> tmUpdate = getTimer("update");
2354 X.update(one, *residual_, one);
2355 }
2356 }
2357 }
2358 }
2359}
2360
2361template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2362void RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::solveH(const MultiVector &RHS, MultiVector &X) const {
2363 Scalar one = Teuchos::ScalarTraits<Scalar>::one();
2364
2365 { // compute residual
2366 RCP<Teuchos::TimeMonitor> tmRes = getTimer("residual calculation");
2369 P11_->apply(*residual_, *P11res_, Teuchos::TRANS);
2370 else
2371 R11_->apply(*residual_, *P11res_, Teuchos::NO_TRANS);
2372 }
2373
2374 { // solve coarse (1,1) block
2375 if (!ImporterCoarse11_.is_null() && !implicitTranspose_) {
2376 RCP<Teuchos::TimeMonitor> tmH = getTimer("import coarse (1,1)");
2377 P11resTmp_->doImport(*P11res_, *ImporterCoarse11_, Xpetra::INSERT);
2378 }
2379 if (!coarseA11_.is_null()) {
2380 RCP<Teuchos::TimeMonitor> tmH = getTimer("solve coarse (1,1)", coarseA11_->getRowMap()->getComm());
2382 }
2383 }
2384
2385 { // update current solution
2386 RCP<Teuchos::TimeMonitor> tmUp = getTimer("update");
2387 P11_->apply(*P11x_, *residual_, Teuchos::NO_TRANS);
2388 X.update(one, *residual_, one);
2389 }
2390}
2391
2392template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2393void RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::solve22(const MultiVector &RHS, MultiVector &X) const {
2394 if (onlyBoundary22_)
2395 return;
2396
2397 Scalar one = Teuchos::ScalarTraits<Scalar>::one();
2398
2399 { // compute residual
2400 RCP<Teuchos::TimeMonitor> tmRes = getTimer("residual calculation");
2403 Dk_1_->apply(*residual_, *Dres_, Teuchos::TRANS);
2404 else
2405 Dk_1_T_->apply(*residual_, *Dres_, Teuchos::NO_TRANS);
2406 }
2407
2408 { // solve (2,2) block
2409 if (!Importer22_.is_null() && !implicitTranspose_) {
2410 RCP<Teuchos::TimeMonitor> tm22 = getTimer("import (2,2)");
2411 DresTmp_->doImport(*Dres_, *Importer22_, Xpetra::INSERT);
2412 }
2413 if (!A22_.is_null()) {
2414 RCP<Teuchos::TimeMonitor> tm22 = getTimer("solve (2,2)", A22_->getRowMap()->getComm());
2415 Hierarchy22_->Iterate(*DresSubComm_, *DxSubComm_, numIters22_, true);
2416 }
2417 }
2418
2419 { // update current solution
2420 RCP<Teuchos::TimeMonitor> tmUp = getTimer("update");
2421 Dk_1_->apply(*Dx_, *residual_, Teuchos::NO_TRANS);
2422 X.update(one, *residual_, one);
2423 }
2424}
2425
2426template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2427void RefMaxwell<Scalar, LocalOrdinal, GlobalOrdinal, Node>::apply(const MultiVector &RHS, MultiVector &X,
2428 Teuchos::ETransp /* mode */,
2429 Scalar /* alpha */,
2430 Scalar /* beta */) const {
2431 RCP<Teuchos::TimeMonitor> tm = getTimer("solve");
2432
2433 // make sure that we have enough temporary memory
2434 if (!onlyBoundary11_ && X.getNumVectors() != P11res_->getNumVectors())
2435 allocateMemory(X.getNumVectors());
2436
2437 { // apply pre-smoothing
2438
2439 RCP<Teuchos::TimeMonitor> tmSm = getTimer("smoothing");
2440
2441 PreSmoother11_->Apply(X, RHS, use_as_preconditioner_);
2442 }
2443
2444 // do solve for the 2x2 block system
2445 if (mode_ == "additive")
2446 applyInverseAdditive(RHS, X);
2447 else if (mode_ == "121") {
2448 solveH(RHS, X);
2449 solve22(RHS, X);
2450 solveH(RHS, X);
2451 } else if (mode_ == "212") {
2452 solve22(RHS, X);
2453 solveH(RHS, X);
2454 solve22(RHS, X);
2455 } else if (mode_ == "1")
2456 solveH(RHS, X);
2457 else if (mode_ == "2")
2458 solve22(RHS, X);
2459 else if (mode_ == "7") {
2460 solveH(RHS, X);
2461 { // apply pre-smoothing
2462
2463 RCP<Teuchos::TimeMonitor> tmSm = getTimer("smoothing");
2464
2465 PreSmoother11_->Apply(X, RHS, false);
2466 }
2467 solve22(RHS, X);
2468 { // apply post-smoothing
2469
2470 RCP<Teuchos::TimeMonitor> tmSm = getTimer("smoothing");
2471
2472 PostSmoother11_->Apply(X, RHS, false);
2473 }
2474 solveH(RHS, X);
2475 } else if (mode_ == "none") {
2476 // do nothing
2477 } else
2478 applyInverseAdditive(RHS, X);
2479
2480 { // apply post-smoothing
2481
2482 RCP<Teuchos::TimeMonitor> tmSm = getTimer("smoothing");
2483
2484 PostSmoother11_->Apply(X, RHS, false);
2485 }
2486}
2487
2488template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2492
2493template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2495 RefMaxwell(const Teuchos::RCP<Matrix> &SM_Matrix,
2496 Teuchos::ParameterList &List,
2497 bool ComputePrec) {
2498 int spaceNumber = List.get<int>("refmaxwell: space number", 1);
2499
2500 RCP<Matrix> Dk_1, Dk_2, D0;
2501 RCP<Matrix> M1_beta, M1_alpha;
2502 RCP<Matrix> Mk_one, Mk_1_one;
2503 RCP<Matrix> invMk_1_invBeta, invMk_2_invAlpha;
2504 RCP<MultiVector> Nullspace11, Nullspace22;
2505 RCP<RealValuedMultiVector> NodalCoords;
2506
2507 Dk_1 = pop(List, "Dk_1", Dk_1);
2508 Dk_2 = pop<RCP<Matrix>>(List, "Dk_2", Dk_2);
2509 D0 = pop<RCP<Matrix>>(List, "D0", D0);
2510
2511 M1_beta = pop<RCP<Matrix>>(List, "M1_beta", M1_beta);
2512 M1_alpha = pop<RCP<Matrix>>(List, "M1_alpha", M1_alpha);
2513
2514 Mk_one = pop<RCP<Matrix>>(List, "Mk_one", Mk_one);
2515 Mk_1_one = pop<RCP<Matrix>>(List, "Mk_1_one", Mk_1_one);
2516
2517 invMk_1_invBeta = pop<RCP<Matrix>>(List, "invMk_1_invBeta", invMk_1_invBeta);
2518 invMk_2_invAlpha = pop<RCP<Matrix>>(List, "invMk_2_invAlpha", invMk_2_invAlpha);
2519
2520 Nullspace11 = pop<RCP<MultiVector>>(List, "Nullspace11", Nullspace11);
2521 Nullspace22 = pop<RCP<MultiVector>>(List, "Nullspace22", Nullspace22);
2522 NodalCoords = pop<RCP<RealValuedMultiVector>>(List, "Coordinates", NodalCoords);
2523
2524 // old parameter names
2525 if (List.isType<RCP<Matrix>>("Ms")) {
2526 if (M1_beta.is_null())
2527 M1_beta = pop<RCP<Matrix>>(List, "Ms");
2528 else
2529 TEUCHOS_ASSERT(false);
2530 }
2531 if (List.isType<RCP<Matrix>>("M1")) {
2532 if (Mk_one.is_null())
2533 Mk_one = pop<RCP<Matrix>>(List, "M1");
2534 else
2535 TEUCHOS_ASSERT(false);
2536 }
2537 if (List.isType<RCP<Matrix>>("M0inv")) {
2538 if (invMk_1_invBeta.is_null())
2539 invMk_1_invBeta = pop<RCP<Matrix>>(List, "M0inv");
2540 else
2541 TEUCHOS_ASSERT(false);
2542 }
2543 if (List.isType<RCP<MultiVector>>("Nullspace")) {
2544 if (Nullspace11.is_null())
2545 Nullspace11 = pop<RCP<MultiVector>>(List, "Nullspace");
2546 else
2547 TEUCHOS_ASSERT(false);
2548 }
2549
2550 if (spaceNumber == 1) {
2551 if (Dk_1.is_null())
2552 Dk_1 = D0;
2553 else if (D0.is_null())
2554 D0 = Dk_1;
2555 if (M1_beta.is_null())
2556 M1_beta = Mk_one;
2557 } else if (spaceNumber == 2) {
2558 if (Dk_2.is_null())
2559 Dk_2 = D0;
2560 else if (D0.is_null())
2561 D0 = Dk_2;
2562 }
2563
2564 initialize(spaceNumber,
2565 Dk_1, Dk_2, D0,
2566 M1_beta, M1_alpha,
2567 Mk_one, Mk_1_one,
2568 invMk_1_invBeta, invMk_2_invAlpha,
2569 Nullspace11, Nullspace22,
2570 NodalCoords,
2571 Teuchos::null, Teuchos::null,
2572 List);
2573
2574 if (SM_Matrix != Teuchos::null)
2575 resetMatrix(SM_Matrix, ComputePrec);
2576}
2577
2578template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2580 initialize(const Teuchos::RCP<Matrix> &D0_Matrix,
2581 const Teuchos::RCP<Matrix> &Ms_Matrix,
2582 const Teuchos::RCP<Matrix> &M0inv_Matrix,
2583 const Teuchos::RCP<Matrix> &M1_Matrix,
2584 const Teuchos::RCP<MultiVector> &Nullspace11,
2585 const Teuchos::RCP<RealValuedMultiVector> &NodalCoords,
2586 const Teuchos::RCP<MultiVector> &Material,
2587 Teuchos::ParameterList &List) {
2588 initialize(1,
2589 D0_Matrix, Teuchos::null, D0_Matrix,
2590 Ms_Matrix, Teuchos::null,
2591 M1_Matrix, Teuchos::null,
2592 M0inv_Matrix, Teuchos::null,
2593 Nullspace11, Teuchos::null,
2594 NodalCoords,
2595 Teuchos::null, Material,
2596 List);
2597}
2598
2599template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2601 initialize(const int k,
2602 const Teuchos::RCP<Matrix> &Dk_1,
2603 const Teuchos::RCP<Matrix> &Dk_2,
2604 const Teuchos::RCP<Matrix> &D0,
2605 const Teuchos::RCP<Matrix> &M1_beta,
2606 const Teuchos::RCP<Matrix> &M1_alpha,
2607 const Teuchos::RCP<Matrix> &Mk_one,
2608 const Teuchos::RCP<Matrix> &Mk_1_one,
2609 const Teuchos::RCP<Matrix> &invMk_1_invBeta,
2610 const Teuchos::RCP<Matrix> &invMk_2_invAlpha,
2611 const Teuchos::RCP<MultiVector> &Nullspace11,
2612 const Teuchos::RCP<MultiVector> &Nullspace22,
2613 const Teuchos::RCP<RealValuedMultiVector> &NodalCoords,
2614 const Teuchos::RCP<MultiVector> &Material_beta,
2615 const Teuchos::RCP<MultiVector> &Material_alpha,
2616 Teuchos::ParameterList &List) {
2617 spaceNumber_ = k;
2618 if (spaceNumber_ == 1)
2619 solverName_ = "RefMaxwell";
2620 else if (spaceNumber_ == 2)
2621 solverName_ = "RefDarcy";
2622 else
2623 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
2624 "spaceNumber needs to be 1 (HCurl) or 2 (HDiv)");
2625 HierarchyCoarse11_ = Teuchos::null;
2626 Hierarchy22_ = Teuchos::null;
2627 PreSmoother11_ = Teuchos::null;
2628 PostSmoother11_ = Teuchos::null;
2629 disable_addon_ = false;
2630 disable_addon_22_ = true;
2631 mode_ = "additive";
2632
2633 // set parameters
2634 setParameters(List);
2635
2636 // some pre-conditions
2637 TEUCHOS_ASSERT((k == 1) || (k == 2));
2638 // Need Dk_1
2639 TEUCHOS_ASSERT(Dk_1 != Teuchos::null);
2640 // Need D0 for aggregation
2641 TEUCHOS_ASSERT(D0 != Teuchos::null);
2642
2643 // Need M1_beta for aggregation
2644 TEUCHOS_ASSERT(M1_beta != Teuchos::null);
2645 // Need M1_alpha for aggregation if k>=1
2646 if (k >= 2)
2647 TEUCHOS_ASSERT(M1_alpha != Teuchos::null);
2648
2649 if (!disable_addon_) {
2650 // Need Mk_one and invMk_1_invBeta for addon11
2651 TEUCHOS_ASSERT(Mk_one != Teuchos::null);
2652 TEUCHOS_ASSERT(invMk_1_invBeta != Teuchos::null);
2653 }
2654
2655 if ((k >= 2) && !disable_addon_22_) {
2656 // Need Dk_2, Mk_1_one and invMk_2_invAlpha for addon22
2657 TEUCHOS_ASSERT(Dk_2 != Teuchos::null);
2658 TEUCHOS_ASSERT(Mk_1_one != Teuchos::null);
2659 TEUCHOS_ASSERT(invMk_2_invAlpha != Teuchos::null);
2660 }
2661
2662#ifdef HAVE_MUELU_DEBUG
2663
2664 TEUCHOS_ASSERT(D0->getRangeMap()->isSameAs(*D0->getRowMap()));
2665
2666 // M1_beta is square
2667 TEUCHOS_ASSERT(M1_beta->getDomainMap()->isSameAs(*M1_beta->getRangeMap()));
2668 TEUCHOS_ASSERT(M1_beta->getDomainMap()->isSameAs(*M1_beta->getRowMap()));
2669
2670 // M1_beta is consistent with D0
2671 TEUCHOS_ASSERT(M1_beta->getDomainMap()->isSameAs(*D0->getRangeMap()));
2672
2673 if (k >= 2) {
2674 // M1_alpha is square
2675 TEUCHOS_ASSERT(M1_alpha->getDomainMap()->isSameAs(*M1_alpha->getRangeMap()));
2676 TEUCHOS_ASSERT(M1_alpha->getDomainMap()->isSameAs(*M1_alpha->getRowMap()));
2677
2678 // M1_alpha is consistent with D0
2679 TEUCHOS_ASSERT(M1_alpha->getDomainMap()->isSameAs(*D0->getRangeMap()))
2680 }
2681
2682 if (!disable_addon_) {
2683 // Mk_one is square
2684 TEUCHOS_ASSERT(Mk_one->getDomainMap()->isSameAs(*Mk_one->getRangeMap()));
2685 TEUCHOS_ASSERT(Mk_one->getDomainMap()->isSameAs(*Mk_one->getRowMap()));
2686
2687 // Mk_one is consistent with Dk_1
2688 TEUCHOS_ASSERT(Mk_one->getDomainMap()->isSameAs(*Dk_1->getRangeMap()));
2689
2690 // invMk_1_invBeta is square
2691 TEUCHOS_ASSERT(invMk_1_invBeta->getDomainMap()->isSameAs(*invMk_1_invBeta->getRangeMap()));
2692 TEUCHOS_ASSERT(invMk_1_invBeta->getDomainMap()->isSameAs(*invMk_1_invBeta->getRowMap()));
2693
2694 // invMk_1_invBeta is consistent with Dk_1
2695 TEUCHOS_ASSERT(Mk_one->getDomainMap()->isSameAs(*Dk_1->getRangeMap()));
2696 }
2697
2698 if ((k >= 2) && !disable_addon_22_) {
2699 // Mk_1_one is square
2700 TEUCHOS_ASSERT(Mk_1_one->getDomainMap()->isSameAs(*Mk_1_one->getRangeMap()));
2701 TEUCHOS_ASSERT(Mk_1_one->getDomainMap()->isSameAs(*Mk_1_one->getRowMap()));
2702
2703 // Mk_1_one is consistent with Dk_1
2704 TEUCHOS_ASSERT(Mk_1_one->getDomainMap()->isSameAs(*Dk_1->getDomainMap()));
2705
2706 // Mk_1_one is consistent with Dk_2
2707 TEUCHOS_ASSERT(Mk_1_one->getDomainMap()->isSameAs(*Dk_2->getRangeMap()));
2708
2709 // invMk_2_invAlpha is square
2710 TEUCHOS_ASSERT(invMk_2_invAlpha->getDomainMap()->isSameAs(*invMk_2_invAlpha->getRangeMap()));
2711 TEUCHOS_ASSERT(invMk_2_invAlpha->getDomainMap()->isSameAs(*invMk_2_invAlpha->getRowMap()));
2712
2713 // invMk_2_invAlpha is consistent with Dk_2
2714 TEUCHOS_ASSERT(invMk_2_invAlpha->getDomainMap()->isSameAs(*Dk_2->getDomainMap()));
2715 }
2716#endif
2717
2718 D0_ = D0;
2719 if (Dk_1->getRowMap()->lib() == Xpetra::UseTpetra) {
2720 // We will remove boundary conditions from Dk_1, and potentially change maps, so we copy the input.
2721 // Fortunately, Dk_1 is quite sparse.
2722 // We cannot use the Tpetra copy constructor, since it does not copy the graph.
2723
2724 RCP<Matrix> Dk_1copy = MatrixFactory::Build(Dk_1->getRowMap(), Dk_1->getColMap(), 0);
2725 RCP<CrsMatrix> Dk_1copyCrs = toCrsMatrix(Dk_1copy);
2726 ArrayRCP<const size_t> Dk_1rowptr_RCP;
2727 ArrayRCP<const LO> Dk_1colind_RCP;
2728 ArrayRCP<const SC> Dk_1vals_RCP;
2729 toCrsMatrix(Dk_1)->getAllValues(Dk_1rowptr_RCP, Dk_1colind_RCP, Dk_1vals_RCP);
2730
2731 ArrayRCP<size_t> Dk_1copyrowptr_RCP;
2732 ArrayRCP<LO> Dk_1copycolind_RCP;
2733 ArrayRCP<SC> Dk_1copyvals_RCP;
2734 Dk_1copyCrs->allocateAllValues(Dk_1vals_RCP.size(), Dk_1copyrowptr_RCP, Dk_1copycolind_RCP, Dk_1copyvals_RCP);
2735 Dk_1copyrowptr_RCP.deepCopy(Dk_1rowptr_RCP());
2736 Dk_1copycolind_RCP.deepCopy(Dk_1colind_RCP());
2737 Dk_1copyvals_RCP.deepCopy(Dk_1vals_RCP());
2738 Dk_1copyCrs->setAllValues(Dk_1copyrowptr_RCP,
2739 Dk_1copycolind_RCP,
2740 Dk_1copyvals_RCP);
2741 Dk_1copyCrs->expertStaticFillComplete(Dk_1->getDomainMap(), Dk_1->getRangeMap(),
2742 toCrsMatrix(Dk_1)->getCrsGraph()->getImporter(),
2743 toCrsMatrix(Dk_1)->getCrsGraph()->getExporter());
2744 Dk_1_ = Dk_1copy;
2745 } else
2746 Dk_1_ = MatrixFactory::BuildCopy(Dk_1);
2747
2748 if ((!Dk_2.is_null()) && (Dk_2->getRowMap()->lib() == Xpetra::UseTpetra)) {
2749 // We will remove boundary conditions from Dk_2, and potentially change maps, so we copy the input.
2750 // Fortunately, Dk_2 is quite sparse.
2751 // We cannot use the Tpetra copy constructor, since it does not copy the graph.
2752
2753 RCP<Matrix> Dk_2copy = MatrixFactory::Build(Dk_2->getRowMap(), Dk_2->getColMap(), 0);
2754 RCP<CrsMatrix> Dk_2copyCrs = toCrsMatrix(Dk_2copy);
2755 ArrayRCP<const size_t> Dk_2rowptr_RCP;
2756 ArrayRCP<const LO> Dk_2colind_RCP;
2757 ArrayRCP<const SC> Dk_2vals_RCP;
2758 toCrsMatrix(Dk_2)->getAllValues(Dk_2rowptr_RCP, Dk_2colind_RCP, Dk_2vals_RCP);
2759
2760 ArrayRCP<size_t> Dk_2copyrowptr_RCP;
2761 ArrayRCP<LO> Dk_2copycolind_RCP;
2762 ArrayRCP<SC> Dk_2copyvals_RCP;
2763 Dk_2copyCrs->allocateAllValues(Dk_2vals_RCP.size(), Dk_2copyrowptr_RCP, Dk_2copycolind_RCP, Dk_2copyvals_RCP);
2764 Dk_2copyrowptr_RCP.deepCopy(Dk_2rowptr_RCP());
2765 Dk_2copycolind_RCP.deepCopy(Dk_2colind_RCP());
2766 Dk_2copyvals_RCP.deepCopy(Dk_2vals_RCP());
2767 Dk_2copyCrs->setAllValues(Dk_2copyrowptr_RCP,
2768 Dk_2copycolind_RCP,
2769 Dk_2copyvals_RCP);
2770 Dk_2copyCrs->expertStaticFillComplete(Dk_2->getDomainMap(), Dk_2->getRangeMap(),
2771 toCrsMatrix(Dk_2)->getCrsGraph()->getImporter(),
2772 toCrsMatrix(Dk_2)->getCrsGraph()->getExporter());
2773 Dk_2_ = Dk_2copy;
2774 } else if (!Dk_2.is_null())
2775 Dk_2_ = MatrixFactory::BuildCopy(Dk_2);
2776
2777 M1_beta_ = M1_beta;
2778 M1_alpha_ = M1_alpha;
2779
2780 Material_beta_ = Material_beta;
2781 Material_alpha_ = Material_alpha;
2782
2783 Mk_one_ = Mk_one;
2784 Mk_1_one_ = Mk_1_one;
2785
2786 invMk_1_invBeta_ = invMk_1_invBeta;
2787 invMk_2_invAlpha_ = invMk_2_invAlpha;
2788
2789 NodalCoords_ = NodalCoords;
2790 Nullspace11_ = Nullspace11;
2791 Nullspace22_ = Nullspace22;
2792
2793 dump(D0_, "D0.m");
2794 dump(Dk_1_, "Dk_1_clean.m");
2795 dump(Dk_2_, "Dk_2_clean.m");
2796
2797 dump(M1_beta_, "M1_beta.m");
2798 dump(M1_alpha_, "M1_alpha.m");
2799
2800 dump(Mk_one_, "Mk_one.m");
2801 dump(Mk_1_one_, "Mk_1_one.m");
2802
2803 dump(invMk_1_invBeta_, "invMk_1_invBeta.m");
2804 dump(invMk_2_invAlpha_, "invMk_2_invAlpha.m");
2805
2806 dumpCoords(NodalCoords_, "coords.m");
2807}
2808
2809template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2811 describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel /* verbLevel */) const {
2812 std::ostringstream oss;
2813
2814 RCP<const Teuchos::Comm<int>> comm = SM_Matrix_->getDomainMap()->getComm();
2815
2816#ifdef HAVE_MPI
2817 int root;
2818 if (!coarseA11_.is_null())
2819 root = comm->getRank();
2820 else
2821 root = -1;
2822
2823 int actualRoot;
2824 reduceAll(*comm, Teuchos::REDUCE_MAX, root, Teuchos::ptr(&actualRoot));
2825 root = actualRoot;
2826#endif
2827
2828 oss << "\n--------------------------------------------------------------------------------\n"
2829 << "--- " + solverName_ +
2830 " Summary ---\n"
2831 "--------------------------------------------------------------------------------"
2832 << std::endl;
2833 oss << std::endl;
2834
2835 GlobalOrdinal numRows;
2836 GlobalOrdinal nnz;
2837
2838 SM_Matrix_->getRowMap()->getComm()->barrier();
2839
2840 numRows = SM_Matrix_->getGlobalNumRows();
2841 nnz = SM_Matrix_->getGlobalNumEntries();
2842
2843 Xpetra::global_size_t tt = numRows;
2844 int rowspacer = 3;
2845 while (tt != 0) {
2846 tt /= 10;
2847 rowspacer++;
2848 }
2849 tt = nnz;
2850 int nnzspacer = 2;
2851 while (tt != 0) {
2852 tt /= 10;
2853 nnzspacer++;
2854 }
2855
2856 oss << "block " << std::setw(rowspacer) << " rows " << std::setw(nnzspacer) << " nnz " << std::setw(9) << " nnz/row" << std::endl;
2857 oss << "(1, 1)" << std::setw(rowspacer) << numRows << std::setw(nnzspacer) << nnz << std::setw(9) << as<double>(nnz) / numRows << std::endl;
2858
2859 if (!A22_.is_null()) {
2860 numRows = A22_->getGlobalNumRows();
2861 nnz = A22_->getGlobalNumEntries();
2862
2863 oss << "(2, 2)" << std::setw(rowspacer) << numRows << std::setw(nnzspacer) << nnz << std::setw(9) << as<double>(nnz) / numRows << std::endl;
2864 }
2865
2866 oss << std::endl;
2867
2868 {
2870 oss << "Smoother 11 both : " << PreSmoother11_->description() << std::endl;
2871 else {
2872 oss << "Smoother 11 pre : "
2873 << (PreSmoother11_ != null ? PreSmoother11_->description() : "no smoother") << std::endl;
2874 oss << "Smoother 11 post : "
2875 << (PostSmoother11_ != null ? PostSmoother11_->description() : "no smoother") << std::endl;
2876 }
2877 }
2878 oss << std::endl;
2879
2880 std::string outstr = oss.str();
2881
2882#ifdef HAVE_MPI
2883 RCP<const Teuchos::MpiComm<int>> mpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int>>(comm);
2884 MPI_Comm rawComm = (*mpiComm->getRawMpiComm())();
2885
2886 int strLength = outstr.size();
2887 MPI_Bcast(&strLength, 1, MPI_INT, root, rawComm);
2888 if (comm->getRank() != root)
2889 outstr.resize(strLength);
2890 MPI_Bcast(&outstr[0], strLength, MPI_CHAR, root, rawComm);
2891#endif
2892
2893 out << outstr;
2894
2895 if (!HierarchyCoarse11_.is_null())
2896 HierarchyCoarse11_->describe(out, GetVerbLevel());
2897
2898 if (!Hierarchy22_.is_null())
2899 Hierarchy22_->describe(out, GetVerbLevel());
2900
2901 if (IsPrint(Statistics2)) {
2902 // Print the grid of processors
2903 std::ostringstream oss2;
2904
2905 oss2 << "Sub-solver distribution over ranks" << std::endl;
2906 oss2 << "( (1,1) block only is indicated by '1', (2,2) block only by '2', and both blocks by 'B' and none by '.')" << std::endl;
2907
2908 int numProcs = comm->getSize();
2909#ifdef HAVE_MPI
2910 RCP<const Teuchos::MpiComm<int>> tmpic = rcp_dynamic_cast<const Teuchos::MpiComm<int>>(comm);
2911 TEUCHOS_TEST_FOR_EXCEPTION(tmpic == Teuchos::null, Exceptions::RuntimeError, "Cannot cast base Teuchos::Comm to Teuchos::MpiComm object.");
2912 RCP<const Teuchos::OpaqueWrapper<MPI_Comm>> rawMpiComm = tmpic->getRawMpiComm();
2913#endif
2914
2915 char status = 0;
2916 if (!coarseA11_.is_null())
2917 status += 1;
2918 if (!A22_.is_null())
2919 status += 2;
2920 std::vector<char> states(numProcs, 0);
2921#ifdef HAVE_MPI
2922 MPI_Gather(&status, 1, MPI_CHAR, &states[0], 1, MPI_CHAR, 0, *rawMpiComm);
2923#else
2924 states.push_back(status);
2925#endif
2926
2927 int rowWidth = std::min(Teuchos::as<int>(ceil(sqrt(numProcs))), 100);
2928 for (int proc = 0; proc < numProcs; proc += rowWidth) {
2929 for (int j = 0; j < rowWidth; j++)
2930 if (proc + j < numProcs)
2931 if (states[proc + j] == 0)
2932 oss2 << ".";
2933 else if (states[proc + j] == 1)
2934 oss2 << "1";
2935 else if (states[proc + j] == 2)
2936 oss2 << "2";
2937 else
2938 oss2 << "B";
2939 else
2940 oss2 << " ";
2941
2942 oss2 << " " << proc << ":" << std::min(proc + rowWidth, numProcs) - 1 << std::endl;
2943 }
2944 oss2 << std::endl;
2945 GetOStream(Statistics2) << oss2.str();
2946 }
2947}
2948
2949} // namespace MueLu
2950
2951#define MUELU_REFMAXWELL_SHORT
2952#endif // ifdef MUELU_REFMAXWELL_DEF_HPP
Various adapters that will create a MueLu preconditioner that is an Xpetra::Matrix.
#define MueLu_maxAll(rcpComm, in, out)
#define MueLu_sumAll(rcpComm, in, out)
#define MueLu_minAll(rcpComm, in, out)
MueLu::DefaultLocalOrdinal LocalOrdinal
MueLu::DefaultScalar Scalar
MueLu::DefaultGlobalOrdinal GlobalOrdinal
Factory to export aggregation info or visualize aggregates using VTK.
AmalgamationFactory for subblocks of strided map based amalgamation data.
Factory for creating a graph based on a given matrix.
Factory for creating a graph based on a given matrix.
Factory for generating coarse level map. Used by TentativePFactory.
Class for transferring coordinates from a finer level to a coarser one.
Exception throws to report errors in the internal logical of the program.
This class specifies the default factory that should generate some data on a Level if the data does n...
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.
void setlib(Xpetra::UnderlyingLib lib2)
void SetLevelID(int levelID)
Set level number.
void AddKeepFlag(const std::string &ename, const FactoryBase *factory=NoFactory::get(), KeepType keep=MueLu::Keep)
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())
void Request(const FactoryBase &factory)
Increment the storage counter for all the inputs of a factory.
void SetPreviousLevel(const RCP< Level > &previousLevel)
void SetFactoryManager(const RCP< const FactoryManagerBase > &factoryManager)
Set default factories (used internally by Hierarchy::SetLevel()).
static std::string translate(Teuchos::ParameterList &paramList, const std::string &defaultVals="")
: Translate ML parameters to MueLu parameter XML string
static const T & getDefault(const std::string &name)
Returns default value on the "master" list for a parameter with the specified name and type.
static void detectBoundaryConditionsSM(RCP< Matrix > &SM_Matrix, RCP< Matrix > &D0_Matrix, magnitudeType rowSumTol, bool useKokkos_, Kokkos::View< bool *, typename Node::device_type::memory_space > &BCrowsKokkos, Kokkos::View< bool *, typename Node::device_type::memory_space > &BCcolsKokkos, Kokkos::View< bool *, typename Node::device_type::memory_space > &BCdomainKokkos, int &BCedges, int &BCnodes, Teuchos::ArrayRCP< bool > &BCrows, Teuchos::ArrayRCP< bool > &BCcols, Teuchos::ArrayRCP< bool > &BCdomain, bool &allEdgesBoundary, bool &allNodesBoundary)
Detect Dirichlet boundary conditions.
static void thresholdedAbs(const RCP< Matrix > &A, const magnitudeType thresholded)
static RCP< Matrix > removeExplicitZeros(const RCP< Matrix > &A, const magnitudeType tolerance, const bool keepDiagonal=true, const size_t expectedNNZperRow=0)
Remove explicit zeros.
static void setMatvecParams(Matrix &A, RCP< ParameterList > matvecParams)
Sets matvec params on a matrix.
static RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > PtAPWrapper(const RCP< Matrix > &A, const RCP< Matrix > &P, Teuchos::ParameterList &params, const std::string &label)
Performs an P^T AP.
static const RCP< const NoFactory > getRCP()
Static Get() functions.
static std::string PrintMatrixInfo(const Matrix &A, const std::string &msgTag, RCP< const Teuchos::ParameterList > params=Teuchos::null)
Factory for building coarse matrices.
Factory for building coarse matrices.
Applies permutation to grid transfer operators.
Teuchos::RCP< MultiVector > P11resTmp_
Teuchos::RCP< Matrix > Mk_1_one_
Teuchos::RCP< RealValuedMultiVector > NodalCoords_
Coordinates.
Teuchos::RCP< MultiVector > Material_beta_
material for first space
Teuchos::ScalarTraits< Scalar >::coordinateType coordinateType
Teuchos::RCP< MultiVector > P11x_
Teuchos::RCP< MultiVector > Nullspace22_
Teuchos::RCP< MultiVector > residual_
Teuchos::RCP< Matrix > M1_beta_
mass matrices on first space with weights beta and alpha respectively
Teuchos::RCP< MultiVector > Dx_colmap_
Teuchos::RCP< Teuchos::ParameterList > coarseA11_AP_reuse_data_
Kokkos::View< bool *, typename Node::device_type::memory_space > BCrows11_
Vectors for BCs.
void setupSubSolve(Teuchos::RCP< Hierarchy > &hierarchy, Teuchos::RCP< Operator > &thyraPrecOp, const Teuchos::RCP< Matrix > &A, const Teuchos::RCP< MultiVector > &Nullspace, const Teuchos::RCP< RealValuedMultiVector > &Coords, const Teuchos::RCP< MultiVector > &Material, Teuchos::ParameterList &params, std::string &label, const bool reuse, const bool isSingular=false)
Setup a subsolve.
Teuchos::RCP< Teuchos::ParameterList > A22_AP_reuse_data_
Teuchos::RCP< Matrix > coarseA22_
Teuchos::RCP< MultiVector > P11res_
Temporary memory.
Teuchos::RCP< Matrix > coarseA11_
coarse 11, 22 and coarse 22 blocks
Teuchos::RCP< Matrix > Mk_one_
mass matrices with unit weight on k-th and (k-1)-th spaces
Teuchos::RCP< Matrix > Dk_1_T_
Teuchos::RCP< Teuchos::TimeMonitor > getTimer(std::string name, RCP< const Teuchos::Comm< int > > comm=Teuchos::null) const
get a (synced) timer
void allocateMemory(int numVectors) const
allocate multivectors for solve
RCP< Matrix > buildVectorNodalProlongator(const Teuchos::RCP< Matrix > &P_nodal) const
Teuchos::RCP< const Map > DorigDomainMap_
Teuchos::RCP< Matrix > SM_Matrix_
The system that is getting preconditioned.
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::VERB_HIGH) const
Teuchos::RCP< Matrix > invMk_1_invBeta_
inverse of mass matrices on (k-1)-th and (k-2)-th space with weights 1/beta and 1/alpha respectively
Kokkos::View< bool *, typename Node::device_type::memory_space > BCcols22_
void build22Matrix(const bool reuse, const bool doRebalancing, const int rebalanceStriding, const int numProcsA22)
Setup A22 = D0^T SM D0 and rebalance it, as well as D0 and Coords_.
void buildCoarse11Matrix()
Compute coarseA11 = P11^{T}*SM*P11 + addon efficiently.
void apply(const MultiVector &X, MultiVector &Y, Teuchos::ETransp mode=Teuchos::NO_TRANS, Scalar alpha=Teuchos::ScalarTraits< Scalar >::one(), Scalar beta=Teuchos::ScalarTraits< Scalar >::zero()) const
Teuchos::RCP< SmootherPrototype > PostSmootherData11_
Teuchos::RCP< Teuchos::ParameterList > A22_RAP_reuse_data_
RCP< MultiVector > buildNullspace(const int spaceNumber, const Kokkos::View< bool *, typename Node::device_type > &bcs, const bool applyBCs)
Builds a nullspace.
bool hasTransposeApply() const
Indicates whether this operator supports applying the adjoint operator.
void determineSubHierarchyCommSizes(bool &doRebalancing, int &rebalanceStriding, int &numProcsCoarseA11, int &numProcsA22)
Determine how large the sub-communicators for the two hierarchies should be.
Teuchos::RCP< RealValuedMultiVector > Coords22_
bool disable_addon_
Some options.
Kokkos::View< bool *, typename Node::device_type::memory_space > BCdomain22_
void solveH(const MultiVector &RHS, MultiVector &X) const
apply solve to 1-1 block only
Teuchos::ParameterList precList22_
Teuchos::RCP< Matrix > A22_
Teuchos::RCP< SmootherBase > PostSmoother11_
Teuchos::RCP< MultiVector > NullspaceCoarse11_
Nullspace for coarse (1,1) problem.
Teuchos::RCP< Matrix > Dk_2_
D_{k-2} matrix.
void setFineLevelSmoother11()
Set the fine level smoother.
Teuchos::RCP< Matrix > R11_
std::string solverName_
The name of the solver.
Teuchos::ScalarTraits< Scalar >::magnitudeType magnitudeType
void dumpCoords(const RCP< RealValuedMultiVector > &X, std::string name) const
dump out real-valued multivector
Teuchos::RCP< Matrix > D0_
D_0 matrix.
Teuchos::RCP< const Import > Importer22_
const Teuchos::RCP< const Map > getDomainMap() const
Returns the Xpetra::Map object associated with the domain of this operator.
Teuchos::RCP< MultiVector > Dx_
Teuchos::RCP< Matrix > M1_alpha_
Teuchos::RCP< Matrix > P11_
special prolongator for 11 block and its transpose
Teuchos::RCP< MultiVector > DresTmp_
Teuchos::RCP< MultiVector > P11resSubComm_
Teuchos::RCP< MultiVector > P11xSubComm_
Teuchos::RCP< Hierarchy > Hierarchy22_
Teuchos::RCP< Teuchos::ParameterList > getValidParamterList()
Teuchos::RCP< Matrix > P22_
special prolongator for 22 block and its transpose
Teuchos::RCP< Hierarchy > HierarchyCoarse11_
Two hierarchies: one for the coarse (1,1)-block, another for the (2,2)-block.
Teuchos::RCP< MultiVector > CoarseNullspace22_
Nullspace for coarse (2,2) problem.
Teuchos::RCP< MultiVector > DTR11Tmp_
Teuchos::RCP< SmootherPrototype > PreSmootherData11_
int spaceNumber_
The number of the space in the deRham complex.
Teuchos::RCP< MultiVector > Dres_
void applyInverseAdditive(const MultiVector &RHS, MultiVector &X) const
apply additive algorithm for 2x2 solve
Teuchos::RCP< RealValuedMultiVector > CoordsCoarse11_
Teuchos::RCP< const Import > DorigImporter_
void buildProlongator(const int spaceNumber, const Teuchos::RCP< Matrix > &A_nodal_Matrix, const RCP< MultiVector > &EdgeNullspace, Teuchos::RCP< Matrix > &edgeProlongator, Teuchos::RCP< MultiVector > &coarseEdgeNullspace, Teuchos::RCP< RealValuedMultiVector > &coarseNodalCoords) const
const Teuchos::RCP< const Map > getRangeMap() const
Returns the Xpetra::Map object associated with the range of this operator.
void compute(bool reuse=false)
Setup the preconditioner.
Teuchos::ParameterList precList11_
Teuchos::RCP< Matrix > Dk_1_
D_{k-1} matrix and its transpose.
Teuchos::RCP< Teuchos::ParameterList > coarseA11_RAP_reuse_data_
void initialize(const Teuchos::RCP< Matrix > &D0_Matrix, const Teuchos::RCP< Matrix > &Ms_Matrix, const Teuchos::RCP< Matrix > &M0inv_Matrix, const Teuchos::RCP< Matrix > &M1_Matrix, const Teuchos::RCP< MultiVector > &Nullspace11, const Teuchos::RCP< RealValuedMultiVector > &NodalCoords, const Teuchos::RCP< MultiVector > &Material, Teuchos::ParameterList &List)
void buildNodalProlongator(const Teuchos::RCP< Matrix > &A_nodal, Teuchos::RCP< Matrix > &P_nodal, Teuchos::RCP< MultiVector > &Nullspace_nodal, Teuchos::RCP< RealValuedMultiVector > &Coords_nodal) const
Teuchos::RCP< Matrix > Addon11_
the addon for the 11 block
Teuchos::RCP< Matrix > buildProjection(const int spaceNumber, const RCP< MultiVector > &EdgeNullspace) const
Builds a projection from a vector values space into a vector valued nodal space.
Teuchos::ParameterList parameterList_
Parameter lists.
void dump(const RCP< Matrix > &A, std::string name) const
dump out matrix
void rebalanceCoarse11Matrix(const int rebalanceStriding, const int numProcsCoarseA11)
rebalance the coarse A11 matrix, as well as P11, CoordsCoarse11 and Addon11
Teuchos::RCP< MultiVector > Nullspace11_
Nullspace for (1.1) block.
size_t dim_
The spatial dimension.
Teuchos::RCP< MultiVector > P11x_colmap_
Teuchos::RCP< MultiVector > DresSubComm_
void resetMatrix(Teuchos::RCP< Matrix > SM_Matrix_new, bool ComputePrec=true)
Reset system matrix.
void setParameters(Teuchos::ParameterList &list)
Set parameters.
Teuchos::RCP< SmootherBase > PreSmoother11_
Teuchos::RCP< MultiVector > Material_alpha_
Teuchos::RCP< const Import > ImporterCoarse11_
Importer to coarse (1,1) hierarchy.
Teuchos::RCP< Matrix > R22_
RCP< Matrix > buildAddon(const int spaceNumber)
void solve22(const MultiVector &RHS, MultiVector &X) const
apply solve to 2-2 block only
Teuchos::RCP< Matrix > invMk_2_invAlpha_
Teuchos::RCP< MultiVector > DxSubComm_
Factory for building permutation matrix that can be be used to shuffle data (matrices,...
Factory for determing the number of partitions for rebalancing.
Factory for building Smoothed Aggregation prolongators.
Generic Smoother Factory for generating the smoothers of the MG hierarchy.
Factory for building tentative prolongator.
Class that encapsulates external library smoothers.
static void ZeroDirichletRows(Teuchos::RCP< Xpetra::Matrix< Scalar, DefaultLocalOrdinal, DefaultGlobalOrdinal, DefaultNode > > &A, const std::vector< DefaultLocalOrdinal > &dirichletRows, Scalar replaceWith=Teuchos::ScalarTraits< Scalar >::zero())
static void ZeroDirichletCols(Teuchos::RCP< Matrix > &A, const Teuchos::ArrayRCP< const bool > &dirichletCols, Scalar replaceWith=Teuchos::ScalarTraits< Scalar >::zero())
static void ApplyRowSumCriterion(const Xpetra::Matrix< Scalar, DefaultLocalOrdinal, DefaultGlobalOrdinal, DefaultNode > &A, const Magnitude rowSumTol, Teuchos::ArrayRCP< bool > &dirichletRows)
static void ApplyOAZToMatrixRows(Teuchos::RCP< Xpetra::Matrix< Scalar, DefaultLocalOrdinal, DefaultGlobalOrdinal, DefaultNode > > &A, const std::vector< DefaultLocalOrdinal > &dirichletRows)
static void DetectDirichletColsAndDomains(const Xpetra::Matrix< Scalar, DefaultLocalOrdinal, DefaultGlobalOrdinal, DefaultNode > &A, const Teuchos::ArrayRCP< bool > &dirichletRows, Teuchos::ArrayRCP< bool > dirichletCols, Teuchos::ArrayRCP< bool > dirichletDomain)
static RCP< MultiVector > Residual(const Xpetra::Operator< Scalar, DefaultLocalOrdinal, DefaultGlobalOrdinal, DefaultNode > &Op, const MultiVector &X, const MultiVector &RHS)
static RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Transpose(Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, bool optimizeTranspose=false, const std::string &label=std::string(), const Teuchos::RCP< Teuchos::ParameterList > &params=Teuchos::null)
static RCP< Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > RealValuedToScalarMultiVector(RCP< Xpetra::MultiVector< typename Teuchos::ScalarTraits< Scalar >::coordinateType, LocalOrdinal, GlobalOrdinal, Node > > X)
Teuchos::FancyOStream & GetOStream(MsgType type, int thisProcRankOnly=0) const
Get an output stream for outputting the input message type.
VerbLevel GetVerbLevel() const
Get the verbosity level.
int SetProcRankVerbose(int procRank) const
Set proc rank used for printing.
static VerbLevel GetDefaultVerbLevel()
Get the default (global) verbosity level.
bool IsPrint(MsgType type, int thisProcRankOnly=-1) const
Find out whether we need to print out information for a specific message type.
static void SetMueLuOStream(const Teuchos::RCP< Teuchos::FancyOStream > &mueluOStream)
static void SetDefaultVerbLevel(const VerbLevel defaultVerbLevel)
Set the default (global) verbosity level.
static void SetMueLuOFileStream(const std::string &filename)
Interface to Zoltan2 library.
Interface to Zoltan library.
Namespace for MueLu classes and methods.
@ Warnings0
Important warning messages (one line).
@ Statistics2
Print even more statistics.
@ Runtime0
One-liner description of what is happening.
@ Runtime1
Description of what is happening (more verbose).
@ Warnings1
Additional warnings.
@ Timings
Print all timing information.
MsgType toVerbLevel(const std::string &verbLevelStr)
T pop(Teuchos::ParameterList &pl, std::string const &name_in)
Teuchos::RCP< MueLu::Hierarchy< Scalar, LocalOrdinal, GlobalOrdinal, Node > > CreateXpetraPreconditioner(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > op, const Teuchos::ParameterList &inParamList)
Helper function to create a MueLu preconditioner that can be used by Xpetra.Given an Xpetra::Matrix,...