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