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