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