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_RebalanceTransferFactory.hpp"
33#include "MueLu_Monitor.hpp"
34#include "MueLu_PerfUtils.hpp"
35#include "MueLu_ParameterListInterpreter.hpp"
36#include "MueLu_HierarchyManager.hpp"
37#include <MueLu_HierarchyUtils.hpp>
41#include <MueLu_RefMaxwellSmoother.hpp>
42#include "MueLu_Behavior.hpp"
43
44#ifdef HAVE_MUELU_CUDA
45#include "cuda_profiler_api.h"
46#endif
47
48namespace MueLu {
49
50template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
51const Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getDomainMap() const {
52 return SM_Matrix_->getDomainMap();
53}
54
55template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
56const Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getRangeMap() const {
57 return SM_Matrix_->getRangeMap();
58}
59
60template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
62 if (list.isType<std::string>("parameterlist: syntax") && list.get<std::string>("parameterlist: syntax") == "ml") {
63 list = *MueLu::ML2MueLuParameterTranslator::translate(list, "Maxwell");
64 }
65
66 std::string mode_string = list.get("maxwell1: mode", MasterList::getDefault<std::string>("maxwell1: mode"));
67 applyBCsTo22_ = list.get("maxwell1: apply BCs to 22", false);
68 dump_matrices_ = list.get("maxwell1: dump matrices", MasterList::getDefault<bool>("maxwell1: dump matrices"));
69 check_D0_scaling_ = list.get("maxwell1: check and fix D0 scaling", MasterList::getDefault<bool>("maxwell1: check and fix D0 scaling"));
70
71 // Default smoother. We'll copy this around.
72 Teuchos::ParameterList defaultSmootherList;
73 defaultSmootherList.set("smoother: type", "CHEBYSHEV");
74 defaultSmootherList.sublist("smoother: params").set("chebyshev: degree", 2);
75 defaultSmootherList.sublist("smoother: params").set("chebyshev: ratio eigenvalue", 7.0);
76 defaultSmootherList.sublist("smoother: params").set("chebyshev: eigenvalue max iterations", 30);
77
78 // Make sure verbosity gets passed to the sublists
79 std::string verbosity = list.get("verbosity", "high");
81
82 // Check the validity of the run mode
84 if (mode_string == "standard")
86 else if (mode_string == "refmaxwell")
88 else if (mode_string == "edge only")
90 else {
91 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "Must use mode 'standard', 'refmaxwell', 'edge only', or use the GMHD constructor.");
92 }
93 }
94
95 // If we're in edge only or standard modes, then the (2,2) hierarchy gets built without smoothers.
96 // Otherwise we use the user's smoothers (defaulting to Chebyshev if unspecified)
97 if (list.isSublist("maxwell1: 22list"))
98 precList22_ = list.sublist("maxwell1: 22list");
99 else if (list.isSublist("refmaxwell: 22list"))
100 precList22_ = list.sublist("refmaxwell: 22list");
102 precList22_.set("smoother: pre or post", "none");
103 else if (!precList22_.isType<std::string>("Preconditioner Type") &&
104 !precList22_.isType<std::string>("smoother: type") &&
105 !precList22_.isType<std::string>("smoother: pre type") &&
106 !precList22_.isType<std::string>("smoother: post type")) {
107 precList22_ = defaultSmootherList;
108 }
109 precList22_.set("verbosity", precList22_.get("verbosity", verbosity));
110
111 // For the (1,1) hierarchy we'll use Hiptmair (STANDARD) or Chebyshev (EDGE_ONLY / REFMAXWELL) if
112 // the user doesn't specify things
113 if (list.isSublist("maxwell1: 11list"))
114 precList11_ = list.sublist("maxwell1: 11list");
115 else if (list.isSublist("refmaxwell: 11list"))
116 precList11_ = list.sublist("refmaxwell: 11list");
117
118 if (mode_ == MODE_GMHD_STANDARD) {
119 precList11_.set("smoother: pre or post", "none");
120 precList11_.set("smoother: type", "none");
121 }
122 if (!precList11_.isType<std::string>("Preconditioner Type") &&
123 !precList11_.isType<std::string>("smoother: type") &&
124 !precList11_.isType<std::string>("smoother: pre type") &&
125 !precList11_.isType<std::string>("smoother: post type")) {
127 precList11_ = defaultSmootherList;
128 }
129 if (mode_ == MODE_STANDARD) {
130 precList11_.set("smoother: type", "HIPTMAIR");
131 precList11_.set("hiptmair: smoother type 1", "CHEBYSHEV");
132 precList11_.set("hiptmair: smoother type 2", "CHEBYSHEV");
133 precList11_.sublist("hiptmair: smoother list 1") = defaultSmootherList;
134 precList11_.sublist("hiptmair: smoother list 2") = defaultSmootherList;
135 }
136 }
137 precList11_.set("verbosity", precList11_.get("verbosity", verbosity));
138
139 // Reuse support
140 if (enable_reuse_ &&
141 !precList11_.isType<std::string>("Preconditioner Type") &&
142 !precList11_.isParameter("reuse: type"))
143 precList11_.set("reuse: type", "full");
144 if (enable_reuse_ &&
145 !precList22_.isType<std::string>("Preconditioner Type") &&
146 !precList22_.isParameter("reuse: type"))
147 precList22_.set("reuse: type", "full");
148
149 // Are we using Kokkos?
150 useKokkos_ = !Node::is_serial;
151 useKokkos_ = list.get("use kokkos refactor", useKokkos_);
152
153 parameterList_ = list;
154}
155
156template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
158 Teuchos::ParameterList precListGmhd;
159
161
162 HierarchyGmhd_->GetLevel(0)->Set("A", GmhdA_Matrix_);
163 GmhdA_Matrix_->setObjectLabel("GmhdA");
164
165 TEUCHOS_TEST_FOR_EXCEPTION(!List.isSublist("maxwell1: Gmhdlist"), Exceptions::RuntimeError, "Must provide maxwell1: Gmhdlist for GMHD setup");
166 precListGmhd = List.sublist("maxwell1: Gmhdlist");
167 precListGmhd.set("coarse: max size", 1);
168 precListGmhd.set("max levels", HierarchyGmhd_->GetNumLevels());
169 RCP<MueLu::HierarchyManager<SC, LO, GO, NO>> mueLuFactory = rcp(new MueLu::ParameterListInterpreter<SC, LO, GO, NO>(precListGmhd, GmhdA_Matrix_->getDomainMap()->getComm()));
170 HierarchyGmhd_->setlib(GmhdA_Matrix_->getDomainMap()->lib());
171 HierarchyGmhd_->SetProcRankVerbose(GmhdA_Matrix_->getDomainMap()->getComm()->getRank());
172 mueLuFactory->SetupHierarchy(*HierarchyGmhd_);
173}
174
175template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
177 /* Algorithm overview for Maxwell1 construction:
178
179 1) Create a nodal auxiliary hierarchy based on (a) the user's nodal matrix or (b) a matrix constructed
180 by D0^T A D0 if the user doesn't provide a nodal matrix. We call this matrix "NodeAggMatrix."
181
182 2) If the user provided a node matrix, we use the prolongators from the auxiliary nodal hierarchy
183 to generate matrices for smoothers on all levels. We call this "NodeMatrix." Otherwise NodeMatrix = NodeAggMatrix
184
185 3) We stick all of the nodal P matrices and NodeMatrix objects on the final (1,1) hierarchy and then use the
186 ReitzingerPFactory to generate the edge P and A matrices.
187 */
188
189#ifdef HAVE_MUELU_CUDA
190 if (parameterList_.get<bool>("maxwell1: cuda profile setup", false)) cudaProfilerStart();
191#endif
192
193 std::string timerLabel;
194 if (reuse)
195 timerLabel = "MueLu Maxwell1: compute (reuse)";
196 else
197 timerLabel = "MueLu Maxwell1: compute";
198 RCP<Teuchos::TimeMonitor> tmCompute = getTimer(timerLabel);
199
201 // Generate Kn and apply BCs (if needed)
202 bool have_generated_Kn = false;
203 if (Kn_Matrix_.is_null()) {
204 // generate_kn() will do diagonal repair if requested
205 GetOStream(Runtime0) << "Maxwell1::compute(): Kn not provided. Generating." << std::endl;
207 have_generated_Kn = true;
208 } else if (parameterList_.get<bool>("rap: fix zero diagonals", true)) {
209 magnitudeType threshold;
210 if (parameterList_.isType<magnitudeType>("rap: fix zero diagonals threshold"))
211 threshold = parameterList_.get<magnitudeType>("rap: fix zero diagonals threshold",
212 Teuchos::ScalarTraits<double>::eps());
213 else
214 threshold = Teuchos::as<magnitudeType>(parameterList_.get<double>("rap: fix zero diagonals threshold",
215 Teuchos::ScalarTraits<double>::eps()));
216 Scalar replacement = Teuchos::as<Scalar>(parameterList_.get<double>("rap: fix zero diagonals replacement",
217 MasterList::getDefault<double>("rap: fix zero diagonals replacement")));
218 Xpetra::MatrixUtils<SC, LO, GO, NO>::CheckRepairMainDiagonal(Kn_Matrix_, true, GetOStream(Warnings1), threshold, replacement);
219 }
220
222 // Generate the (2,2) Hierarchy
223 Kn_Matrix_->setObjectLabel("Maxwell1 (2,2)");
224
225 /* Critical ParameterList changes */
226 if (!Coords_.is_null())
227 precList22_.sublist("user data").set("Coordinates", Coords_);
228 if (!Material_.is_null())
229 precList22_.sublist("user data").set("Material", Material_);
230
231 if (mode_ == MODE_STANDARD) {
232 /* We do not need to set up any smoothers or coarse solver for the (2,2) hierarchy. */
233 if (!precList22_.isParameter("smoother: type") && !precList22_.isParameter("smoother: pre type") && !precList22_.isParameter("smoother: post type")) {
234 precList22_.set("smoother: type", "none");
235 }
236 if (!precList22_.isParameter("coarse: type")) {
237 precList22_.set("coarse: type", "none");
238 }
239 }
240
241 auto algo11 = precList11_.get<std::string>("multigrid algorithm");
242 auto algo22 = precList22_.get<std::string>("multigrid algorithm");
243
244 // | algo22 | algo11 | allowed | comment |
245 // |------------|-----------------------|---------|-------------------------------------------|
246 // | unsmoothed | unsmoothed reitzinger | yes | classical unsmoothed RS |
247 // | unsmoothed | smoothed reitzinger | yes | smoothed RS with edge-only smoothing |
248 // | unsmoothed | emin reitzinger | yes | emin RS with unsmoothed nodal prolongator |
249 // | sa | unsmoothed reitzinger | no | |
250 // | sa | smoothed reitzinger | yes | smoothed RS with edge and nodal smoothing |
251 // | sa | emin reitzinger | yes | emin RS with SA nodal prolongator |
252 // | emin | unsmoothed reitzinger | no | |
253 // | emin | smoothed reitzinger | no | |
254 // | emin | emin reitzinger | yes | emin RS with emin nodal prolongator |
255
256 if (algo11 == "unsmoothed reitzinger") {
257 TEUCHOS_ASSERT(algo22 == "unsmoothed");
258 } else if (algo11 == "smoothed reitzinger") {
259 TEUCHOS_ASSERT((algo22 == "unsmoothed") || (algo22 == "sa"));
260 }
261
262 if (algo22 == "sa") {
263 // Nodal prolongators are smoothed. Make the damping factor available in the edge list.
264 double nodalDamping;
265 if (precList22_.isType<double>("sa: damping factor")) {
266 nodalDamping = precList22_.get<double>("sa: damping factor");
267 } else {
268 nodalDamping = MasterList::getDefault<double>("sa: damping factor");
269 }
270 precList11_.set("sa: nodal damping factor", nodalDamping);
271 } else if (algo22 == "unsmoothed")
272 precList11_.set("sa: nodal damping factor", 0.0);
273
274 if (algo11 == "smoothed reitzinger") {
275 precList11_.set("sa: use filtered matrix", false);
276 precList22_.set("sa: use filtered matrix", false);
277 bool useEdgeMatrixForSmoothing = MasterList::getDefault<bool>("sa: use edge matrix for smoothing");
278 if (precList11_.isType<bool>("sa: use edge matrix for smoothing"))
279 useEdgeMatrixForSmoothing = precList11_.get<bool>("sa: use edge matrix for smoothing");
280 if (!precList11_.sublist("user data").isParameter("CurlCurl")) {
281 if (precList11_.isType<double>("sa: damping factor")) {
282 double edgeDamping = precList11_.get<double>("sa: damping factor");
283 if (edgeDamping != 0) {
284 if (!useEdgeMatrixForSmoothing) {
285 GetOStream(Warnings0) << "\"sa: damping factor\" in \"maxwell1: 11list\" is set to " << std::to_string(edgeDamping) << ", but no CurlCurl matrix has been passed in \"user data\". Switching off edge-only damping. Set \"sa: use edge matrix for smoothing\" = true in the \"maxwell1: 11list\" to use the edge matrix." << std::endl;
286 precList11_.set("sa: damping factor", 0.);
287 } else
288 GetOStream(Warnings0) << "\"sa: damping factor\" in \"maxwell1: 11list\" is set to " << std::to_string(edgeDamping) << ". Using the edge matrix for smoothing and violating the commuting relationship." << std::endl;
289 }
290 } else {
291 if (!useEdgeMatrixForSmoothing) {
292 GetOStream(Warnings0) << "\"sa: damping factor\" in \"maxwell1: 11list\" is nonzero by default, but no CurlCurl matrix has been passed in \"user data\". Switching off edge-only damping." << std::endl;
293 precList11_.set("sa: damping factor", 0.);
294 } else
295 GetOStream(Warnings0) << "\"sa: damping factor\" in \"maxwell1: 11list\" is nonzero by default. Using the edge matrix for smoothing and violating the commuting relationship." << std::endl;
296 }
297 }
298 }
299
300 if (!precList22_.isParameter("tentative: constant column sums"))
301 precList22_.set("tentative: constant column sums", false);
302 else if (precList22_.get<bool>("tentative: constant column sums") != false)
303 GetOStream(Warnings0) << "\"tentative: constant column sums\" is set to \"true\". There is no guarantee that this will work." << std::endl;
304
305 if (!precList22_.isParameter("tentative: calculate qr"))
306 precList22_.set("tentative: calculate qr", false);
307 else if (precList22_.get<bool>("tentative: calculate qr") != false)
308 GetOStream(Warnings0) << "\"tentative: calculate qr\" is set to \"true\". There is no guarantee that this will work." << std::endl;
309
310 /* We need both nodal Ptent and P for Emin. */
311 if (((parameterList_.sublist("maxwell1: 11list").template get<std::string>("multigrid algorithm") == "smoothed reitzinger") || (parameterList_.sublist("maxwell1: 11list").template get<std::string>("multigrid algorithm") == "emin reitzinger")) &&
312 (!precList22_.isParameter("sa: keep tentative prolongator") || !precList22_.get<bool>("sa: keep tentative prolongator")))
313 precList22_.set("sa: keep tentative prolongator", true);
314
315 /* Repartitioning *must* be in sync between hierarchies, which means
316 that we need to keep the importers in sync too */
317 if (precList22_.isParameter("repartition: enable")) {
318 bool repartition = precList22_.get<bool>("repartition: enable");
319 precList11_.set("repartition: enable", repartition);
320
321 // If we're repartitioning (2,2), we need to rebalance for (1,1) to do the right thing,
322 // as well as keep the importers
323 if (repartition) {
324 if (!precList22_.isParameter("repartition: save importer"))
325 precList22_.set("repartition: save importer", true);
326 else if (!precList22_.get<bool>("repartition: save importer")) {
327 GetOStream(Warnings0) << "\"repartition: save importer\" is set to false, but it is required to be true. Changing it." << std::endl;
328 precList22_.set("repartition: save importer", true);
329 }
330
331 if (!precList22_.isParameter("repartition: rebalance P and R"))
332 precList22_.set("repartition: rebalance P and R", true);
333 else if (!precList22_.get<bool>("repartition: rebalance P and R")) {
334 GetOStream(Warnings0) << "\"repartition: rebalance P and R\" is set to false, but it is required to be true. Changing it." << std::endl;
335 precList22_.set("repartition: rebalance P and R", true);
336 }
337
338 if (!precList22_.isParameter("repartition: use subcommunicators"))
339 precList22_.set("repartition: use subcommunicators", true);
340 else if (!precList22_.get<bool>("repartition: use subcommunicators")) {
341 GetOStream(Warnings0) << "\"repartition: use subcommunicators\" is set to false, but it is required to be true. Changing it." << std::endl;
342 precList22_.set("repartition: use subcommunicators", true);
343 }
344 }
345
346 if (precList22_.isParameter("repartition: use subcommunicators")) {
347 precList11_.set("repartition: use subcommunicators", precList22_.get<bool>("repartition: use subcommunicators"));
348
349 // We do not want (1,1) and (2,2) blocks being repartitioned seperately, so we specify the map that
350 // is going to be used (this is generated in ReitzingerPFactory)
351 if (precList11_.get<bool>("repartition: use subcommunicators") == true)
352 precList11_.set("repartition: use subcommunicators in place", true);
353 } else {
354 // We'll have Maxwell1 default to using subcommunicators if you don't specify
355 precList11_.set("repartition: use subcommunicators", true);
356 precList22_.set("repartition: use subcommunicators", true);
357
358 // We do not want (1,1) and (2,2) blocks being repartitioned seperately, so we specify the map that
359 // is going to be used (this is generated in ReitzingerPFactory)
360 precList11_.set("repartition: use subcommunicators in place", true);
361 }
362
363 } else
364 precList11_.remove("repartition: enable", false);
365
367 // Remove explicit zeros from matrices
368 /*
369 Maxwell_Utils<SC,LO,GO,NO>::removeExplicitZeros(parameterList_,D0_Matrix_,SM_Matrix_);
370 */
371
372 if (IsPrint(Statistics2)) {
373 RCP<ParameterList> params = rcp(new ParameterList());
374 ;
375 params->set("printLoadBalancingInfo", true);
376 params->set("printCommInfo", true);
378 }
379
381 // Detect Dirichlet boundary conditions
382 if (!reuse) {
383 magnitudeType rowSumTol = precList11_.get("aggregation: row sum drop tol", -1.0);
388 if (IsPrint(Statistics2)) {
389 GetOStream(Statistics2) << "MueLu::Maxwell1::compute(): Detected " << BCedges_ << " BC rows and " << BCnodes_ << " BC columns." << std::endl;
390 }
391 }
392
393 if (allEdgesBoundary_) {
394 // All edges have been detected as boundary edges.
395 // Do not attempt to construct sub-hierarchies, but just set up a single level preconditioner.
396 GetOStream(Warnings0) << "All edges are detected as boundary edges!" << std::endl;
398
399 // Generate single level hierarchy for the edge
400 precList22_.set("max levels", 1);
401 }
402
403 if (allNodesBoundary_) {
404 // All Nodes have been detected as boundary nodes.
405 // Do not attempt to construct sub-hierarchies, but just set up a single level preconditioner.
406 GetOStream(Warnings0) << "All nodes are detected as boundary nodes!" << std::endl;
408
409 // Generate single level hierarchy for the edge
410 precList22_.set("max levels", 1);
411 }
412
414 // Build (2,2) hierarchy
416
418 // Apply boundary conditions to D0 (if needed)
419 if (!reuse) {
420 D0_Matrix_->resumeFill();
421 Scalar replaceWith = Teuchos::ScalarTraits<SC>::zero();
422
423 if (applyBCsTo22_) {
424 GetOStream(Runtime0) << "Maxwell1::compute(): nuking BC rows/cols of D0" << std::endl;
425 if (useKokkos_) {
427 } else {
429 }
430 } else {
431 GetOStream(Runtime0) << "Maxwell1::compute(): nuking BC rows of D0" << std::endl;
432 if (useKokkos_) {
434 } else {
436 }
437 }
438
439 D0_Matrix_->fillComplete(D0_Matrix_->getDomainMap(), D0_Matrix_->getRangeMap());
440 }
441
443 // What ML does is generate nodal prolongators with an auxiliary hierarchy based on the
444 // user's (2,2) matrix. The actual nodal matrices for smoothing are generated by the
445 // Hiptmair smoother construction. We're not going to do that --- we'll
446 // do as we insert them into the final (1,1) hierarchy.
447
448 // Level 0
449 RCP<Matrix> Kn_Smoother_0;
450 if (have_generated_Kn) {
451 Kn_Smoother_0 = Kn_Matrix_;
452 } else {
453 Kn_Smoother_0 = generate_kn();
454 }
455
457 // Copy the relevant (2,2) data to the (1,1) hierarchy
458 Hierarchy11_ = rcp(new Hierarchy("Maxwell1 (1,1)"));
459 RCP<Matrix> OldSmootherMatrix;
460 RCP<Level> OldEdgeLevel;
461 for (int i = 0; i < Hierarchy22_->GetNumLevels(); i++) {
462 Hierarchy11_->AddNewLevel();
463 RCP<Level> NodeL = Hierarchy22_->GetLevel(i);
464 RCP<Level> EdgeL = Hierarchy11_->GetLevel(i);
465 RCP<Operator> NodeAggOp = NodeL->Get<RCP<Operator>>("A");
466 RCP<Matrix> NodeAggMatrix = rcp_dynamic_cast<Matrix>(NodeAggOp);
467 std::string labelstr = FormattingHelper::getColonLabel(EdgeL->getObjectLabel());
468
469 if (i == 0) {
470 EdgeL->Set("A", SM_Matrix_);
471 EdgeL->Set("D0", D0_Matrix_);
472
473 EdgeL->Set("NodeAggMatrix", NodeAggMatrix);
474 EdgeL->Set("NodeMatrix", Kn_Smoother_0);
475 OldSmootherMatrix = Kn_Smoother_0;
476 OldEdgeLevel = EdgeL;
477 } else {
478 // Set the Nodal P
479 auto NodalP = NodeL->Get<RCP<Matrix>>("P");
480
481 // NOTE: ML uses normalized prolongators for the aggregation hierarchy
482 // and then prolongators of all 1's for doing the Reitzinger prolongator
483 // generation for the edge hierarchy.
484
485 // Get the importer if we have one (for repartitioning)
486 RCP<const Import> importer;
487 if (NodeL->IsAvailable("Importer")) {
488 importer = NodeL->Get<RCP<const Import>>("Importer");
489 EdgeL->Set("NodeImporter", importer);
490 }
491
492 // We used tentative P to generate the coarse discrete gradient.
493 RCP<Matrix> NodalPtent;
494 if (parameterList_.sublist("maxwell1: 22list").template get<std::string>("multigrid algorithm") == "unsmoothed")
495 NodalPtent = NodeL->Get<RCP<Matrix>>("P");
496 else {
497 NodalPtent = NodeL->Get<RCP<Matrix>>("Ptent");
498
499 if (!importer.is_null()) {
500 // The nodal hierarchy rebalanced the coarse level.
501 // P got rebalanced as well, but not Ptent.
502 // Let's do that here.
503 Level fineLevel;
504 Level coarseLevel;
505 fineLevel.SetFactoryManager(null);
506 coarseLevel.SetFactoryManager(null);
507 fineLevel.SetLevelID(0);
508 coarseLevel.SetLevelID(1);
509 auto rebalTransfer = rcp(new RebalanceTransferFactory());
510 ParameterList rebalTransferParams;
511 rebalTransferParams.set("repartition: rebalance P and R", true);
512 rebalTransferParams.set("type", "Interpolation");
513 rebalTransfer->SetParameterList(rebalTransferParams);
514 coarseLevel.Set("P", NodalPtent);
515 coarseLevel.Set("Importer", importer);
516 rebalTransfer->Build(fineLevel, coarseLevel);
517 NodalPtent = coarseLevel.Get<RCP<Matrix>>("P");
518 }
519 }
520
521 auto P_for_RS_construction = Utilities::ReplaceNonZerosWithOnes(NodalPtent);
522 TEUCHOS_TEST_FOR_EXCEPTION(P_for_RS_construction.is_null(), Exceptions::RuntimeError, "Applying ones to prolongator failed");
523
524 // Pnodal is used by ReitzingerP to generate a coarse discrete gradient D0c and by the Hiptmair smoother
525 EdgeL->Set("Pnodal", P_for_RS_construction);
526
527 if (parameterList_.sublist("maxwell1: 11list").template get<std::string>("multigrid algorithm") == "emin reitzinger") {
528 // PnodalEmin is used for the RHS of the sparse constraint in energy minimization:
529 // Pe*D0c = D0*PnodalEmin
530 EdgeL->Set("PnodalEmin", NodalP);
531 }
532
533 // If we repartition a processor away, a RCP<Operator> is stuck
534 // on the level instead of an RCP<Matrix>
535 if (!OldSmootherMatrix.is_null() && !P_for_RS_construction.is_null()) {
536 EdgeL->Set("NodeAggMatrix", NodeAggMatrix);
537 if (!have_generated_Kn) {
538 // The user gave us a Kn on the fine level, so we're using a seperate aggregation
539 // hierarchy from the smoothing hierarchy.
540
541 // ML does a *fixed* 1e-10 diagonal repair on the Nodal Smoothing Matrix
542 // This fix is applied *after* the next level is generated, but before the smoother is.
543 // We can see this behavior from ML, though it isn't 100% clear from the code *how* it happens.
544 // So, here we turn the fix off, then once we've generated the new matrix, we fix the old one.
545
546 // Generate the new matrix
547 Teuchos::ParameterList RAPlist;
548 RAPlist.set("rap: fix zero diagonals", false);
549 RCP<Matrix> NewKn = Maxwell_Utils<SC, LO, GO, NO>::PtAPWrapper(OldSmootherMatrix, P_for_RS_construction, RAPlist, labelstr);
550
551 // If there's an importer, we need to Rebalance the NewKn
552 if (!importer.is_null()) {
553 ParameterList rebAcParams;
554 rebAcParams.set("repartition: use subcommunicators", true);
555 rebAcParams.set("repartition: use subcommunicators in place", true);
556 auto newAfact = rcp(new RebalanceAcFactory());
557 newAfact->SetParameterList(rebAcParams);
558 RCP<const Map> InPlaceMap = NodeAggMatrix.is_null() ? Teuchos::null : NodeAggMatrix->getRowMap();
559
560 Level fLevel, cLevel;
561 cLevel.SetPreviousLevel(Teuchos::rcpFromRef(fLevel));
562 cLevel.Set("InPlaceMap", InPlaceMap);
563 cLevel.Set("A", NewKn);
564 cLevel.Request("A", newAfact.get());
565 newAfact->Build(fLevel, cLevel);
566
567 NewKn = cLevel.Get<RCP<Matrix>>("A", newAfact.get());
568 EdgeL->Set("NodeMatrix", NewKn);
569 } else {
570 EdgeL->Set("NodeMatrix", NewKn);
571 }
572
573 // Fix the old one
574 double thresh = parameterList_.get("maxwell1: nodal smoother fix zero diagonal threshold", 1e-10);
575 if (thresh > 0.0) {
576 GetOStream(Runtime0) << "Maxwell1::compute(): Fixing zero diagonal for nodal smoother matrix" << std::endl;
577 Scalar replacement = Teuchos::ScalarTraits<Scalar>::one();
578 Xpetra::MatrixUtils<SC, LO, GO, NO>::CheckRepairMainDiagonal(OldSmootherMatrix, true, GetOStream(Warnings1), thresh, replacement);
579 }
580 OldEdgeLevel->Set("NodeMatrix", OldSmootherMatrix);
581
582 OldSmootherMatrix = NewKn;
583 } else {
584 // The user didn't give us a Kn, so we aggregate and smooth with the same matrix
585 EdgeL->Set("NodeMatrix", NodeAggMatrix);
586 }
587 } else {
588 // We've partitioned things away.
589 EdgeL->Set("NodeMatrix", NodeAggOp);
590 EdgeL->Set("NodeAggMatrix", NodeAggOp);
591 }
592
593 OldEdgeLevel = EdgeL;
594 }
595
596 } // end Hierarchy22 loop
597
599 // Generating the (1,1) Hierarchy
600 {
601 SM_Matrix_->setObjectLabel("A(1,1)");
602 precList11_.set("coarse: max size", 1);
603 precList11_.set("max levels", Hierarchy22_->GetNumLevels());
604
605 const bool refmaxwellCoarseSolve = (precList11_.get<std::string>("coarse: type",
606 MasterList::getDefault<std::string>("coarse: type")) == "RefMaxwell");
607 if (refmaxwellCoarseSolve) {
608 GetOStream(Runtime0) << "Maxwell1::compute(): Will set up RefMaxwell coarse solver" << std::endl;
609 precList11_.set("coarse: type", "none");
610 }
611
612 // Rip off non-serializable data before validation
613 Teuchos::ParameterList nonSerialList11;
614 Teuchos::ParameterList processedPrecList11;
615 MueLu::ExtractNonSerializableData(precList11_, processedPrecList11, nonSerialList11);
616 RCP<HierarchyManager<SC, LO, GO, NO>> mueLuFactory = rcp(new ParameterListInterpreter<SC, LO, GO, NO>(processedPrecList11, SM_Matrix_->getDomainMap()->getComm()));
617 Hierarchy11_->setlib(SM_Matrix_->getDomainMap()->lib());
618 Hierarchy11_->SetProcRankVerbose(SM_Matrix_->getDomainMap()->getComm()->getRank());
619
620 // Stick the non-serializable data on the hierarchy and do setup
621 if (nonSerialList11.numParams() > 0) {
623 }
624 mueLuFactory->SetupHierarchy(*Hierarchy11_);
625
626 if (refmaxwellCoarseSolve) {
627 GetOStream(Runtime0) << "Maxwell1::compute(): Setting up RefMaxwell coarse solver" << std::endl;
628 auto coarseLvl = Hierarchy11_->GetLevel(Hierarchy11_->GetNumLevels() - 1);
629 auto coarseSolver = rcp(new MueLu::RefMaxwellSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>("RefMaxwell",
630 precList11_.sublist("coarse: params")));
631 coarseSolver->Setup(*coarseLvl);
632 coarseLvl->Set("PreSmoother",
633 rcp_dynamic_cast<SmootherBase>(coarseSolver, true));
634 }
635
636 if (mode_ == MODE_REFMAXWELL) {
637 if (Hierarchy11_->GetNumLevels() > 1) {
638 RCP<Level> EdgeL = Hierarchy11_->GetLevel(1);
639 P11_ = EdgeL->Get<RCP<Matrix>>("P");
640 }
641 }
642 }
643
645 // Allocate temporary MultiVectors for solve (only needed for RefMaxwell style)
647
649
650 if (Behavior::debug()) {
651 for (int i = 1; i < Hierarchy11_->GetNumLevels(); i++) {
652 auto EdgeL = Hierarchy11_->GetLevel(i);
653 auto EdgeL_fine = Hierarchy11_->GetLevel(i - 1);
654 auto NodeL = Hierarchy22_->GetLevel(i);
655
656 auto Pe = EdgeL->template Get<RCP<Matrix>>("P");
657 auto Pn = NodeL->template Get<RCP<Matrix>>("P");
658 auto D0_f = EdgeL_fine->template Get<RCP<Matrix>>("D0");
659 auto D0_c = EdgeL->template Get<RCP<Matrix>>("D0");
660
661 if (!Pe.is_null() && !D0_c.is_null() && (Pe->getRowMap()->getComm()->getSize() == D0_c->getRowMap()->getComm()->getSize())) {
662 using XMM = Xpetra::MatrixMatrix<SC, LO, GO, NO>;
663 auto one = Teuchos::ScalarTraits<SC>::one();
664
665 RCP<Matrix> dummy;
666 RCP<Matrix> left = XMM::Multiply(*Pe, false, *D0_c, false, dummy, GetOStream(Runtime0));
667 RCP<Matrix> right = XMM::Multiply(*D0_f, false, *Pn, false, dummy, GetOStream(Runtime0));
668
669 RCP<Matrix> summation;
670 XMM::TwoMatrixAdd(*left, false, one, *right, false, -one, summation, GetOStream(Runtime0));
671 summation->fillComplete(left->getDomainMap(), left->getRangeMap());
672
673 auto norm = summation->getFrobeniusNorm();
674 GetOStream(Runtime0) << "CheckCommutingProperty on level " << i - 1 << ": || Pe D0_c - D0_f Pn || = " << norm << std::endl;
675 } else if (!Pe.is_null()) {
676 GetOStream(Runtime0) << "Cannot run CheckCommutingProperty on level " << i - 1 << " due to rebalancing" << std::endl;
677 }
678 }
679 }
680#ifdef MUELU_MAXWELL1_DEBUG
681
682 for (int i = 0; i < Hierarchy11_->GetNumLevels(); i++) {
683 RCP<Level> L = Hierarchy11_->GetLevel(i);
684 RCP<Matrix> EdgeMatrix = rcp_dynamic_cast<Matrix>(L->Get<RCP<Operator>>("A"));
685 RCP<Matrix> NodeMatrix = rcp_dynamic_cast<Matrix>(L->Get<RCP<Operator>>("NodeMatrix"));
686 RCP<Matrix> NodeAggMatrix = rcp_dynamic_cast<Matrix>(L->Get<RCP<Operator>>("NodeAggMatrix"));
687 RCP<Matrix> D0 = rcp_dynamic_cast<Matrix>(L->Get<RCP<Operator>>("D0"));
688
689 auto nrmE = EdgeMatrix->getFrobeniusNorm();
690 auto nrmN = NodeMatrix->getFrobeniusNorm();
691 auto nrmNa = NodeAggMatrix->getFrobeniusNorm();
692 auto nrmD0 = D0->getFrobeniusNorm();
693
694 std::cout << "DEBUG: Norms on Level " << i << " E/N/NA/D0 = " << nrmE << " / " << nrmN << " / " << nrmNa << " / " << nrmD0 << std::endl;
695 std::cout << "DEBUG: NNZ on Level " << i << " E/N/NA/D0 = " << EdgeMatrix->getGlobalNumEntries() << " / " << NodeMatrix->getGlobalNumEntries() << " / " << NodeAggMatrix->getGlobalNumEntries() << " / " << D0->getGlobalNumEntries() << std::endl;
696 }
697#endif
698}
699
700template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
701RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>> Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::generate_kn() const {
702 // This is important, as we'll be doing diagonal repair *after* the next-level matrix is generated, not before
703 Teuchos::ParameterList RAPlist;
704 RAPlist.set("rap: fix zero diagonals", false);
705
706 std::string labelstr = "NodeMatrix (Level 0)";
707 RCP<Matrix> rv = Maxwell_Utils<SC, LO, GO, NO>::PtAPWrapper(SM_Matrix_, D0_Matrix_, RAPlist, labelstr);
708 return rv;
709}
710
711template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
713 if (mode_ == MODE_REFMAXWELL) {
714 RCP<Teuchos::TimeMonitor> tmAlloc = getTimer("MueLu Maxwell1: Allocate MVs");
715
716 residualFine_ = MultiVectorFactory::Build(SM_Matrix_->getRangeMap(), numVectors);
717
718 if (!Hierarchy11_.is_null() && Hierarchy11_->GetNumLevels() > 1) {
719 RCP<Level> EdgeL = Hierarchy11_->GetLevel(1);
720 RCP<Matrix> A = EdgeL->Get<RCP<Matrix>>("A");
721 residual11c_ = MultiVectorFactory::Build(A->getRangeMap(), numVectors);
722 update11c_ = MultiVectorFactory::Build(A->getDomainMap(), numVectors);
723 }
724
725 if (!Hierarchy22_.is_null()) {
726 residual22_ = MultiVectorFactory::Build(D0_Matrix_->getDomainMap(), numVectors);
727 update22_ = MultiVectorFactory::Build(D0_Matrix_->getDomainMap(), numVectors);
728 }
729 }
730}
731
732template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
733void Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dump(const Matrix& A, std::string name) const {
734 if (dump_matrices_) {
735 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
736 Xpetra::IO<SC, LO, GO, NO>::Write(name, A);
737 }
738}
739
740template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
741void Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dump(const MultiVector& X, std::string name) const {
742 if (dump_matrices_) {
743 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
744 Xpetra::IO<SC, LO, GO, NO>::Write(name, X);
745 }
746}
747
748template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
750 if (dump_matrices_) {
751 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
752 Xpetra::IO<coordinateType, LO, GO, NO>::Write(name, X);
753 }
754}
755
756template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
757void Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dump(const Teuchos::ArrayRCP<bool>& v, std::string name) const {
758 if (dump_matrices_) {
759 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
760 std::ofstream out(name);
761 for (size_t i = 0; i < Teuchos::as<size_t>(v.size()); i++)
762 out << v[i] << "\n";
763 }
764}
765
766template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
767void Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dump(const Kokkos::View<bool*, typename Node::device_type>& v, std::string name) const {
768 if (dump_matrices_) {
769 GetOStream(Runtime0) << "Dumping to " << name << std::endl;
770 std::ofstream out(name);
771 auto vH = Kokkos::create_mirror_view(v);
772 Kokkos::deep_copy(vH, v);
773 for (size_t i = 0; i < vH.size(); i++)
774 out << vH[i] << "\n";
775 }
776}
777
778template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
779Teuchos::RCP<Teuchos::TimeMonitor> Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getTimer(std::string name, RCP<const Teuchos::Comm<int>> comm) const {
780 if (IsPrint(Timings)) {
781 if (!syncTimers_)
782 return Teuchos::rcp(new Teuchos::TimeMonitor(*Teuchos::TimeMonitor::getNewTimer(name)));
783 else {
784 if (comm.is_null())
785 return Teuchos::rcp(new Teuchos::SyncTimeMonitor(*Teuchos::TimeMonitor::getNewTimer(name), SM_Matrix_->getRowMap()->getComm().ptr()));
786 else
787 return Teuchos::rcp(new Teuchos::SyncTimeMonitor(*Teuchos::TimeMonitor::getNewTimer(name), comm.ptr()));
788 }
789 } else
790 return Teuchos::null;
791}
792
793template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
794void Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::resetMatrix(RCP<Matrix> SM_Matrix_new, bool ComputePrec) {
795 bool reuse = !SM_Matrix_.is_null();
796 SM_Matrix_ = SM_Matrix_new;
797 dump(*SM_Matrix_, "SM.m");
798 if (ComputePrec)
799 compute(reuse);
800}
801
802template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
804 // make sure that we have enough temporary memory
805 const SC one = Teuchos::ScalarTraits<SC>::one();
806 if (!allEdgesBoundary_ && X.getNumVectors() != residualFine_->getNumVectors())
807 allocateMemory(X.getNumVectors());
808
809 TEUCHOS_TEST_FOR_EXCEPTION(Hierarchy11_.is_null() || Hierarchy11_->GetNumLevels() == 0, Exceptions::RuntimeError, "(1,1) Hierarchy is null.");
810
811 // 1) Run fine pre-smoother using Hierarchy11
812 RCP<Level> Fine = Hierarchy11_->GetLevel(0);
813 if (Fine->IsAvailable("PreSmoother")) {
814 RCP<Teuchos::TimeMonitor> tmRes = getTimer("MueLu Maxwell1: PreSmoother");
815 RCP<SmootherBase> preSmoo = Fine->Get<RCP<SmootherBase>>("PreSmoother");
816 preSmoo->Apply(X, RHS, true);
817 }
818
819 // 2) Compute residual
820 {
821 RCP<Teuchos::TimeMonitor> tmRes = getTimer("MueLu Maxwell1: residual calculation");
823 }
824
825 // 3a) Restrict residual to (1,1) Hierarchy's level 1 and execute (1,1) hierarchy (use startLevel and InitialGuessIsZero)
826 if (!P11_.is_null()) {
827 RCP<Teuchos::TimeMonitor> tmRes = getTimer("MueLu Maxwell1: (1,1) correction");
828 P11_->apply(*residualFine_, *residual11c_, Teuchos::TRANS);
829 Hierarchy11_->Iterate(*residual11c_, *update11c_, 1, true, 1);
830 }
831
832 // 3b) Restrict residual to (2,2) Hierarchy's level 0 and execute (2,2) hierarchy (use InitialGuessIsZero)
833 if (!allNodesBoundary_) {
834 RCP<Teuchos::TimeMonitor> tmRes = getTimer("MueLu Maxwell1: (2,2) correction");
835 D0_Matrix_->apply(*residualFine_, *residual22_, Teuchos::TRANS);
836 Hierarchy22_->Iterate(*residual22_, *update22_, 1, true, 0);
837 }
838
839 // 4) Prolong both updates back into X-vector (Need to do both the P11 null and not null cases
840 {
841 RCP<Teuchos::TimeMonitor> tmRes = getTimer("MueLu Maxwell1: Prolongation");
842 if (!P11_.is_null())
843 P11_->apply(*update11c_, X, Teuchos::NO_TRANS, one, one);
845 D0_Matrix_->apply(*update22_, X, Teuchos::NO_TRANS, one, one);
846 }
847
848 // 5) Run fine post-smoother using Hierarchy11
849 if (Fine->IsAvailable("PostSmoother")) {
850 RCP<Teuchos::TimeMonitor> tmRes = getTimer("MueLu Maxwell1: PostSmoother");
851 RCP<SmootherBase> postSmoo = Fine->Get<RCP<SmootherBase>>("PostSmoother");
852 postSmoo->Apply(X, RHS, false);
853 }
854}
855
856template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
857void Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::applyInverseStandard(const MultiVector& RHS, MultiVector& X) const {
858 Hierarchy11_->Iterate(RHS, X, 1, true);
859}
860
861template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
862void Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::apply(const MultiVector& RHS, MultiVector& X,
863 Teuchos::ETransp /* mode */,
864 Scalar /* alpha */,
865 Scalar /* beta */) const {
866 RCP<Teuchos::TimeMonitor> tm = getTimer("MueLu Maxwell1: solve");
868 HierarchyGmhd_->Iterate(RHS, X, 1, true);
869 else if (mode_ == MODE_STANDARD || mode_ == MODE_EDGE_ONLY)
870 applyInverseStandard(RHS, X);
871 else if (mode_ == MODE_REFMAXWELL)
873 else
874 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "Must use mode 'standard', 'refmaxwell' or 'edge only' when not doing GMHD.");
875}
876
877template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
881
882template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
883std::pair<std::set<std::string>, std::set<std::string>> Maxwell1<Scalar, LocalOrdinal, GlobalOrdinal, Node>::requiredAndOptionalUserData(const Teuchos::ParameterList& params) {
884 std::set<std::string> requiredUserData;
885 std::set<std::string> optionalUserData;
886
887 requiredUserData.insert("D0");
888
889 // auto [requiredUserData11, optionalUserData11] = ParameterListInterpreter<Scalar, LocalOrdinal, GlobalOrdinal, Node>::requiredAndOptionalUserData(params.sublist("maxwell1: 11list"));
890 auto [requiredUserData22, optionalUserData22] = ParameterListInterpreter<Scalar, LocalOrdinal, GlobalOrdinal, Node>::requiredAndOptionalUserData(params.sublist("maxwell1: 22list"));
891
892 if (requiredUserData22.contains("Coordinates"))
893 requiredUserData.insert("Coordinates");
894 if (requiredUserData22.contains("Material"))
895 requiredUserData.insert("Material");
896
897 if (params.sublist("maxwell1: 11list").isType<std::string>("multigrid algorithm") &&
898 params.sublist("maxwell1: 11list").get<std::string>("multigrid algorithm") == "smoothed reitzinger" &&
899 (!params.sublist("maxwell1: 11list").isType<double>("sa: damping factor") ||
900 params.sublist("maxwell1: 11list").get<double>("sa: damping factor") != 0.)) {
901 if (!params.sublist("maxwell1: 11list").isType<bool>("sa: use edge matrix for smoothing") ||
902 !params.sublist("maxwell1: 11list").get<bool>("sa: use edge matrix for smoothing"))
903 requiredUserData.insert("CurlCurl");
904 }
905
906 optionalUserData.insert("Nullspace");
907 optionalUserData.insert("Kn");
908 optionalUserData.insert("GmhdA");
909
910 return std::make_pair(requiredUserData, optionalUserData);
911}
912
913template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
914void scaleD0(Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& D0) {
915 // We assume that D0 has entries +-1.
916 // Construction D0 via interpolation can instead give +-0.5
917 // Let's check and scale D0.
918
919 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
920 using Matrix = Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
921 using impl_scalar_type = typename Matrix::impl_scalar_type;
922 using impl_ATS = KokkosKernels::ArithTraits<impl_scalar_type>;
923 using magnitude_type = typename impl_ATS::magnitudeType;
924 using MinMax = Kokkos::MinMax<magnitude_type>;
925
926 typename MinMax::value_type result;
927 {
928 auto lclD0 = D0.getLocalMatrixDevice();
929 Kokkos::parallel_reduce(
930 "MueLu::Maxwell1::D0_fixup",
931 range_type(0, lclD0.nnz()),
932 KOKKOS_LAMBDA(const LocalOrdinal k, typename MinMax::value_type& res) {
933 auto val = impl_ATS::magnitude(lclD0.values(k));
934 res.min_val = Kokkos::min(res.min_val, val);
935 res.max_val = Kokkos::max(res.max_val, val);
936 },
937 MinMax(result));
938 }
939
940 TEUCHOS_ASSERT_EQUALITY(result.min_val, result.max_val);
941
942 if (impl_ATS::magnitude(result.max_val - impl_ATS::one()) > impl_ATS::eps()) {
943 Scalar scaling = impl_ATS::one() / result.max_val;
944 D0.scale(scaling);
945 }
946}
947
948template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
950 initialize(const Teuchos::RCP<Matrix>& D0_Matrix,
951 const Teuchos::RCP<Matrix>& Kn_Matrix,
952 const Teuchos::RCP<MultiVector>& Nullspace,
953 const Teuchos::RCP<RealValuedMultiVector>& Coords,
954 const Teuchos::RCP<Matrix>& CurlCurl_Matrix,
955 const Teuchos::RCP<MultiVector>& Material,
956 Teuchos::ParameterList& List) {
957 // some pre-conditions
958 TEUCHOS_ASSERT(D0_Matrix != Teuchos::null);
959
960 if (Behavior::debug()) {
961 if (!Kn_Matrix.is_null()) {
962 TEUCHOS_ASSERT(Kn_Matrix->getDomainMap()->isSameAs(*D0_Matrix->getDomainMap()));
963 TEUCHOS_ASSERT(Kn_Matrix->getRangeMap()->isSameAs(*D0_Matrix->getDomainMap()));
964 }
965
966 TEUCHOS_ASSERT(D0_Matrix->getRangeMap()->isSameAs(*D0_Matrix->getRowMap()));
967 }
968
969 Hierarchy11_ = Teuchos::null;
970 Hierarchy22_ = Teuchos::null;
971 HierarchyGmhd_ = Teuchos::null;
973
974 // Default settings
975 useKokkos_ = false;
976 allEdgesBoundary_ = false;
977 allNodesBoundary_ = false;
978 dump_matrices_ = false;
979 check_D0_scaling_ = false;
980 enable_reuse_ = false;
981 syncTimers_ = false;
982 applyBCsTo22_ = false;
983
984 // set parameters
985 setParameters(List);
986
987 if (D0_Matrix->getRowMap()->lib() == Xpetra::UseTpetra) {
988 // We will remove boundary conditions from D0, and potentially change maps, so we copy the input.
989 // Fortunately, D0 is quite sparse.
990 // We cannot use the Tpetra copy constructor, since it does not copy the graph.
991
992 RCP<Matrix> D0copy = MatrixFactory::Build(D0_Matrix->getRowMap(), D0_Matrix->getColMap(), 0);
993 RCP<CrsMatrix> D0copyCrs = toCrsMatrix(D0copy);
994 ArrayRCP<const size_t> D0rowptr_RCP;
995 ArrayRCP<const LO> D0colind_RCP;
996 ArrayRCP<const SC> D0vals_RCP;
997 toCrsMatrix(D0_Matrix)->getAllValues(D0rowptr_RCP, D0colind_RCP, D0vals_RCP);
998
999 ArrayRCP<size_t> D0copyrowptr_RCP;
1000 ArrayRCP<LO> D0copycolind_RCP;
1001 ArrayRCP<SC> D0copyvals_RCP;
1002 D0copyCrs->allocateAllValues(D0vals_RCP.size(), D0copyrowptr_RCP, D0copycolind_RCP, D0copyvals_RCP);
1003 D0copyrowptr_RCP.deepCopy(D0rowptr_RCP());
1004 D0copycolind_RCP.deepCopy(D0colind_RCP());
1005 D0copyvals_RCP.deepCopy(D0vals_RCP());
1006 D0copyCrs->setAllValues(D0copyrowptr_RCP,
1007 D0copycolind_RCP,
1008 D0copyvals_RCP);
1009 D0copyCrs->expertStaticFillComplete(D0_Matrix->getDomainMap(), D0_Matrix->getRangeMap(),
1010 toCrsMatrix(D0_Matrix)->getCrsGraph()->getImporter(),
1011 toCrsMatrix(D0_Matrix)->getCrsGraph()->getExporter());
1012 D0_Matrix_ = D0copy;
1013 } else
1014 D0_Matrix_ = MatrixFactory::BuildCopy(D0_Matrix);
1015
1018
1019 Kn_Matrix_ = Kn_Matrix;
1020 Coords_ = Coords;
1021 Material_ = Material;
1022 Nullspace_ = Nullspace;
1023
1024 if (!CurlCurl_Matrix.is_null()) {
1025 precList11_.sublist("user data").set("CurlCurl", CurlCurl_Matrix);
1026 dump(*CurlCurl_Matrix, "CurlCurl.m");
1027 }
1028
1029 dump(*D0_Matrix_, "D0.m");
1030 if (!Kn_Matrix_.is_null()) dump(*Kn_Matrix_, "Kn.m");
1031 if (!Nullspace_.is_null()) dump(*Nullspace_, "nullspace.m");
1032 if (!Coords_.is_null()) dumpCoords(*Coords_, "coords.m");
1033}
1034
1035template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1037 describe(Teuchos::FancyOStream& out, const Teuchos::EVerbosityLevel /* verbLevel */) const {
1038 std::ostringstream oss;
1039
1040 RCP<const Teuchos::Comm<int>> comm = SM_Matrix_->getDomainMap()->getComm();
1041
1042#ifdef HAVE_MPI
1043 int root;
1044 if (!Kn_Matrix_.is_null())
1045 root = comm->getRank();
1046 else
1047 root = -1;
1048
1049 int actualRoot;
1050 reduceAll(*comm, Teuchos::REDUCE_MAX, root, Teuchos::ptr(&actualRoot));
1051 root = actualRoot;
1052#endif
1053
1054 oss << "\n--------------------------------------------------------------------------------\n"
1055 << "--- Maxwell1 Summary ---\n"
1056 "--------------------------------------------------------------------------------"
1057 << std::endl;
1058 oss << std::endl;
1059
1060 GlobalOrdinal numRows;
1061 GlobalOrdinal nnz;
1062
1063 SM_Matrix_->getRowMap()->getComm()->barrier();
1064
1065 numRows = SM_Matrix_->getGlobalNumRows();
1066 nnz = SM_Matrix_->getGlobalNumEntries();
1067
1068 Xpetra::global_size_t tt = numRows;
1069 int rowspacer = 3;
1070 while (tt != 0) {
1071 tt /= 10;
1072 rowspacer++;
1073 }
1074 tt = nnz;
1075 int nnzspacer = 2;
1076 while (tt != 0) {
1077 tt /= 10;
1078 nnzspacer++;
1079 }
1080
1081 oss << "block " << std::setw(rowspacer) << " rows " << std::setw(nnzspacer) << " nnz " << std::setw(9) << " nnz/row" << std::endl;
1082 oss << "(1, 1)" << std::setw(rowspacer) << numRows << std::setw(nnzspacer) << nnz << std::setw(9) << as<double>(nnz) / numRows << std::endl;
1083
1084 if (!Kn_Matrix_.is_null()) {
1085 // ToDo: make sure that this is printed correctly
1086 numRows = Kn_Matrix_->getGlobalNumRows();
1087 nnz = Kn_Matrix_->getGlobalNumEntries();
1088
1089 oss << "(2, 2)" << std::setw(rowspacer) << numRows << std::setw(nnzspacer) << nnz << std::setw(9) << as<double>(nnz) / numRows << std::endl;
1090 }
1091
1092 oss << std::endl;
1093
1094 std::string outstr = oss.str();
1095
1096#ifdef HAVE_MPI
1097 RCP<const Teuchos::MpiComm<int>> mpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int>>(comm);
1098 MPI_Comm rawComm = (*mpiComm->getRawMpiComm())();
1099
1100 int strLength = outstr.size();
1101 MPI_Bcast(&strLength, 1, MPI_INT, root, rawComm);
1102 if (comm->getRank() != root)
1103 outstr.resize(strLength);
1104 MPI_Bcast(&outstr[0], strLength, MPI_CHAR, root, rawComm);
1105#endif
1106
1107 out << outstr;
1108
1109 if (!Hierarchy11_.is_null())
1110 Hierarchy11_->describe(out, GetVerbLevel());
1111
1112 if (!Hierarchy22_.is_null())
1113 Hierarchy22_->describe(out, GetVerbLevel());
1114
1115 if (!HierarchyGmhd_.is_null())
1116 HierarchyGmhd_->describe(out, GetVerbLevel());
1117
1118 if (IsPrint(Statistics2)) {
1119 // Print the grid of processors
1120 std::ostringstream oss2;
1121
1122 oss2 << "Sub-solver distribution over ranks" << std::endl;
1123 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;
1124
1125 int numProcs = comm->getSize();
1126#ifdef HAVE_MPI
1127 RCP<const Teuchos::MpiComm<int>> tmpic = rcp_dynamic_cast<const Teuchos::MpiComm<int>>(comm);
1128
1129 RCP<const Teuchos::OpaqueWrapper<MPI_Comm>> rawMpiComm = tmpic->getRawMpiComm();
1130#endif
1131
1132 char status = 0;
1133 if (!Kn_Matrix_.is_null())
1134 status += 1;
1135 std::vector<char> states(numProcs, 0);
1136#ifdef HAVE_MPI
1137 MPI_Gather(&status, 1, MPI_CHAR, &states[0], 1, MPI_CHAR, 0, *rawMpiComm);
1138#else
1139 states.push_back(status);
1140#endif
1141
1142 int rowWidth = std::min(Teuchos::as<int>(ceil(sqrt(numProcs))), 100);
1143 for (int proc = 0; proc < numProcs; proc += rowWidth) {
1144 for (int j = 0; j < rowWidth; j++)
1145 if (proc + j < numProcs)
1146 if (states[proc + j] == 0)
1147 oss2 << ".";
1148 else if (states[proc + j] == 1)
1149 oss2 << "1";
1150 else if (states[proc + j] == 2)
1151 oss2 << "2";
1152 else
1153 oss2 << "B";
1154 else
1155 oss2 << " ";
1156
1157 oss2 << " " << proc << ":" << std::min(proc + rowWidth, numProcs) - 1 << std::endl;
1158 }
1159 oss2 << std::endl;
1160 GetOStream(Statistics2) << oss2.str();
1161 }
1162}
1163
1164} // namespace MueLu
1165
1166#define MUELU_MAXWELL1_SHORT
1167#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
static bool debug()
Whether MueLu is in debug mode.
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.
void SetLevelID(int levelID)
Set level number.
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access)....
void Set(const std::string &ename, const T &entry, const FactoryBase *factory=NoFactory::get())
void Request(const FactoryBase &factory)
Increment the storage counter for all the inputs of a factory.
void SetPreviousLevel(const RCP< Level > &previousLevel)
void SetFactoryManager(const RCP< const FactoryManagerBase > &factoryManager)
Set default factories (used internally by Hierarchy::SetLevel()).
static Teuchos::RCP< Teuchos::ParameterList > translate(const Teuchos::ParameterList &paramList, const std::string &defaultVals="")
: Translate ML parameters to MueLu parameter XML string
static const T & getDefault(const std::string &name)
Returns default value on the "master" list for a parameter with the specified name and type.
const Teuchos::RCP< const Map > getDomainMap() const
Returns the Xpetra::Map object associated with the domain of this operator.
bool useKokkos_
Some options.
Teuchos::RCP< Matrix > generate_kn() const
Generates the Kn matrix.
Teuchos::RCP< Hierarchy > Hierarchy11_
Two hierarchies: one for the (1,1)-block, another for the (2,2)-block.
Teuchos::RCP< Hierarchy > HierarchyGmhd_
Teuchos::RCP< MultiVector > residualFine_
typename Teuchos::ScalarTraits< Scalar >::magnitudeType magnitudeType
Teuchos::ArrayRCP< bool > BCcols_
Teuchos::ArrayRCP< bool > BCrows_
Teuchos::RCP< Matrix > SM_Matrix_
Various matrices.
Teuchos::RCP< Hierarchy > Hierarchy22_
Kokkos::View< bool *, typename Node::device_type::memory_space > BCrowsKokkos_
Vectors for BCs.
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.
Teuchos::ParameterList parameterList_
ParameterLists.
Teuchos::RCP< MultiVector > residual22_
Kokkos::View< bool *, typename Node::device_type::memory_space > BCdomainKokkos_
Teuchos::RCP< RealValuedMultiVector > Coords_
Coordinates.
Teuchos::RCP< Matrix > D0_Matrix_
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
Teuchos::RCP< MultiVector > Nullspace_
Nullspace.
Teuchos::RCP< MultiVector > update11c_
void apply(const MultiVector &RHS, MultiVector &X, Teuchos::ETransp mode=Teuchos::NO_TRANS, Scalar alpha=Teuchos::ScalarTraits< Scalar >::one(), Scalar beta=Teuchos::ScalarTraits< Scalar >::zero()) const
void applyInverseStandard(const MultiVector &RHS, MultiVector &X) const
apply standard Maxwell1 cycle
RCP< Matrix > P11_
Temporary memory (cached vectors for RefMaxwell-style).
Teuchos::RCP< MultiVector > Material_
Material.
void dumpCoords(const RealValuedMultiVector &X, std::string name) const
dump out real-valued multivector
Teuchos::RCP< MultiVector > update22_
Teuchos::ArrayRCP< bool > BCdomain_
Teuchos::ParameterList precList11_
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::VERB_HIGH) const
Teuchos::RCP< Matrix > GmhdA_Matrix_
void dump(const Matrix &A, std::string name) const
dump out matrix
typename Xpetra::MultiVector< coordinateType, LO, GO, NO > RealValuedMultiVector
Teuchos::ParameterList precList22_
void resetMatrix(Teuchos::RCP< Matrix > SM_Matrix_new, bool ComputePrec=true)
Reset system matrix.
static std::pair< std::set< std::string >, std::set< std::string > > requiredAndOptionalUserData(const Teuchos::ParameterList &params)
Teuchos::RCP< Matrix > Kn_Matrix_
Teuchos::RCP< MultiVector > residual11c_
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
Kokkos::View< bool *, typename Node::device_type::memory_space > BCcolsKokkos_
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< Matrix > &CurlCurl_Matrix, const Teuchos::RCP< MultiVector > &Material, Teuchos::ParameterList &List)
void setParameters(Teuchos::ParameterList &list)
Set parameters.
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.
static std::pair< std::set< std::string >, std::set< std::string > > requiredAndOptionalUserData(const Teuchos::ParameterList &paramList, Teuchos::RCP< const Teuchos::ParameterList > defaultList=Teuchos::null, int maxLevel=0)
static std::string PrintMatrixInfo(const Matrix &A, const std::string &msgTag, RCP< const Teuchos::ParameterList > params=Teuchos::null)
Factory for building coarse matrices.
Applies permutation to grid transfer operators.
Class that encapsulates Operator smoothers.
static void ZeroDirichletRows(Teuchos::RCP< Xpetra::Matrix< Scalar, DefaultLocalOrdinal, DefaultGlobalOrdinal, DefaultNode > > &A, const std::vector< DefaultLocalOrdinal > &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, DefaultLocalOrdinal, DefaultGlobalOrdinal, DefaultNode > > ReplaceNonZerosWithOnes(const RCP< Matrix > &original)
static RCP< MultiVector > Residual(const Xpetra::Operator< Scalar, DefaultLocalOrdinal, DefaultGlobalOrdinal, DefaultNode > &Op, const MultiVector &X, const MultiVector &RHS)
Teuchos::FancyOStream & GetOStream(MsgType type, int thisProcRankOnly=0) const
Get an output stream for outputting the input message type.
VerbLevel GetVerbLevel() const
Get the verbosity level.
bool IsPrint(MsgType type, int thisProcRankOnly=-1) const
Find out whether we need to print out information for a specific message type.
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.