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