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