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