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