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