MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_Maxwell1_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_MAXWELL1_DEF_HPP
11#define MUELU_MAXWELL1_DEF_HPP
12
13#include <sstream>
15
16#include "MueLu_ConfigDefs.hpp"
17
18#include "Xpetra_CrsMatrixWrap_decl.hpp"
19#include "Xpetra_Map.hpp"
21#include "Xpetra_MatrixUtils.hpp"
22
24#include "MueLu_Maxwell_Utils.hpp"
25
26#include "MueLu_ReitzingerPFactory.hpp"
27#include "MueLu_Utilities.hpp"
28#include "MueLu_Level.hpp"
29#include "MueLu_Hierarchy.hpp"
30#include "MueLu_RAPFactory.hpp"
31#include "MueLu_RebalanceAcFactory.hpp"
32#include "MueLu_Monitor.hpp"
33#include "MueLu_PerfUtils.hpp"
34#include "MueLu_ParameterListInterpreter.hpp"
35#include "MueLu_HierarchyManager.hpp"
36#include <MueLu_HierarchyUtils.hpp>
40#include <MueLu_RefMaxwellSmoother.hpp>
41
42#ifdef HAVE_MUELU_CUDA
43#include "cuda_profiler_api.h"
44#endif
45
46namespace MueLu {
47
48template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
49const Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node> > Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getDomainMap() const {
50 return SM_Matrix_->getDomainMap();
51}
52
53template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
54const Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node> > Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getRangeMap() const {
55 return SM_Matrix_->getRangeMap();
56}
57
58template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
60 if (list.isType<std::string>("parameterlist: syntax") && list.get<std::string>("parameterlist: syntax") == "ml") {
61 list.remove("parameterlist: syntax");
62 Teuchos::ParameterList newList;
63
64 // interpret ML list
65 newList.sublist("maxwell1: 22list") = *Teuchos::getParametersFromXmlString(MueLu::ML2MueLuParameterTranslator::translate(list, "Maxwell"));
66
67 // Hardwiring options to ensure ML compatibility
68 newList.sublist("maxwell1: 22list").set("use kokkos refactor", false);
69
70 newList.sublist("maxwell1: 11list").set("use kokkos refactor", false);
71 newList.sublist("maxwell1: 11list").set("tentative: constant column sums", false);
72 newList.sublist("maxwell1: 11list").set("tentative: calculate qr", false);
73
74 newList.sublist("maxwell1: 11list").set("aggregation: use ml scaling of drop tol", true);
75 newList.sublist("maxwell1: 22list").set("aggregation: use ml scaling of drop tol", true);
76
77 newList.sublist("maxwell1: 22list").set("aggregation: min agg size", 3);
78 newList.sublist("maxwell1: 22list").set("aggregation: match ML phase1", true);
79 newList.sublist("maxwell1: 22list").set("aggregation: match ML phase2a", true);
80 newList.sublist("maxwell1: 22list").set("aggregation: match ML phase2b", true);
81
82 if (list.isParameter("aggregation: damping factor") && list.get<double>("aggregation: damping factor") == 0.0)
83 newList.sublist("maxwell1: 11list").set("multigrid algorithm", "unsmoothed reitzinger");
84 else
85 newList.sublist("maxwell1: 11list").set("multigrid algorithm", "smoothed reitzinger");
86 newList.sublist("maxwell1: 11list").set("aggregation: type", "uncoupled");
87
88 newList.sublist("maxwell1: 22list").set("multigrid algorithm", "unsmoothed");
89 newList.sublist("maxwell1: 22list").set("aggregation: type", "uncoupled");
90
91 if (newList.sublist("maxwell1: 22list").isType<std::string>("verbosity"))
92 newList.set("verbosity", newList.sublist("maxwell1: 22list").get<std::string>("verbosity"));
93
94 // Move coarse solver and smoother stuff to 11list
95 std::vector<std::string> convert = {"coarse:", "smoother:", "smoother: pre", "smoother: post"};
96 for (auto it = convert.begin(); it != convert.end(); ++it) {
97 if (newList.sublist("maxwell1: 22list").isType<std::string>(*it + " type")) {
98 newList.sublist("maxwell1: 11list").set(*it + " type", newList.sublist("maxwell1: 22list").get<std::string>(*it + " type"));
99 newList.sublist("maxwell1: 22list").remove(*it + " type");
100 }
101 if (newList.sublist("maxwell1: 22list").isSublist(*it + " params")) {
102 newList.sublist("maxwell1: 11list").set(*it + " params", newList.sublist("maxwell1: 22list").sublist(*it + " params"));
103 newList.sublist("maxwell1: 22list").remove(*it + " params");
104 }
105 }
106
107 newList.sublist("maxwell1: 22list").set("smoother: type", "none");
108 newList.sublist("maxwell1: 22list").set("coarse: type", "none");
109
110 newList.set("maxwell1: nodal smoother fix zero diagonal threshold", 1e-10);
111 newList.sublist("maxwell1: 22list").set("rap: fix zero diagonals", true);
112 newList.sublist("maxwell1: 22list").set("rap: fix zero diagonals threshold", 1e-10);
113
114 list = newList;
115 }
116
117 std::string mode_string = list.get("maxwell1: mode", MasterList::getDefault<std::string>("maxwell1: mode"));
118 applyBCsTo22_ = list.get("maxwell1: apply BCs to 22", false);
119 dump_matrices_ = list.get("maxwell1: dump matrices", MasterList::getDefault<bool>("maxwell1: dump matrices"));
120 check_D0_scaling_ = list.get("maxwell1: check and fix D0 scaling", MasterList::getDefault<bool>("maxwell1: check and fix D0 scaling"));
121
122 // Default smoother. We'll copy this around.
123 Teuchos::ParameterList defaultSmootherList;
124 defaultSmootherList.set("smoother: type", "CHEBYSHEV");
125 defaultSmootherList.sublist("smoother: params").set("chebyshev: degree", 2);
126 defaultSmootherList.sublist("smoother: params").set("chebyshev: ratio eigenvalue", 7.0);
127 defaultSmootherList.sublist("smoother: params").set("chebyshev: eigenvalue max iterations", 30);
128
129 // Make sure verbosity gets passed to the sublists
130 std::string verbosity = list.get("verbosity", "high");
132
133 // Check the validity of the run mode
134 if (mode_ != MODE_GMHD_STANDARD) {
135 if (mode_string == "standard")
136 mode_ = MODE_STANDARD;
137 else if (mode_string == "refmaxwell")
138 mode_ = MODE_REFMAXWELL;
139 else if (mode_string == "edge only")
140 mode_ = MODE_EDGE_ONLY;
141 else {
142 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "Must use mode 'standard', 'refmaxwell', 'edge only', or use the GMHD constructor.");
143 }
144 }
145
146 // If we're in edge only or standard modes, then the (2,2) hierarchy gets built without smoothers.
147 // Otherwise we use the user's smoothers (defaulting to Chebyshev if unspecified)
148 if (list.isSublist("maxwell1: 22list"))
149 precList22_ = list.sublist("maxwell1: 22list");
150 else if (list.isSublist("refmaxwell: 22list"))
151 precList22_ = list.sublist("refmaxwell: 22list");
152 if (mode_ == MODE_EDGE_ONLY || mode_ == MODE_STANDARD || mode_ == MODE_GMHD_STANDARD)
153 precList22_.set("smoother: pre or post", "none");
154 else if (!precList22_.isType<std::string>("Preconditioner Type") &&
155 !precList22_.isType<std::string>("smoother: type") &&
156 !precList22_.isType<std::string>("smoother: pre type") &&
157 !precList22_.isType<std::string>("smoother: post type")) {
158 precList22_ = defaultSmootherList;
159 }
160 precList22_.set("verbosity", precList22_.get("verbosity", verbosity));
161
162 // For the (1,1) hierarchy we'll use Hiptmair (STANDARD) or Chebyshev (EDGE_ONLY / REFMAXWELL) if
163 // the user doesn't specify things
164 if (list.isSublist("maxwell1: 11list"))
165 precList11_ = list.sublist("maxwell1: 11list");
166 else if (list.isSublist("refmaxwell: 11list"))
167 precList11_ = list.sublist("refmaxwell: 11list");
168
169 if (mode_ == MODE_GMHD_STANDARD) {
170 precList11_.set("smoother: pre or post", "none");
171 precList11_.set("smoother: type", "none");
172 }
173 if (!precList11_.isType<std::string>("Preconditioner Type") &&
174 !precList11_.isType<std::string>("smoother: type") &&
175 !precList11_.isType<std::string>("smoother: pre type") &&
176 !precList11_.isType<std::string>("smoother: post type")) {
177 if (mode_ == MODE_EDGE_ONLY || mode_ == MODE_REFMAXWELL) {
178 precList11_ = defaultSmootherList;
179 }
180 if (mode_ == MODE_STANDARD) {
181 precList11_.set("smoother: type", "HIPTMAIR");
182 precList11_.set("hiptmair: smoother type 1", "CHEBYSHEV");
183 precList11_.set("hiptmair: smoother type 2", "CHEBYSHEV");
184 precList11_.sublist("hiptmair: smoother list 1") = defaultSmootherList;
185 precList11_.sublist("hiptmair: smoother list 2") = defaultSmootherList;
186 }
187 }
188 precList11_.set("verbosity", precList11_.get("verbosity", verbosity));
189
190 // Reuse support
191 if (enable_reuse_ &&
192 !precList11_.isType<std::string>("Preconditioner Type") &&
193 !precList11_.isParameter("reuse: type"))
194 precList11_.set("reuse: type", "full");
195 if (enable_reuse_ &&
196 !precList22_.isType<std::string>("Preconditioner Type") &&
197 !precList22_.isParameter("reuse: type"))
198 precList22_.set("reuse: type", "full");
199
200 // Are we using Kokkos?
201 useKokkos_ = !Node::is_serial;
202 useKokkos_ = list.get("use kokkos refactor", useKokkos_);
203
204 parameterList_ = list;
205}
206
207template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
209 Teuchos::ParameterList precListGmhd;
210
211 MueLu::HierarchyUtils<SC, LO, GO, NO>::CopyBetweenHierarchies(*Hierarchy11_, *HierarchyGmhd_, "P", "Psubblock", "RCP<Matrix>");
212
213 HierarchyGmhd_->GetLevel(0)->Set("A", GmhdA_Matrix_);
214 GmhdA_Matrix_->setObjectLabel("GmhdA");
215
216 TEUCHOS_TEST_FOR_EXCEPTION(!List.isSublist("maxwell1: Gmhdlist"), Exceptions::RuntimeError, "Must provide maxwell1: Gmhdlist for GMHD setup");
217 precListGmhd = List.sublist("maxwell1: Gmhdlist");
218 precListGmhd.set("coarse: max size", 1);
219 precListGmhd.set("max levels", HierarchyGmhd_->GetNumLevels());
220 RCP<MueLu::HierarchyManager<SC, LO, GO, NO> > mueLuFactory = rcp(new MueLu::ParameterListInterpreter<SC, LO, GO, NO>(precListGmhd, GmhdA_Matrix_->getDomainMap()->getComm()));
221 HierarchyGmhd_->setlib(GmhdA_Matrix_->getDomainMap()->lib());
222 HierarchyGmhd_->SetProcRankVerbose(GmhdA_Matrix_->getDomainMap()->getComm()->getRank());
223 mueLuFactory->SetupHierarchy(*HierarchyGmhd_);
224}
225
226template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
228 /* Algorithm overview for Maxwell1 construction:
229
230 1) Create a nodal auxillary hierarchy based on (a) the user's nodal matrix or (b) a matrix constructed
231 by D0^T A D0 if the user doesn't provide a nodal matrix. We call this matrix "NodeAggMatrix."
232
233 2) If the user provided a node matrix, we use the prolongators from the auxillary nodal hierarchy
234 to generate matrices for smoothers on all levels. We call this "NodeMatrix." Otherwise NodeMatrix = NodeAggMatrix
235
236 3) We stick all of the nodal P matrices and NodeMatrix objects on the final (1,1) hierarchy and then use the
237 ReitzingerPFactory to generate the edge P and A matrices.
238 */
239
240#ifdef HAVE_MUELU_CUDA
241 if (parameterList_.get<bool>("maxwell1: cuda profile setup", false)) cudaProfilerStart();
242#endif
243
244 std::string timerLabel;
245 if (reuse)
246 timerLabel = "MueLu Maxwell1: compute (reuse)";
247 else
248 timerLabel = "MueLu Maxwell1: compute";
249 RCP<Teuchos::TimeMonitor> tmCompute = getTimer(timerLabel);
250
252 // Generate Kn and apply BCs (if needed)
253 bool have_generated_Kn = false;
254 if (Kn_Matrix_.is_null()) {
255 // generate_kn() will do diagonal repair if requested
256 GetOStream(Runtime0) << "Maxwell1::compute(): Kn not provided. Generating." << std::endl;
257 Kn_Matrix_ = generate_kn();
258 have_generated_Kn = true;
259 } else if (parameterList_.get<bool>("rap: fix zero diagonals", true)) {
260 magnitudeType threshold;
261 if (parameterList_.isType<magnitudeType>("rap: fix zero diagonals threshold"))
262 threshold = parameterList_.get<magnitudeType>("rap: fix zero diagonals threshold",
263 Teuchos::ScalarTraits<double>::eps());
264 else
265 threshold = Teuchos::as<magnitudeType>(parameterList_.get<double>("rap: fix zero diagonals threshold",
266 Teuchos::ScalarTraits<double>::eps()));
267 Scalar replacement = Teuchos::as<Scalar>(parameterList_.get<double>("rap: fix zero diagonals replacement",
268 MasterList::getDefault<double>("rap: fix zero diagonals replacement")));
269 Xpetra::MatrixUtils<SC, LO, GO, NO>::CheckRepairMainDiagonal(Kn_Matrix_, true, GetOStream(Warnings1), threshold, replacement);
270 }
271
273 // Generate the (2,2) Hierarchy
274 Kn_Matrix_->setObjectLabel("Maxwell1 (2,2)");
275
276 /* Critical ParameterList changes */
277 if (!Coords_.is_null())
278 precList22_.sublist("user data").set("Coordinates", Coords_);
279 if (!Material_.is_null())
280 precList22_.sublist("user data").set("Material", Material_);
281
282 /* Repartitioning *must* be in sync between hierarchies, which means
283 that we need to keep the importers in sync too */
284 if (precList22_.isParameter("repartition: enable")) {
285 bool repartition = precList22_.get<bool>("repartition: enable");
286 precList11_.set("repartition: enable", repartition);
287
288 // If we're repartitioning (2,2), we need to rebalance for (1,1) to do the right thing,
289 // as well as keep the importers
290 if (repartition) {
291 // FIXME: We should probably update rather than clobber
292 precList22_.set("repartition: save importer", true);
293 // precList22_.set("repartition: rebalance P and R", false);
294 precList22_.set("repartition: rebalance P and R", true);
295 }
296
297 if (precList22_.isParameter("repartition: use subcommunicators")) {
298 precList11_.set("repartition: use subcommunicators", precList22_.get<bool>("repartition: use subcommunicators"));
299
300 // We do not want (1,1) and (2,2) blocks being repartitioned seperately, so we specify the map that
301 // is going to be used (this is generated in ReitzingerPFactory)
302 if (precList11_.get<bool>("repartition: use subcommunicators") == true)
303 precList11_.set("repartition: use subcommunicators in place", true);
304 } else {
305 // We'll have Maxwell1 default to using subcommunicators if you don't specify
306 precList11_.set("repartition: use subcommunicators", true);
307 precList22_.set("repartition: use subcommunicators", true);
308
309 // We do not want (1,1) and (2,2) blocks being repartitioned seperately, so we specify the map that
310 // is going to be used (this is generated in ReitzingerPFactory)
311 precList11_.set("repartition: use subcommunicators in place", true);
312 }
313
314 } else
315 precList11_.remove("repartition: enable", false);
316
318 // Remove explicit zeros from matrices
319 /*
320 Maxwell_Utils<SC,LO,GO,NO>::removeExplicitZeros(parameterList_,D0_Matrix_,SM_Matrix_);
321
322
323 if (IsPrint(Statistics2)) {
324 RCP<ParameterList> params = rcp(new ParameterList());;
325 params->set("printLoadBalancingInfo", true);
326 params->set("printCommInfo", true);
327 GetOStream(Statistics2) << PerfUtils::PrintMatrixInfo(*SM_Matrix_, "SM_Matrix", params);
328 }
329 */
330
332 // Detect Dirichlet boundary conditions
333 if (!reuse) {
334 magnitudeType rowSumTol = precList11_.get("aggregation: row sum drop tol", -1.0);
335 Maxwell_Utils<SC, LO, GO, NO>::detectBoundaryConditionsSM(SM_Matrix_, D0_Matrix_, rowSumTol,
336 useKokkos_, BCrowsKokkos_, BCcolsKokkos_, BCdomainKokkos_,
337 BCedges_, BCnodes_, BCrows_, BCcols_, BCdomain_,
338 allEdgesBoundary_, allNodesBoundary_);
339 if (IsPrint(Statistics2)) {
340 GetOStream(Statistics2) << "MueLu::Maxwell1::compute(): Detected " << BCedges_ << " BC rows and " << BCnodes_ << " BC columns." << std::endl;
341 }
342 }
343
344 if (allEdgesBoundary_) {
345 // All edges have been detected as boundary edges.
346 // Do not attempt to construct sub-hierarchies, but just set up a single level preconditioner.
347 GetOStream(Warnings0) << "All edges are detected as boundary edges!" << std::endl;
348 mode_ = MODE_EDGE_ONLY;
349
350 // Generate single level hierarchy for the edge
351 precList22_.set("max levels", 1);
352 }
353
354 if (allNodesBoundary_) {
355 // All Nodes have been detected as boundary nodes.
356 // Do not attempt to construct sub-hierarchies, but just set up a single level preconditioner.
357 GetOStream(Warnings0) << "All nodes are detected as boundary nodes!" << std::endl;
358 mode_ = MODE_EDGE_ONLY;
359
360 // Generate single level hierarchy for the edge
361 precList22_.set("max levels", 1);
362 }
363
365 // Build (2,2) hierarchy
366 Hierarchy22_ = MueLu::CreateXpetraPreconditioner(Kn_Matrix_, precList22_);
367
369 // Apply boundary conditions to D0 (if needed)
370 if (!reuse) {
371 D0_Matrix_->resumeFill();
372 Scalar replaceWith = Teuchos::ScalarTraits<SC>::zero();
373
374 if (applyBCsTo22_) {
375 GetOStream(Runtime0) << "Maxwell1::compute(): nuking BC rows/cols of D0" << std::endl;
376 if (useKokkos_) {
377 Utilities::ZeroDirichletCols(D0_Matrix_, BCcolsKokkos_, replaceWith);
378 } else {
379 Utilities::ZeroDirichletCols(D0_Matrix_, BCcols_, replaceWith);
380 }
381 } else {
382 GetOStream(Runtime0) << "Maxwell1::compute(): nuking BC rows of D0" << std::endl;
383 if (useKokkos_) {
384 Utilities::ZeroDirichletRows(D0_Matrix_, BCrowsKokkos_, replaceWith);
385 } else {
386 Utilities::ZeroDirichletRows(D0_Matrix_, BCrows_, replaceWith);
387 }
388 }
389
390 D0_Matrix_->fillComplete(D0_Matrix_->getDomainMap(), D0_Matrix_->getRangeMap());
391 }
392
394 // What ML does is generate nodal prolongators with an auxillary hierarchy based on the
395 // user's (2,2) matrix. The actual nodal matrices for smoothing are generated by the
396 // Hiptmair smoother construction. We're not going to do that --- we'll
397 // do as we insert them into the final (1,1) hierarchy.
398
399 // Level 0
400 RCP<Matrix> Kn_Smoother_0;
401 if (have_generated_Kn) {
402 Kn_Smoother_0 = Kn_Matrix_;
403 } else {
404 Kn_Smoother_0 = generate_kn();
405 }
406
408 // Copy the relevant (2,2) data to the (1,1) hierarchy
409 Hierarchy11_ = rcp(new Hierarchy("Maxwell1 (1,1)"));
410 RCP<Matrix> OldSmootherMatrix;
411 RCP<Level> OldEdgeLevel;
412 for (int i = 0; i < Hierarchy22_->GetNumLevels(); i++) {
413 Hierarchy11_->AddNewLevel();
414 RCP<Level> NodeL = Hierarchy22_->GetLevel(i);
415 RCP<Level> EdgeL = Hierarchy11_->GetLevel(i);
416 RCP<Operator> NodeAggOp = NodeL->Get<RCP<Operator> >("A");
417 RCP<Matrix> NodeAggMatrix = rcp_dynamic_cast<Matrix>(NodeAggOp);
418 std::string labelstr = FormattingHelper::getColonLabel(EdgeL->getObjectLabel());
419
420 if (i == 0) {
421 EdgeL->Set("A", SM_Matrix_);
422 EdgeL->Set("D0", D0_Matrix_);
423
424 EdgeL->Set("NodeAggMatrix", NodeAggMatrix);
425 EdgeL->Set("NodeMatrix", Kn_Smoother_0);
426 OldSmootherMatrix = Kn_Smoother_0;
427 OldEdgeLevel = EdgeL;
428 } else {
429 // Set the Nodal P
430 // NOTE: ML uses normalized prolongators for the aggregation hierarchy
431 // and then prolongators of all 1's for doing the Reitzinger prolongator
432 // generation for the edge hierarchy.
433 auto NodalP = NodeL->Get<RCP<Matrix> >("P");
434 auto NodalP_ones = Utilities::ReplaceNonZerosWithOnes(NodalP);
435 TEUCHOS_TEST_FOR_EXCEPTION(NodalP_ones.is_null(), Exceptions::RuntimeError, "Applying ones to prolongator failed");
436 EdgeL->Set("Pnodal", NodalP_ones);
437
438 // Get the importer if we have one (for repartitioning)
439 RCP<const Import> importer;
440 if (NodeL->IsAvailable("Importer")) {
441 importer = NodeL->Get<RCP<const Import> >("Importer");
442 EdgeL->Set("NodeImporter", importer);
443 }
444
445 // If we repartition a processor away, a RCP<Operator> is stuck
446 // on the level instead of an RCP<Matrix>
447 if (!OldSmootherMatrix.is_null() && !NodalP_ones.is_null()) {
448 EdgeL->Set("NodeAggMatrix", NodeAggMatrix);
449 if (!have_generated_Kn) {
450 // The user gave us a Kn on the fine level, so we're using a seperate aggregation
451 // hierarchy from the smoothing hierarchy.
452
453 // ML does a *fixed* 1e-10 diagonal repair on the Nodal Smoothing Matrix
454 // This fix is applied *after* the next level is generated, but before the smoother is.
455 // We can see this behavior from ML, though it isn't 100% clear from the code *how* it happens.
456 // So, here we turn the fix off, then once we've generated the new matrix, we fix the old one.
457
458 // Generate the new matrix
459 Teuchos::ParameterList RAPlist;
460 RAPlist.set("rap: fix zero diagonals", false);
461 RCP<Matrix> NewKn = Maxwell_Utils<SC, LO, GO, NO>::PtAPWrapper(OldSmootherMatrix, NodalP_ones, RAPlist, labelstr);
462
463 // If there's an importer, we need to Rebalance the NewKn
464 if (!importer.is_null()) {
465 ParameterList rebAcParams;
466 rebAcParams.set("repartition: use subcommunicators", true);
467 rebAcParams.set("repartition: use subcommunicators in place", true);
468 auto newAfact = rcp(new RebalanceAcFactory());
469 newAfact->SetParameterList(rebAcParams);
470 RCP<const Map> InPlaceMap = NodeAggMatrix.is_null() ? Teuchos::null : NodeAggMatrix->getRowMap();
471
472 Level fLevel, cLevel;
473 cLevel.SetPreviousLevel(Teuchos::rcpFromRef(fLevel));
474 cLevel.Set("InPlaceMap", InPlaceMap);
475 cLevel.Set("A", NewKn);
476 cLevel.Request("A", newAfact.get());
477 newAfact->Build(fLevel, cLevel);
478
479 NewKn = cLevel.Get<RCP<Matrix> >("A", newAfact.get());
480 EdgeL->Set("NodeMatrix", NewKn);
481 } else {
482 EdgeL->Set("NodeMatrix", NewKn);
483 }
484
485 // Fix the old one
486 double thresh = parameterList_.get("maxwell1: nodal smoother fix zero diagonal threshold", 1e-10);
487 if (thresh > 0.0) {
488 GetOStream(Runtime0) << "Maxwell1::compute(): Fixing zero diagonal for nodal smoother matrix" << std::endl;
489 Scalar replacement = Teuchos::ScalarTraits<Scalar>::one();
490 Xpetra::MatrixUtils<SC, LO, GO, NO>::CheckRepairMainDiagonal(OldSmootherMatrix, true, GetOStream(Warnings1), thresh, replacement);
491 }
492 OldEdgeLevel->Set("NodeMatrix", OldSmootherMatrix);
493
494 OldSmootherMatrix = NewKn;
495 } else {
496 // The user didn't give us a Kn, so we aggregate and smooth with the same matrix
497 EdgeL->Set("NodeMatrix", NodeAggMatrix);
498 }
499 } else {
500 // We've partitioned things away.
501 EdgeL->Set("NodeMatrix", NodeAggOp);
502 EdgeL->Set("NodeAggMatrix", NodeAggOp);
503 }
504
505 OldEdgeLevel = EdgeL;
506 }
507
508 } // end Hierarchy22 loop
509
511 // Generating the (1,1) Hierarchy
512 std::string fine_smoother = precList11_.get<std::string>("smoother: type");
513 {
514 SM_Matrix_->setObjectLabel("A(1,1)");
515 precList11_.set("coarse: max size", 1);
516 precList11_.set("max levels", Hierarchy22_->GetNumLevels());
517
518 const bool refmaxwellCoarseSolve = (precList11_.get<std::string>("coarse: type",
519 MasterList::getDefault<std::string>("coarse: type")) == "RefMaxwell");
520 if (refmaxwellCoarseSolve) {
521 GetOStream(Runtime0) << "Maxwell1::compute(): Will set up RefMaxwell coarse solver" << std::endl;
522 precList11_.set("coarse: type", "none");
523 }
524
525 // Rip off non-serializable data before validation
526 Teuchos::ParameterList nonSerialList11, processedPrecList11;
527 MueLu::ExtractNonSerializableData(precList11_, processedPrecList11, nonSerialList11);
528 RCP<HierarchyManager<SC, LO, GO, NO> > mueLuFactory = rcp(new ParameterListInterpreter<SC, LO, GO, NO>(processedPrecList11, SM_Matrix_->getDomainMap()->getComm()));
529 Hierarchy11_->setlib(SM_Matrix_->getDomainMap()->lib());
530 Hierarchy11_->SetProcRankVerbose(SM_Matrix_->getDomainMap()->getComm()->getRank());
531
532 // Stick the non-serializible data on the hierarchy and do setup
533 if (nonSerialList11.numParams() > 0) {
534 HierarchyUtils<SC, LO, GO, NO>::AddNonSerializableDataToHierarchy(*mueLuFactory, *Hierarchy11_, nonSerialList11);
535 }
536 mueLuFactory->SetupHierarchy(*Hierarchy11_);
537
538 if (refmaxwellCoarseSolve) {
539 GetOStream(Runtime0) << "Maxwell1::compute(): Setting up RefMaxwell coarse solver" << std::endl;
540 auto coarseLvl = Hierarchy11_->GetLevel(Hierarchy11_->GetNumLevels() - 1);
541 auto coarseSolver = rcp(new MueLu::RefMaxwellSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>("RefMaxwell",
542 precList11_.sublist("coarse: params")));
543 coarseSolver->Setup(*coarseLvl);
544 coarseLvl->Set("PreSmoother",
545 rcp_dynamic_cast<SmootherBase>(coarseSolver, true));
546 }
547
548 if (mode_ == MODE_REFMAXWELL) {
549 if (Hierarchy11_->GetNumLevels() > 1) {
550 RCP<Level> EdgeL = Hierarchy11_->GetLevel(1);
551 P11_ = EdgeL->Get<RCP<Matrix> >("P");
552 }
553 }
554 }
555
557 // Allocate temporary MultiVectors for solve (only needed for RefMaxwell style)
558 allocateMemory(1);
559
560 describe(GetOStream(Runtime0));
561
562#ifdef MUELU_MAXWELL1_DEBUG
563 for (int i = 0; i < Hierarchy11_->GetNumLevels(); i++) {
564 RCP<Level> L = Hierarchy11_->GetLevel(i);
565 RCP<Matrix> EdgeMatrix = rcp_dynamic_cast<Matrix>(L->Get<RCP<Operator> >("A"));
566 RCP<Matrix> NodeMatrix = rcp_dynamic_cast<Matrix>(L->Get<RCP<Operator> >("NodeMatrix"));
567 RCP<Matrix> NodeAggMatrix = rcp_dynamic_cast<Matrix>(L->Get<RCP<Operator> >("NodeAggMatrix"));
568 RCP<Matrix> D0 = rcp_dynamic_cast<Matrix>(L->Get<RCP<Operator> >("D0"));
569
570 auto nrmE = EdgeMatrix->getFrobeniusNorm();
571 auto nrmN = NodeMatrix->getFrobeniusNorm();
572 auto nrmNa = NodeAggMatrix->getFrobeniusNorm();
573 auto nrmD0 = D0->getFrobeniusNorm();
574
575 std::cout << "DEBUG: Norms on Level " << i << " E/N/NA/D0 = " << nrmE << " / " << nrmN << " / " << nrmNa << " / " << nrmD0 << std::endl;
576 std::cout << "DEBUG: NNZ on Level " << i << " E/N/NA/D0 = " << EdgeMatrix->getGlobalNumEntries() << " / " << NodeMatrix->getGlobalNumEntries() << " / " << NodeAggMatrix->getGlobalNumEntries() << " / " << D0->getGlobalNumEntries() << std::endl;
577 }
578#endif
579}
580
581template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
582RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> > Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::generate_kn() const {
583 // This is important, as we'll be doing diagonal repair *after* the next-level matrix is generated, not before
584 Teuchos::ParameterList RAPlist;
585 RAPlist.set("rap: fix zero diagonals", false);
586
587 std::string labelstr = "NodeMatrix (Level 0)";
588 RCP<Matrix> rv = Maxwell_Utils<SC, LO, GO, NO>::PtAPWrapper(SM_Matrix_, D0_Matrix_, RAPlist, labelstr);
589 return rv;
590}
591
592template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
594 if (mode_ == MODE_REFMAXWELL) {
595 RCP<Teuchos::TimeMonitor> tmAlloc = getTimer("MueLu Maxwell1: Allocate MVs");
596
597 residualFine_ = MultiVectorFactory::Build(SM_Matrix_->getRangeMap(), numVectors);
598
599 if (!Hierarchy11_.is_null() && Hierarchy11_->GetNumLevels() > 1) {
600 RCP<Level> EdgeL = Hierarchy11_->GetLevel(1);
601 RCP<Matrix> A = EdgeL->Get<RCP<Matrix> >("A");
602 residual11c_ = MultiVectorFactory::Build(A->getRangeMap(), numVectors);
603 update11c_ = MultiVectorFactory::Build(A->getDomainMap(), numVectors);
604 }
605
606 if (!Hierarchy22_.is_null()) {
607 residual22_ = MultiVectorFactory::Build(D0_Matrix_->getDomainMap(), numVectors);
608 update22_ = MultiVectorFactory::Build(D0_Matrix_->getDomainMap(), numVectors);
609 }
610 }
611}
612
613template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
614void Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dump(const Matrix& A, std::string name) const {
615 if (dump_matrices_) {
616 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
617 Xpetra::IO<SC, LO, GO, NO>::Write(name, A);
618 }
619}
620
621template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
622void Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dump(const MultiVector& X, std::string name) const {
623 if (dump_matrices_) {
624 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
625 Xpetra::IO<SC, LO, GO, NO>::Write(name, X);
626 }
627}
628
629template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
631 if (dump_matrices_) {
632 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
633 Xpetra::IO<coordinateType, LO, GO, NO>::Write(name, X);
634 }
635}
636
637template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
638void Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dump(const Teuchos::ArrayRCP<bool>& v, std::string name) const {
639 if (dump_matrices_) {
640 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
641 std::ofstream out(name);
642 for (size_t i = 0; i < Teuchos::as<size_t>(v.size()); i++)
643 out << v[i] << "\n";
644 }
645}
646
647template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
648void Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dump(const Kokkos::View<bool*, typename Node::device_type>& v, std::string name) const {
649 if (dump_matrices_) {
650 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
651 std::ofstream out(name);
652 auto vH = Kokkos::create_mirror_view(v);
653 Kokkos::deep_copy(vH, v);
654 for (size_t i = 0; i < vH.size(); i++)
655 out << vH[i] << "\n";
656 }
657}
658
659template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
660Teuchos::RCP<Teuchos::TimeMonitor> Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getTimer(std::string name, RCP<const Teuchos::Comm<int> > comm) const {
661 if (IsPrint(Timings)) {
662 if (!syncTimers_)
663 return Teuchos::rcp(new Teuchos::TimeMonitor(*Teuchos::TimeMonitor::getNewTimer(name)));
664 else {
665 if (comm.is_null())
666 return Teuchos::rcp(new Teuchos::SyncTimeMonitor(*Teuchos::TimeMonitor::getNewTimer(name), SM_Matrix_->getRowMap()->getComm().ptr()));
667 else
668 return Teuchos::rcp(new Teuchos::SyncTimeMonitor(*Teuchos::TimeMonitor::getNewTimer(name), comm.ptr()));
669 }
670 } else
671 return Teuchos::null;
672}
673
674template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
675void Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::resetMatrix(RCP<Matrix> SM_Matrix_new, bool ComputePrec) {
676 bool reuse = !SM_Matrix_.is_null();
677 SM_Matrix_ = SM_Matrix_new;
678 dump(*SM_Matrix_, "SM.m");
679 if (ComputePrec)
680 compute(reuse);
681}
682
683template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
685 // make sure that we have enough temporary memory
686 const SC one = Teuchos::ScalarTraits<SC>::one();
687 if (!allEdgesBoundary_ && X.getNumVectors() != residualFine_->getNumVectors())
688 allocateMemory(X.getNumVectors());
689
690 TEUCHOS_TEST_FOR_EXCEPTION(Hierarchy11_.is_null() || Hierarchy11_->GetNumLevels() == 0, Exceptions::RuntimeError, "(1,1) Hiearchy is null.");
691
692 // 1) Run fine pre-smoother using Hierarchy11
693 RCP<Level> Fine = Hierarchy11_->GetLevel(0);
694 if (Fine->IsAvailable("PreSmoother")) {
695 RCP<Teuchos::TimeMonitor> tmRes = getTimer("MueLu Maxwell1: PreSmoother");
696 RCP<SmootherBase> preSmoo = Fine->Get<RCP<SmootherBase> >("PreSmoother");
697 preSmoo->Apply(X, RHS, true);
698 }
699
700 // 2) Compute residual
701 {
702 RCP<Teuchos::TimeMonitor> tmRes = getTimer("MueLu Maxwell1: residual calculation");
703 Utilities::Residual(*SM_Matrix_, X, RHS, *residualFine_);
704 }
705
706 // 3a) Restrict residual to (1,1) Hierarchy's level 1 and execute (1,1) hierarchy (use startLevel and InitialGuessIsZero)
707 if (!P11_.is_null()) {
708 RCP<Teuchos::TimeMonitor> tmRes = getTimer("MueLu Maxwell1: (1,1) correction");
709 P11_->apply(*residualFine_, *residual11c_, Teuchos::TRANS);
710 Hierarchy11_->Iterate(*residual11c_, *update11c_, true, 1);
711 }
712
713 // 3b) Restrict residual to (2,2) Hierarchy's level 0 and execute (2,2) hierarchy (use InitialGuessIsZero)
714 if (!allNodesBoundary_) {
715 RCP<Teuchos::TimeMonitor> tmRes = getTimer("MueLu Maxwell1: (2,2) correction");
716 D0_Matrix_->apply(*residualFine_, *residual22_, Teuchos::TRANS);
717 Hierarchy22_->Iterate(*residual22_, *update22_, true, 0);
718 }
719
720 // 4) Prolong both updates back into X-vector (Need to do both the P11 null and not null cases
721 {
722 RCP<Teuchos::TimeMonitor> tmRes = getTimer("MueLu Maxwell1: Orolongation");
723 if (!P11_.is_null())
724 P11_->apply(*update11c_, X, Teuchos::NO_TRANS, one, one);
725 if (!allNodesBoundary_)
726 D0_Matrix_->apply(*update22_, X, Teuchos::NO_TRANS, one, one);
727 }
728
729 // 5) Run fine post-smoother using Hierarchy11
730 if (Fine->IsAvailable("PostSmoother")) {
731 RCP<Teuchos::TimeMonitor> tmRes = getTimer("MueLu Maxwell1: PostSmoother");
732 RCP<SmootherBase> postSmoo = Fine->Get<RCP<SmootherBase> >("PostSmoother");
733 postSmoo->Apply(X, RHS, false);
734 }
735}
736
737template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
738void Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::applyInverseStandard(const MultiVector& RHS, MultiVector& X) const {
739 Hierarchy11_->Iterate(RHS, X, 1, true);
740}
741
742template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
743void Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::apply(const MultiVector& RHS, MultiVector& X,
744 Teuchos::ETransp /* mode */,
745 Scalar /* alpha */,
746 Scalar /* beta */) const {
747 RCP<Teuchos::TimeMonitor> tm = getTimer("MueLu Maxwell1: solve");
748 if (mode_ == MODE_GMHD_STANDARD)
749 HierarchyGmhd_->Iterate(RHS, X, 1, true);
750 else if (mode_ == MODE_STANDARD || mode_ == MODE_EDGE_ONLY)
751 applyInverseStandard(RHS, X);
752 else if (mode_ == MODE_REFMAXWELL)
753 applyInverseRefMaxwellAdditive(RHS, X);
754 else
755 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "Must use mode 'standard', 'refmaxwell' or 'edge only' when not doing GMHD.");
756}
757
758template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
762
763template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
764void scaleD0(Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& D0) {
765 // We assume that D0 has entries +-1.
766 // Construction D0 via interpolation can instead give +-0.5
767 // Let's check and scale D0.
768
769 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
770 using Matrix = Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
771 using impl_scalar_type = typename Matrix::impl_scalar_type;
772 using impl_ATS = KokkosKernels::ArithTraits<impl_scalar_type>;
773 using magnitude_type = typename impl_ATS::magnitudeType;
774 using MinMax = Kokkos::MinMax<magnitude_type>;
775
776 typename MinMax::value_type result;
777 {
778 auto lclD0 = D0.getLocalMatrixDevice();
779 Kokkos::parallel_reduce(
780 "MueLu::Maxwell1::D0_fixup",
781 range_type(0, lclD0.nnz()),
782 KOKKOS_LAMBDA(const LocalOrdinal k, typename MinMax::value_type& res) {
783 auto val = impl_ATS::magnitude(lclD0.values(k));
784 res.min_val = Kokkos::min(res.min_val, val);
785 res.max_val = Kokkos::max(res.max_val, val);
786 },
787 MinMax(result));
788 }
789
790 TEUCHOS_ASSERT_EQUALITY(result.min_val, result.max_val);
791
792 if (impl_ATS::magnitude(result.max_val - impl_ATS::one()) > impl_ATS::eps()) {
793 Scalar scaling = impl_ATS::one() / result.max_val;
794 D0.scale(scaling);
795 }
796}
797
798template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
800 initialize(const Teuchos::RCP<Matrix>& D0_Matrix,
801 const Teuchos::RCP<Matrix>& Kn_Matrix,
802 const Teuchos::RCP<MultiVector>& Nullspace,
803 const Teuchos::RCP<RealValuedMultiVector>& Coords,
804 const Teuchos::RCP<MultiVector>& Material,
805 Teuchos::ParameterList& List) {
806 // some pre-conditions
807 TEUCHOS_ASSERT(D0_Matrix != Teuchos::null);
808
809#ifdef HAVE_MUELU_DEBUG
810 if (!Kn_Matrix.is_null()) {
811 TEUCHOS_ASSERT(Kn_Matrix->getDomainMap()->isSameAs(*D0_Matrix->getDomainMap()));
812 TEUCHOS_ASSERT(Kn_Matrix->getRangeMap()->isSameAs(*D0_Matrix->getDomainMap()));
813 }
814
815 TEUCHOS_ASSERT(D0_Matrix->getRangeMap()->isSameAs(*D0_Matrix->getRowMap()));
816#endif
817
818 Hierarchy11_ = Teuchos::null;
819 Hierarchy22_ = Teuchos::null;
820 HierarchyGmhd_ = Teuchos::null;
821 if (mode_ != MODE_GMHD_STANDARD) mode_ = MODE_STANDARD;
822
823 // Default settings
824 useKokkos_ = false;
825 allEdgesBoundary_ = false;
826 allNodesBoundary_ = false;
827 dump_matrices_ = false;
828 check_D0_scaling_ = false;
829 enable_reuse_ = false;
830 syncTimers_ = false;
831 applyBCsTo22_ = false;
832
833 // set parameters
834 setParameters(List);
835
836 if (D0_Matrix->getRowMap()->lib() == Xpetra::UseTpetra) {
837 // We will remove boundary conditions from D0, and potentially change maps, so we copy the input.
838 // Fortunately, D0 is quite sparse.
839 // We cannot use the Tpetra copy constructor, since it does not copy the graph.
840
841 RCP<Matrix> D0copy = MatrixFactory::Build(D0_Matrix->getRowMap(), D0_Matrix->getColMap(), 0);
842 RCP<CrsMatrix> D0copyCrs = toCrsMatrix(D0copy);
843 ArrayRCP<const size_t> D0rowptr_RCP;
844 ArrayRCP<const LO> D0colind_RCP;
845 ArrayRCP<const SC> D0vals_RCP;
846 toCrsMatrix(D0_Matrix)->getAllValues(D0rowptr_RCP, D0colind_RCP, D0vals_RCP);
847
848 ArrayRCP<size_t> D0copyrowptr_RCP;
849 ArrayRCP<LO> D0copycolind_RCP;
850 ArrayRCP<SC> D0copyvals_RCP;
851 D0copyCrs->allocateAllValues(D0vals_RCP.size(), D0copyrowptr_RCP, D0copycolind_RCP, D0copyvals_RCP);
852 D0copyrowptr_RCP.deepCopy(D0rowptr_RCP());
853 D0copycolind_RCP.deepCopy(D0colind_RCP());
854 D0copyvals_RCP.deepCopy(D0vals_RCP());
855 D0copyCrs->setAllValues(D0copyrowptr_RCP,
856 D0copycolind_RCP,
857 D0copyvals_RCP);
858 D0copyCrs->expertStaticFillComplete(D0_Matrix->getDomainMap(), D0_Matrix->getRangeMap(),
859 toCrsMatrix(D0_Matrix)->getCrsGraph()->getImporter(),
860 toCrsMatrix(D0_Matrix)->getCrsGraph()->getExporter());
861 D0_Matrix_ = D0copy;
862 } else
863 D0_Matrix_ = MatrixFactory::BuildCopy(D0_Matrix);
864
865 if (check_D0_scaling_)
866 scaleD0(*D0_Matrix_);
867
868 Kn_Matrix_ = Kn_Matrix;
869 Coords_ = Coords;
870 Material_ = Material;
871 Nullspace_ = Nullspace;
872
873 if (!Kn_Matrix_.is_null()) dump(*Kn_Matrix_, "Kn.m");
874 if (!Nullspace_.is_null()) dump(*Nullspace_, "nullspace.m");
875 if (!Coords_.is_null()) dumpCoords(*Coords_, "coords.m");
876}
877
878template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
880 describe(Teuchos::FancyOStream& out, const Teuchos::EVerbosityLevel /* verbLevel */) const {
881 std::ostringstream oss;
882
883 RCP<const Teuchos::Comm<int> > comm = SM_Matrix_->getDomainMap()->getComm();
884
885#ifdef HAVE_MPI
886 int root;
887 if (!Kn_Matrix_.is_null())
888 root = comm->getRank();
889 else
890 root = -1;
891
892 int actualRoot;
893 reduceAll(*comm, Teuchos::REDUCE_MAX, root, Teuchos::ptr(&actualRoot));
894 root = actualRoot;
895#endif
896
897 oss << "\n--------------------------------------------------------------------------------\n"
898 << "--- Maxwell1 Summary ---\n"
899 "--------------------------------------------------------------------------------"
900 << std::endl;
901 oss << std::endl;
902
903 GlobalOrdinal numRows;
904 GlobalOrdinal nnz;
905
906 SM_Matrix_->getRowMap()->getComm()->barrier();
907
908 numRows = SM_Matrix_->getGlobalNumRows();
909 nnz = SM_Matrix_->getGlobalNumEntries();
910
911 Xpetra::global_size_t tt = numRows;
912 int rowspacer = 3;
913 while (tt != 0) {
914 tt /= 10;
915 rowspacer++;
916 }
917 tt = nnz;
918 int nnzspacer = 2;
919 while (tt != 0) {
920 tt /= 10;
921 nnzspacer++;
922 }
923
924 oss << "block " << std::setw(rowspacer) << " rows " << std::setw(nnzspacer) << " nnz " << std::setw(9) << " nnz/row" << std::endl;
925 oss << "(1, 1)" << std::setw(rowspacer) << numRows << std::setw(nnzspacer) << nnz << std::setw(9) << as<double>(nnz) / numRows << std::endl;
926
927 if (!Kn_Matrix_.is_null()) {
928 // ToDo: make sure that this is printed correctly
929 numRows = Kn_Matrix_->getGlobalNumRows();
930 nnz = Kn_Matrix_->getGlobalNumEntries();
931
932 oss << "(2, 2)" << std::setw(rowspacer) << numRows << std::setw(nnzspacer) << nnz << std::setw(9) << as<double>(nnz) / numRows << std::endl;
933 }
934
935 oss << std::endl;
936
937 std::string outstr = oss.str();
938
939#ifdef HAVE_MPI
940 RCP<const Teuchos::MpiComm<int> > mpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(comm);
941 MPI_Comm rawComm = (*mpiComm->getRawMpiComm())();
942
943 int strLength = outstr.size();
944 MPI_Bcast(&strLength, 1, MPI_INT, root, rawComm);
945 if (comm->getRank() != root)
946 outstr.resize(strLength);
947 MPI_Bcast(&outstr[0], strLength, MPI_CHAR, root, rawComm);
948#endif
949
950 out << outstr;
951
952 if (!Hierarchy11_.is_null())
953 Hierarchy11_->describe(out, GetVerbLevel());
954
955 if (!Hierarchy22_.is_null())
956 Hierarchy22_->describe(out, GetVerbLevel());
957
958 if (!HierarchyGmhd_.is_null())
959 HierarchyGmhd_->describe(out, GetVerbLevel());
960
961 if (IsPrint(Statistics2)) {
962 // Print the grid of processors
963 std::ostringstream oss2;
964
965 oss2 << "Sub-solver distribution over ranks" << std::endl;
966 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;
967
968 int numProcs = comm->getSize();
969#ifdef HAVE_MPI
970 RCP<const Teuchos::MpiComm<int> > tmpic = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(comm);
971
972 RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > rawMpiComm = tmpic->getRawMpiComm();
973#endif
974
975 char status = 0;
976 if (!Kn_Matrix_.is_null())
977 status += 1;
978 std::vector<char> states(numProcs, 0);
979#ifdef HAVE_MPI
980 MPI_Gather(&status, 1, MPI_CHAR, &states[0], 1, MPI_CHAR, 0, *rawMpiComm);
981#else
982 states.push_back(status);
983#endif
984
985 int rowWidth = std::min(Teuchos::as<int>(ceil(sqrt(numProcs))), 100);
986 for (int proc = 0; proc < numProcs; proc += rowWidth) {
987 for (int j = 0; j < rowWidth; j++)
988 if (proc + j < numProcs)
989 if (states[proc + j] == 0)
990 oss2 << ".";
991 else if (states[proc + j] == 1)
992 oss2 << "1";
993 else if (states[proc + j] == 2)
994 oss2 << "2";
995 else
996 oss2 << "B";
997 else
998 oss2 << " ";
999
1000 oss2 << " " << proc << ":" << std::min(proc + rowWidth, numProcs) - 1 << std::endl;
1001 }
1002 oss2 << std::endl;
1003 GetOStream(Statistics2) << oss2.str();
1004 }
1005}
1006
1007} // namespace MueLu
1008
1009#define MUELU_MAXWELL1_SHORT
1010#endif // ifdef MUELU_MAXWELL1_DEF_HPP
Various adapters that will create a MueLu preconditioner that is an Xpetra::Matrix.
MueLu::DefaultLocalOrdinal LocalOrdinal
MueLu::DefaultScalar Scalar
MueLu::DefaultGlobalOrdinal GlobalOrdinal
Exception throws to report errors in the internal logical of the program.
Provides methods to build a multigrid hierarchy and apply multigrid cycles.
static void AddNonSerializableDataToHierarchy(HierarchyManager &HM, Hierarchy &H, const ParameterList &nonSerialList)
Add non-serializable data to Hierarchy.
static void CopyBetweenHierarchies(Hierarchy &fromHierarchy, Hierarchy &toHierarchy, const std::string fromLabel, const std::string toLabel, const std::string dataType)
Class that holds all level-specific information.
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)
static std::string translate(Teuchos::ParameterList &paramList, const std::string &defaultVals="")
: Translate ML parameters to MueLu parameter XML string
const Teuchos::RCP< const Map > getDomainMap() const
Returns the Xpetra::Map object associated with the domain of this operator.
Teuchos::RCP< Matrix > generate_kn() const
Generates the Kn matrix.
typename Teuchos::ScalarTraits< Scalar >::magnitudeType magnitudeType
void compute(bool reuse=false)
Setup the preconditioner.
void GMHDSetupHierarchy(Teuchos::ParameterList &List) const
Sets up hiearchy for GMHD matrices that include generalized Ohms law equations.
void initialize(const Teuchos::RCP< Matrix > &D0_Matrix, const Teuchos::RCP< Matrix > &Kn_Matrix, const Teuchos::RCP< MultiVector > &Nullspace, const Teuchos::RCP< RealValuedMultiVector > &Coords, const Teuchos::RCP< MultiVector > &Material, Teuchos::ParameterList &List)
const Teuchos::RCP< const Map > getRangeMap() const
Returns the Xpetra::Map object associated with the range of this operator.
void applyInverseRefMaxwellAdditive(const MultiVector &RHS, MultiVector &X) const
apply RefMaxwell additive 2x2 style cycle
void applyInverseStandard(const MultiVector &RHS, MultiVector &X) const
apply standard Maxwell1 cycle
void dumpCoords(const RealValuedMultiVector &X, std::string name) const
dump out real-valued multivector
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::VERB_HIGH) const
void dump(const Matrix &A, std::string name) const
dump out matrix
typename Xpetra::MultiVector< coordinateType, LO, GO, NO > RealValuedMultiVector
void resetMatrix(Teuchos::RCP< Matrix > SM_Matrix_new, bool ComputePrec=true)
Reset system matrix.
bool hasTransposeApply() const
Indicates whether this operator supports applying the adjoint operator.
Teuchos::RCP< Teuchos::TimeMonitor > getTimer(std::string name, RCP< const Teuchos::Comm< int > > comm=Teuchos::null) const
get a (synced) timer
void setParameters(Teuchos::ParameterList &list)
Set parameters.
void apply(const MultiVector &X, MultiVector &Y, Teuchos::ETransp mode=Teuchos::NO_TRANS, Scalar alpha=Teuchos::ScalarTraits< Scalar >::one(), Scalar beta=Teuchos::ScalarTraits< Scalar >::zero()) const
void allocateMemory(int numVectors) const
allocate multivectors for solve
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 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.
Factory for building coarse matrices.
Class that encapsulates Operator 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 RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > ReplaceNonZerosWithOnes(const RCP< Matrix > &original)
Creates a copy of a matrix where the non-zero entries are replaced by ones.
static RCP< MultiVector > Residual(const Xpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, const MultiVector &X, const MultiVector &RHS)
static void SetDefaultVerbLevel(const VerbLevel defaultVerbLevel)
Set the default (global) verbosity level.
Namespace for MueLu classes and methods.
long ExtractNonSerializableData(const Teuchos::ParameterList &inList, Teuchos::ParameterList &serialList, Teuchos::ParameterList &nonSerialList)
Extract non-serializable data from level-specific sublists and move it to a separate parameter list.
@ Warnings0
Important warning messages (one line)
@ Statistics2
Print even more statistics.
@ Runtime0
One-liner description of what is happening.
@ Warnings1
Additional warnings.
@ Timings
Print all timing information.
MsgType toVerbLevel(const std::string &verbLevelStr)
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,...
void scaleD0(Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &D0)
static std::string getColonLabel(const std::string &label)
Helper function for object label.