Ifpack2 Templated Preconditioning Package  Version 1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Ifpack2_BlockRelaxation_def.hpp
1 // @HEADER
2 // *****************************************************************************
3 // Ifpack2: Templated Object-Oriented Algebraic Preconditioner Package
4 //
5 // Copyright 2009 NTESS and the Ifpack2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef IFPACK2_BLOCKRELAXATION_DEF_HPP
11 #define IFPACK2_BLOCKRELAXATION_DEF_HPP
12 
14 #include "Ifpack2_LinearPartitioner.hpp"
15 #include "Ifpack2_LinePartitioner.hpp"
16 #include "Ifpack2_Zoltan2Partitioner_decl.hpp"
17 #include "Ifpack2_Zoltan2Partitioner_def.hpp"
19 #include "Ifpack2_Details_UserPartitioner_def.hpp"
20 #include "Ifpack2_LocalFilter.hpp"
21 #include "Ifpack2_Parameters.hpp"
22 #include "Teuchos_TimeMonitor.hpp"
23 #include "Tpetra_BlockCrsMatrix_Helpers_decl.hpp"
24 #include "Tpetra_Import_Util.hpp"
25 #include "Ifpack2_BlockHelper_Timers.hpp"
26 
27 namespace Ifpack2 {
28 
29 template <class MatrixType, class ContainerType>
32  if (A.getRawPtr() != A_.getRawPtr()) { // it's a different matrix
33  IsInitialized_ = false;
34  IsComputed_ = false;
35  Partitioner_ = Teuchos::null;
36  W_ = Teuchos::null;
37 
38  if (!A.is_null()) {
39  IsParallel_ = (A->getRowMap()->getComm()->getSize() != 1);
41  Teuchos::rcp_dynamic_cast<const block_crs_matrix_type>(A);
42  hasBlockCrsMatrix_ = !A_bcrs.is_null();
43  }
44  if (!Container_.is_null()) {
45  // This just frees up the container's memory.
46  // The container will be fully re-constructed during initialize().
47  Container_->clearBlocks();
48  }
49  NumLocalBlocks_ = 0;
50 
51  A_ = A;
52  computeImporter();
53  }
54 }
55 
56 template <class MatrixType, class ContainerType>
59  : Container_(Teuchos::null)
60  , Partitioner_(Teuchos::null)
61  , PartitionerType_("linear")
62  , NumSweeps_(1)
63  , NumLocalBlocks_(0)
64  , containerType_("TriDi")
65  , PrecType_(Ifpack2::Details::JACOBI)
66  , ZeroStartingSolution_(true)
67  , hasBlockCrsMatrix_(false)
68  , DoBackwardGS_(false)
69  , OverlapLevel_(0)
70  , nonsymCombine_(0)
71  , schwarzCombineMode_("ZERO")
72  , DampingFactor_(STS::one())
73  , IsInitialized_(false)
74  , IsComputed_(false)
75  , NumInitialize_(0)
76  , NumCompute_(0)
77  , TimerForApply_(true)
78  , NumApply_(0)
79  , InitializeTime_(0.0)
80  , ComputeTime_(0.0)
81  , NumLocalRows_(0)
82  , NumGlobalRows_(0)
83  , NumGlobalNonzeros_(0)
84  , W_(Teuchos::null)
85  , Importer_(Teuchos::null) {
86  setMatrix(A);
87 }
88 
89 template <class MatrixType, class ContainerType>
92 
93 template <class MatrixType, class ContainerType>
97  Teuchos::RCP<Teuchos::ParameterList> validParams = Teuchos::parameterList("Ifpack2::BlockRelaxation");
98 
99  validParams->set("relaxation: container", "TriDi");
100  validParams->set("relaxation: backward mode", false);
101  validParams->set("relaxation: type", "Jacobi");
102  validParams->set("relaxation: sweeps", 1);
103  validParams->set("relaxation: damping factor", STS::one());
104  validParams->set("relaxation: zero starting solution", true);
105  validParams->set("block relaxation: decouple dofs", false);
106  validParams->set("schwarz: compute condest", false); // mfh 24 Mar 2015: for backwards compatibility ONLY
107  validParams->set("schwarz: combine mode", "ZERO"); // use string mode for this
108  validParams->set("schwarz: use reordering", true);
109  validParams->set("schwarz: filter singletons", false);
110  validParams->set("schwarz: overlap level", 0);
111  validParams->set("partitioner: type", "greedy");
112  validParams->set("zoltan2: algorithm", "phg");
113  validParams->set("partitioner: local parts", 1);
114  validParams->set("partitioner: overlap", 0);
115  validParams->set("partitioner: combine mode", "ZERO"); // use string mode for this
117  validParams->set("partitioner: parts", tmp0);
119  validParams->set("partitioner: global ID parts", tmp1);
120  validParams->set("partitioner: nonsymmetric overlap combine", false);
121  validParams->set("partitioner: maintain sparsity", false);
122  validParams->set("fact: ilut level-of-fill", 1.0);
123  validParams->set("fact: absolute threshold", 0.0);
124  validParams->set("fact: relative threshold", 1.0);
125  validParams->set("fact: relax value", 0.0);
126 
127  Teuchos::ParameterList dummyList;
128  validParams->set("Amesos2", dummyList);
129  validParams->sublist("Amesos2").disableRecursiveValidation();
130  validParams->set("Amesos2 solver name", "KLU2");
131 
133  validParams->set("partitioner: map", tmp);
134 
135  validParams->set("partitioner: line detection threshold", 0.0);
136  validParams->set("partitioner: PDE equations", 1);
138  typename MatrixType::local_ordinal_type,
139  typename MatrixType::global_ordinal_type,
140  typename MatrixType::node_type>>
141  dummy;
142  validParams->set("partitioner: coordinates", dummy);
143  validParams->set("timer for apply", true);
144  validParams->set("partitioner: subparts per part", 1);
145  validParams->set("partitioner: block size", -1);
146  validParams->set("partitioner: print level", false);
147  validParams->set("partitioner: explicit convert to BlockCrs", false);
148  validParams->set("partitioner: checkBlockConsistency", true);
149  validParams->set("partitioner: use LIDs", true);
150 
151  return validParams;
152 }
153 
154 template <class MatrixType, class ContainerType>
157  // CAG: Copied from Relaxation
158  // FIXME (aprokop 18 Oct 2013) Casting away const is bad here.
159  // but otherwise, we will get [unused] in pl
160  this->setParametersImpl(const_cast<Teuchos::ParameterList&>(pl));
161 }
162 
163 template <class MatrixType, class ContainerType>
166  if (List.isType<double>("relaxation: damping factor")) {
167  // Make sure that ST=complex can run with a damping factor that is
168  // a double.
169  scalar_type df = List.get<double>("relaxation: damping factor");
170  List.remove("relaxation: damping factor");
171  List.set("relaxation: damping factor", df);
172  }
173 
174  // Note that the validation process does not change List.
176  validparams = this->getValidParameters();
177  List.validateParameters(*validparams);
178 
179  if (List.isParameter("relaxation: container")) {
180  // If the container type isn't a string, this will throw, but it
181  // rightfully should.
182 
183  // If its value does not match the currently registered Container types,
184  // the ContainerFactory will throw with an informative message.
185  containerType_ = List.get<std::string>("relaxation: container");
186  // Intercept more human-readable aliases for the *TriDi containers
187  if (containerType_ == "Tridiagonal") {
188  containerType_ = "TriDi";
189  }
190  if (containerType_ == "Block Tridiagonal") {
191  containerType_ = "BlockTriDi";
192  }
193  }
194 
195  if (List.isParameter("relaxation: type")) {
196  const std::string relaxType = List.get<std::string>("relaxation: type");
197 
198  if (relaxType == "Jacobi") {
199  PrecType_ = Ifpack2::Details::JACOBI;
200  } else if (relaxType == "MT Split Jacobi") {
201  PrecType_ = Ifpack2::Details::MTSPLITJACOBI;
202  } else if (relaxType == "Gauss-Seidel") {
203  PrecType_ = Ifpack2::Details::GS;
204  } else if (relaxType == "Symmetric Gauss-Seidel") {
205  PrecType_ = Ifpack2::Details::SGS;
206  } else {
207  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
208  "Ifpack2::BlockRelaxation::"
209  "setParameters: Invalid parameter value \""
210  << relaxType
211  << "\" for parameter \"relaxation: type\".");
212  }
213  }
214 
215  if (List.isParameter("relaxation: sweeps")) {
216  NumSweeps_ = List.get<int>("relaxation: sweeps");
217  }
218 
219  // Users may specify this as a floating-point literal. In that
220  // case, it may have type double, even if scalar_type is something
221  // else. We take care to try the various types that make sense.
222  if (List.isParameter("relaxation: damping factor")) {
223  if (List.isType<double>("relaxation: damping factor")) {
224  const double dampingFactor =
225  List.get<double>("relaxation: damping factor");
226  DampingFactor_ = static_cast<scalar_type>(dampingFactor);
227  } else if (List.isType<scalar_type>("relaxation: damping factor")) {
228  DampingFactor_ = List.get<scalar_type>("relaxation: damping factor");
229  } else if (List.isType<magnitude_type>("relaxation: damping factor")) {
230  const magnitude_type dampingFactor =
231  List.get<magnitude_type>("relaxation: damping factor");
232  DampingFactor_ = static_cast<scalar_type>(dampingFactor);
233  } else {
234  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
235  "Ifpack2::BlockRelaxation::"
236  "setParameters: Parameter \"relaxation: damping factor\" "
237  "has the wrong type.");
238  }
239  }
240 
241  if (List.isParameter("relaxation: zero starting solution")) {
242  ZeroStartingSolution_ = List.get<bool>("relaxation: zero starting solution");
243  }
244 
245  if (List.isParameter("relaxation: backward mode")) {
246  DoBackwardGS_ = List.get<bool>("relaxation: backward mode");
247  }
248 
249  if (List.isParameter("partitioner: type")) {
250  PartitionerType_ = List.get<std::string>("partitioner: type");
251  }
252 
253  // Users may specify this as an int literal, so we need to allow
254  // both int and local_ordinal_type (not necessarily same as int).
255  if (List.isParameter("partitioner: local parts")) {
256  if (List.isType<local_ordinal_type>("partitioner: local parts")) {
257  NumLocalBlocks_ = List.get<local_ordinal_type>("partitioner: local parts");
258  } else if (!std::is_same<int, local_ordinal_type>::value &&
259  List.isType<int>("partitioner: local parts")) {
260  NumLocalBlocks_ = List.get<int>("partitioner: local parts");
261  } else {
262  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
263  "Ifpack2::BlockRelaxation::"
264  "setParameters: Parameter \"partitioner: local parts\" "
265  "has the wrong type.");
266  }
267  }
268 
269  if (List.isParameter("partitioner: overlap level")) {
270  if (List.isType<int>("partitioner: overlap level")) {
271  OverlapLevel_ = List.get<int>("partitioner: overlap level");
272  } else if (!std::is_same<int, local_ordinal_type>::value &&
273  List.isType<local_ordinal_type>("partitioner: overlap level")) {
274  OverlapLevel_ = List.get<local_ordinal_type>("partitioner: overlap level");
275  } else {
276  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
277  "Ifpack2::BlockRelaxation::"
278  "setParameters: Parameter \"partitioner: overlap level\" "
279  "has the wrong type.");
280  }
281  }
282  // when using global ID parts, assume that some blocks overlap even if
283  // user did not explicitly set the overlap level in the input file.
284  if ((List.isParameter("partitioner: global ID parts")) && (OverlapLevel_ < 1)) OverlapLevel_ = 1;
285 
286  if (List.isParameter("partitioner: nonsymmetric overlap combine"))
287  nonsymCombine_ = List.get<bool>("partitioner: nonsymmetric overlap combine");
288 
289  if (List.isParameter("partitioner: combine mode"))
290  schwarzCombineMode_ = List.get<std::string>("partitioner: combine mode");
291 
292  std::string defaultContainer = "TriDi";
293  if (std::is_same<ContainerType, Container<MatrixType>>::value) {
294  // Generic container template parameter, container type specified in List
295  Ifpack2::getParameter(List, "relaxation: container", defaultContainer);
296  }
297  // check parameters
298  if (PrecType_ != Ifpack2::Details::JACOBI) {
299  OverlapLevel_ = 0;
300  }
301  if (NumLocalBlocks_ < static_cast<local_ordinal_type>(0)) {
302  NumLocalBlocks_ = A_->getLocalNumRows() / (-NumLocalBlocks_);
303  }
304 
305  decouple_ = false;
306  if (List.isParameter("block relaxation: decouple dofs"))
307  decouple_ = List.get<bool>("block relaxation: decouple dofs");
308 
309  // other checks are performed in Partitioner_
310 
311  // NTS: Sanity check to be removed at a later date when Backward mode is enabled
313  DoBackwardGS_, std::runtime_error,
314  "Ifpack2::BlockRelaxation:setParameters: Setting the \"relaxation: "
315  "backward mode\" parameter to true is not yet supported.");
316 
317  if (List.isParameter("timer for apply"))
318  TimerForApply_ = List.get<bool>("timer for apply");
319 
320  // copy the list as each subblock's constructor will
321  // require it later
322  List_ = List;
323 }
324 
325 template <class MatrixType, class ContainerType>
328  TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error,
329  "Ifpack2::BlockRelaxation::getComm: "
330  "The matrix is null. You must call setMatrix() with a nonnull matrix "
331  "before you may call this method.");
332  return A_->getComm();
333 }
334 
335 template <class MatrixType, class ContainerType>
336 Teuchos::RCP<const Tpetra::RowMatrix<typename MatrixType::scalar_type,
337  typename MatrixType::local_ordinal_type,
338  typename MatrixType::global_ordinal_type,
339  typename MatrixType::node_type>>
341  return A_;
342 }
343 
344 template <class MatrixType, class ContainerType>
345 Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,
346  typename MatrixType::global_ordinal_type,
347  typename MatrixType::node_type>>
349  getDomainMap() const {
350  TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error,
351  "Ifpack2::BlockRelaxation::"
352  "getDomainMap: The matrix is null. You must call setMatrix() with a "
353  "nonnull matrix before you may call this method.");
354  return A_->getDomainMap();
355 }
356 
357 template <class MatrixType, class ContainerType>
358 Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,
359  typename MatrixType::global_ordinal_type,
360  typename MatrixType::node_type>>
362  getRangeMap() const {
363  TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error,
364  "Ifpack2::BlockRelaxation::"
365  "getRangeMap: The matrix is null. You must call setMatrix() with a "
366  "nonnull matrix before you may call this method.");
367  return A_->getRangeMap();
368 }
369 
370 template <class MatrixType, class ContainerType>
372  hasTransposeApply() const {
373  return true;
374 }
375 
376 template <class MatrixType, class ContainerType>
379  return NumInitialize_;
380 }
381 
382 template <class MatrixType, class ContainerType>
384  getNumCompute() const {
385  return NumCompute_;
386 }
387 
388 template <class MatrixType, class ContainerType>
390  getNumApply() const {
391  return NumApply_;
392 }
393 
394 template <class MatrixType, class ContainerType>
395 double
398  return InitializeTime_;
399 }
400 
401 template <class MatrixType, class ContainerType>
402 double
405  return ComputeTime_;
406 }
407 
408 template <class MatrixType, class ContainerType>
409 double
411  getApplyTime() const {
412  return ApplyTime_;
413 }
414 
415 template <class MatrixType, class ContainerType>
418  A_.is_null(), std::runtime_error,
419  "Ifpack2::BlockRelaxation::getNodeSmootherComplexity: "
420  "The input matrix A is null. Please call setMatrix() with a nonnull "
421  "input matrix, then call compute(), before calling this method.");
422  // Relaxation methods cost roughly one apply + one block-diagonal inverse per iteration
423  // NOTE: This approximates all blocks as dense, which may overstate the cost if you have a sparse (or banded) container.
424  size_t block_nnz = 0;
425  for (local_ordinal_type i = 0; i < NumLocalBlocks_; ++i)
426  block_nnz += Partitioner_->numRowsInPart(i) * Partitioner_->numRowsInPart(i);
427 
428  return block_nnz + A_->getLocalNumEntries();
429 }
430 
431 template <class MatrixType, class ContainerType>
433  apply(const Tpetra::MultiVector<typename MatrixType::scalar_type,
434  typename MatrixType::local_ordinal_type,
435  typename MatrixType::global_ordinal_type,
436  typename MatrixType::node_type>& X,
437  Tpetra::MultiVector<typename MatrixType::scalar_type,
438  typename MatrixType::local_ordinal_type,
439  typename MatrixType::global_ordinal_type,
440  typename MatrixType::node_type>& Y,
441  Teuchos::ETransp mode,
442  scalar_type alpha,
443  scalar_type beta) const {
444  TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error,
445  "Ifpack2::BlockRelaxation::apply: "
446  "The matrix is null. You must call setMatrix() with a nonnull matrix, "
447  "then call initialize() and compute() (in that order), before you may "
448  "call this method.");
450  !isComputed(), std::runtime_error,
451  "Ifpack2::BlockRelaxation::apply: "
452  "isComputed() must be true prior to calling apply.");
453  TEUCHOS_TEST_FOR_EXCEPTION(
454  X.getNumVectors() != Y.getNumVectors(), std::invalid_argument,
455  "Ifpack2::BlockRelaxation::apply: X.getNumVectors() = "
456  << X.getNumVectors() << " != Y.getNumVectors() = "
457  << Y.getNumVectors() << ".");
458  TEUCHOS_TEST_FOR_EXCEPTION(
459  mode != Teuchos::NO_TRANS, std::logic_error,
460  "Ifpack2::BlockRelaxation::"
461  "apply: This method currently only implements the case mode == Teuchos::"
462  "NO_TRANS. Transposed modes are not currently supported.");
463  TEUCHOS_TEST_FOR_EXCEPTION(
464  alpha != Teuchos::ScalarTraits<scalar_type>::one(), std::logic_error,
465  "Ifpack2::BlockRelaxation::apply: This method currently only implements "
466  "the case alpha == 1. You specified alpha = "
467  << alpha << ".");
468  TEUCHOS_TEST_FOR_EXCEPTION(
469  beta != Teuchos::ScalarTraits<scalar_type>::zero(), std::logic_error,
470  "Ifpack2::BlockRelaxation::apply: This method currently only implements "
471  "the case beta == 0. You specified beta = "
472  << beta << ".");
473 
474  const std::string timerName("Ifpack2::BlockRelaxation::apply");
476  if (TimerForApply_) {
477  timer = Teuchos::TimeMonitor::lookupCounter(timerName);
478  if (timer.is_null()) {
479  timer = Teuchos::TimeMonitor::getNewCounter(timerName);
480  }
481  }
482 
483  Teuchos::Time time = Teuchos::Time(timerName);
484  double startTime = time.wallTime();
485 
486  {
488  if (TimerForApply_)
489  timeMon = Teuchos::rcp(new Teuchos::TimeMonitor(*timer));
490 
491  // If X and Y are pointing to the same memory location,
492  // we need to create an auxiliary vector, Xcopy
493  Teuchos::RCP<const MV> X_copy;
494  {
495  if (X.aliases(Y)) {
496  X_copy = rcp(new MV(X, Teuchos::Copy));
497  } else {
498  X_copy = rcpFromRef(X);
499  }
500  }
501 
502  if (ZeroStartingSolution_) {
503  Y.putScalar(STS::zero());
504  }
505 
506  // Flops are updated in each of the following.
507  switch (PrecType_) {
508  case Ifpack2::Details::JACOBI:
509  ApplyInverseJacobi(*X_copy, Y);
510  break;
511  case Ifpack2::Details::GS:
512  ApplyInverseGS(*X_copy, Y);
513  break;
514  case Ifpack2::Details::SGS:
515  ApplyInverseSGS(*X_copy, Y);
516  break;
517  case Ifpack2::Details::MTSPLITJACOBI:
518  // note: for this method, the container is always BlockTriDi
519  Container_->applyInverseJacobi(*X_copy, Y, DampingFactor_, ZeroStartingSolution_, NumSweeps_);
520  break;
521  default:
522  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
523  "Ifpack2::BlockRelaxation::apply: Invalid "
524  "PrecType_ enum value "
525  << PrecType_ << ". Valid values are Ifpack2::"
526  "Details::JACOBI = "
527  << Ifpack2::Details::JACOBI << ", Ifpack2::Details"
528  "::GS = "
529  << Ifpack2::Details::GS << ", and Ifpack2::Details::SGS = "
530  << Ifpack2::Details::SGS << ". Please report this bug to the Ifpack2 "
531  "developers.");
532  }
533  }
534 
535  ApplyTime_ += (time.wallTime() - startTime);
536  ++NumApply_;
537 }
538 
539 template <class MatrixType, class ContainerType>
541  applyMat(const Tpetra::MultiVector<typename MatrixType::scalar_type,
542  typename MatrixType::local_ordinal_type,
543  typename MatrixType::global_ordinal_type,
544  typename MatrixType::node_type>& X,
545  Tpetra::MultiVector<typename MatrixType::scalar_type,
546  typename MatrixType::local_ordinal_type,
547  typename MatrixType::global_ordinal_type,
548  typename MatrixType::node_type>& Y,
549  Teuchos::ETransp mode) const {
550  A_->apply(X, Y, mode);
551 }
552 
553 template <class MatrixType, class ContainerType>
556  using Teuchos::rcp;
557  typedef Tpetra::RowGraph<local_ordinal_type, global_ordinal_type, node_type>
558  row_graph_type;
559 
560  TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error,
561  "Ifpack2::BlockRelaxation::initialize: "
562  "The matrix is null. You must call setMatrix() with a nonnull matrix "
563  "before you may call this method.");
564 
566  Teuchos::TimeMonitor::getNewCounter("Ifpack2::BlockRelaxation::initialize");
567  double startTime = timer->wallTime();
568 
569  { // Timing of initialize starts here
570  Teuchos::TimeMonitor timeMon(*timer);
571  IsInitialized_ = false;
572 
573  // Check whether we have a BlockCrsMatrix
575  Teuchos::rcp_dynamic_cast<const block_crs_matrix_type>(A_);
576  hasBlockCrsMatrix_ = !A_bcrs.is_null();
577 
578  Teuchos::RCP<const row_graph_type> graph = A_->getGraph();
579 
580  if (!hasBlockCrsMatrix_ && List_.isParameter("relaxation: container") && List_.get<std::string>("relaxation: container") == "BlockTriDi") {
581  IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::convertToBlockCrsMatrix", convertToBlockCrsMatrix);
582  int block_size = List_.get<int>("partitioner: block size");
583  bool use_explicit_conversion = List_.isParameter("partitioner: explicit convert to BlockCrs") && List_.get<bool>("partitioner: explicit convert to BlockCrs");
584  TEUCHOS_TEST_FOR_EXCEPT_MSG(use_explicit_conversion && block_size == -1, "A pointwise matrix and block_size = -1 were given as inputs.");
585  bool use_LID = !List_.isParameter("partitioner: use LIDs") || List_.get<bool>("partitioner: use LIDs");
586  bool check_block_consistency = !List_.isParameter("partitioner: checkBlockConsistency") || List_.get<bool>("partitioner: checkBlockConsistency");
587 
588  if ((use_LID || !use_explicit_conversion) && check_block_consistency) {
589  if (!A_->getGraph()->getImporter().is_null()) {
590  TEUCHOS_TEST_FOR_EXCEPT_MSG(!Tpetra::Import_Util::checkBlockConsistency(*(A_->getGraph()->getColMap()), block_size),
591  "The pointwise graph of the input matrix A pointwise is not consistent with block_size.");
592  }
593  }
594  if (use_explicit_conversion) {
595  A_bcrs = Tpetra::convertToBlockCrsMatrix(*Teuchos::rcp_dynamic_cast<const crs_matrix_type>(A_), block_size, use_LID);
596  A_ = A_bcrs;
597  hasBlockCrsMatrix_ = true;
598  graph = A_->getGraph();
599  } else {
600  graph = Tpetra::getBlockCrsGraph(*Teuchos::rcp_dynamic_cast<const crs_matrix_type>(A_), block_size, true);
601  }
602  IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
603  }
604 
605  NumLocalRows_ = A_->getLocalNumRows();
606  NumGlobalRows_ = A_->getGlobalNumRows();
607  NumGlobalNonzeros_ = A_->getGlobalNumEntries();
608 
609  // NTS: Will need to add support for Zoltan2 partitions later Also,
610  // will need a better way of handling the Graph typing issue.
611  // Especially with ordinal types w.r.t the container.
612  Partitioner_ = Teuchos::null;
613 
614  if (PartitionerType_ == "linear") {
615  IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::linear", linear);
616  Partitioner_ =
618  IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
619  } else if (PartitionerType_ == "line") {
620  IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::line", line);
621  Partitioner_ =
623  IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
624  } else if (PartitionerType_ == "user") {
625  IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::user", user);
626  Partitioner_ =
628  IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
629  } else if (PartitionerType_ == "zoltan2") {
630  IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::zoltan2", zoltan2);
631 #if defined(HAVE_IFPACK2_ZOLTAN2)
632  if (graph->getComm()->getSize() == 1) {
633  // Only one MPI, so call zoltan2 with global graph
634  Partitioner_ =
635  rcp(new Ifpack2::Zoltan2Partitioner<row_graph_type>(graph));
636  } else {
637  // Form local matrix to get local graph for calling zoltan2
639  Partitioner_ =
640  rcp(new Ifpack2::Zoltan2Partitioner<row_graph_type>(A_local->getGraph()));
641  }
642 #else
643  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Ifpack2::BlockRelaxation::initialize: Zoltan2 not enabled.");
644 #endif
645  IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
646  } else {
647  // We should have checked for this in setParameters(), so it's a
648  // logic_error, not an invalid_argument or runtime_error.
649  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
650  "Ifpack2::BlockRelaxation::initialize: Unknown "
651  "partitioner type "
652  << PartitionerType_ << ". Valid values are "
653  "\"linear\", \"line\", and \"user\".");
654  }
655 
656  // need to partition the graph of A
657  {
658  IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::Partitioner", Partitioner);
659  Partitioner_->setParameters(List_);
660  Partitioner_->compute();
661  IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
662  }
663 
664  // get actual number of partitions
665  NumLocalBlocks_ = Partitioner_->numLocalParts();
666 
667  // Note: Unlike Ifpack, we'll punt on computing W_ until compute(), which is where
668  // we assume that the type of relaxation has been chosen.
669 
670  if (A_->getComm()->getSize() != 1) {
671  IsParallel_ = true;
672  } else {
673  IsParallel_ = false;
674  }
675 
676  // We should have checked for this in setParameters(), so it's a
677  // logic_error, not an invalid_argument or runtime_error.
678  TEUCHOS_TEST_FOR_EXCEPTION(NumSweeps_ < 0, std::logic_error,
679  "Ifpack2::BlockRelaxation::initialize: "
680  "NumSweeps_ = "
681  << NumSweeps_ << " < 0.");
682 
683  // Extract the submatrices
684  {
685  IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::ExtractSubmatricesStructure", ExtractSubmatricesStructure);
686  ExtractSubmatricesStructure();
687  IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
688  }
689 
690  // Compute the weight vector if we're doing overlapped Jacobi (and
691  // only if we're doing overlapped Jacobi).
692  if (PrecType_ == Ifpack2::Details::JACOBI && OverlapLevel_ > 0) {
693  TEUCHOS_TEST_FOR_EXCEPTION(hasBlockCrsMatrix_, std::runtime_error,
694  "Ifpack2::BlockRelaxation::initialize: "
695  "We do not support overlapped Jacobi yet for Tpetra::BlockCrsMatrix. Sorry!");
696 
697  // weight of each vertex
698  W_ = rcp(new vector_type(A_->getRowMap()));
699  W_->putScalar(STS::zero());
700  {
701  Teuchos::ArrayRCP<scalar_type> w_ptr = W_->getDataNonConst(0);
702 
703  for (local_ordinal_type i = 0; i < NumLocalBlocks_; ++i) {
704  for (size_t j = 0; j < Partitioner_->numRowsInPart(i); ++j) {
705  local_ordinal_type LID = (*Partitioner_)(i, j);
706  w_ptr[LID] += STS::one();
707  }
708  }
709  }
710  // communicate to sum together W_[k]'s (# of blocks/patches) that update
711  // kth dof) and have this information in overlapped/extended vector.
712  // only needed when Schwarz combine mode is ADD as opposed to ZERO (which is RAS)
713 
714  if (schwarzCombineMode_ == "ADD") {
715  IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::ADD", ADD);
716  typedef Tpetra::MultiVector<typename MatrixType::scalar_type, typename MatrixType::local_ordinal_type, typename MatrixType::global_ordinal_type, typename MatrixType::node_type> scMV;
717  Teuchos::RCP<const import_type> theImport = A_->getGraph()->getImporter();
718  if (!theImport.is_null()) {
719  scMV nonOverLapW(theImport->getSourceMap(), 1, false);
720  Teuchos::ArrayRCP<scalar_type> w_ptr = W_->getDataNonConst(0);
721  Teuchos::ArrayRCP<scalar_type> nonOverLapWArray = nonOverLapW.getDataNonConst(0);
722  nonOverLapW.putScalar(STS::zero());
723  for (int ii = 0; ii < (int)theImport->getSourceMap()->getLocalNumElements(); ii++) nonOverLapWArray[ii] = w_ptr[ii];
724  nonOverLapWArray = Teuchos::null;
725  w_ptr = Teuchos::null;
726  nonOverLapW.doExport(*W_, *theImport, Tpetra::ADD);
727  W_->doImport(nonOverLapW, *theImport, Tpetra::INSERT);
728  }
729  IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
730  }
731  W_->reciprocal(*W_);
732  }
733  } // timing of initialize stops here
734 
735  InitializeTime_ += (timer->wallTime() - startTime);
736  ++NumInitialize_;
737  IsInitialized_ = true;
738 }
739 
740 template <class MatrixType, class ContainerType>
743  using Teuchos::rcp;
744 
745  TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error,
746  "Ifpack2::BlockRelaxation::compute: "
747  "The matrix is null. You must call setMatrix() with a nonnull matrix, "
748  "then call initialize(), before you may call this method.");
749 
750  if (!isInitialized()) {
751  initialize();
752  }
753 
755  Teuchos::TimeMonitor::getNewCounter("Ifpack2::BlockRelaxation::compute");
756 
757  double startTime = timer->wallTime();
758 
759  {
760  Teuchos::TimeMonitor timeMon(*timer);
761 
762  // reset values
763  IsComputed_ = false;
764 
765  Container_->compute(); // compute each block matrix
766  }
767 
768  ComputeTime_ += (timer->wallTime() - startTime);
769  ++NumCompute_;
770  IsComputed_ = true;
771 }
772 
773 template <class MatrixType, class ContainerType>
776  TEUCHOS_TEST_FOR_EXCEPTION(Partitioner_.is_null(), std::runtime_error,
777  "Ifpack2::BlockRelaxation::"
778  "ExtractSubmatricesStructure: Partitioner object is null.");
779 
780  std::string containerType = ContainerType::getName();
781  if (containerType == "Generic") {
782  // ContainerType is Container<row_matrix_type>. Thus, we need to
783  // get the container name from the parameter list. We use "TriDi"
784  // as the default container type.
785  containerType = containerType_;
786  }
787  // Whether the Container will define blocks (partitions)
788  // in terms of individual DOFs, and not by nodes (blocks).
789  bool pointIndexed = decouple_ && hasBlockCrsMatrix_;
791  if (decouple_) {
792  // dofs [per node] is how many blocks each partition will be split into
793  auto A_bcrs = Teuchos::rcp_dynamic_cast<const block_crs_matrix_type>(A_);
794  local_ordinal_type dofs = hasBlockCrsMatrix_ ? A_bcrs->getBlockSize() : List_.get<int>("partitioner: PDE equations");
795  blockRows.resize(NumLocalBlocks_ * dofs);
796  if (hasBlockCrsMatrix_) {
797  for (local_ordinal_type i = 0; i < NumLocalBlocks_; i++) {
798  size_t blockSize = Partitioner_->numRowsInPart(i);
799  // block i will be split into j different blocks,
800  // each corresponding to a different dof
801  for (local_ordinal_type j = 0; j < dofs; j++) {
802  local_ordinal_type blockIndex = i * dofs + j;
803  blockRows[blockIndex].resize(blockSize);
804  for (size_t k = 0; k < blockSize; k++) {
805  // here, the row and dof are combined to get the point index
806  //(what the row would be if A were a CrsMatrix)
807  blockRows[blockIndex][k] = (*Partitioner_)(i, k) * dofs + j;
808  }
809  }
810  }
811  } else {
812  // Rows in each partition are distributed round-robin to the blocks -
813  // that's how MueLu stores DOFs in a non-block matrix
814  for (local_ordinal_type i = 0; i < NumLocalBlocks_; i++) {
815  //#ifdef HAVE_IFPACK2_DEBUG
816  TEUCHOS_TEST_FOR_EXCEPTION(Partitioner_->numRowsInPart(i) % dofs != 0, std::logic_error,
817  "Expected size of all blocks (partitions) to be divisible by MueLu dofs/node.");
818  size_t blockSize = Partitioner_->numRowsInPart(i) / dofs;
819  //#endif
820  // block i will be split into j different blocks,
821  // each corresponding to a different dof
822  for (local_ordinal_type j = 0; j < dofs; j++) {
823  local_ordinal_type blockIndex = i * dofs + j;
824  blockRows[blockIndex].resize(blockSize);
825  for (size_t k = 0; k < blockSize; k++) {
826  blockRows[blockIndex][k] = (*Partitioner_)(i, k * dofs + j);
827  }
828  }
829  }
830  }
831  } else {
832  // No decoupling - just get the rows directly from Partitioner
833  blockRows.resize(NumLocalBlocks_);
834  for (local_ordinal_type i = 0; i < NumLocalBlocks_; ++i) {
835  const size_t numRows = Partitioner_->numRowsInPart(i);
836  blockRows[i].resize(numRows);
837  // Extract a list of the indices of each partitioner row.
838  for (size_t j = 0; j < numRows; ++j) {
839  blockRows[i][j] = (*Partitioner_)(i, j);
840  }
841  }
842  }
843  // right before constructing the
844  Container_ = ContainerFactory<MatrixType>::build(containerType, A_, blockRows, Importer_, pointIndexed);
845  Container_->setParameters(List_);
846  Container_->initialize();
847 }
848 
849 template <class MatrixType, class ContainerType>
850 void BlockRelaxation<MatrixType, ContainerType>::
851  ApplyInverseJacobi(const MV& X, MV& Y) const {
852  const size_t NumVectors = X.getNumVectors();
853 
854  MV AY(Y.getMap(), NumVectors);
855 
856  // Initial matvec not needed
857  int starting_iteration = 0;
858  if (OverlapLevel_ > 0) {
859  // Overlapping jacobi, with view of W_
860  auto WView = W_->getLocalViewHost(Tpetra::Access::ReadOnly);
861  if (ZeroStartingSolution_) {
862  auto XView = X.getLocalViewHost(Tpetra::Access::ReadOnly);
863  auto YView = Y.getLocalViewHost(Tpetra::Access::ReadWrite);
864  Container_->DoOverlappingJacobi(XView, YView, WView, DampingFactor_, nonsymCombine_);
865  starting_iteration = 1;
866  }
867  const scalar_type ONE = STS::one();
868  for (int j = starting_iteration; j < NumSweeps_; j++) {
869  applyMat(Y, AY);
870  AY.update(ONE, X, -ONE);
871  {
872  auto AYView = AY.getLocalViewHost(Tpetra::Access::ReadOnly);
873  auto YView = Y.getLocalViewHost(Tpetra::Access::ReadWrite);
874  Container_->DoOverlappingJacobi(AYView, YView, WView, DampingFactor_, nonsymCombine_);
875  }
876  }
877  } else {
878  // Non-overlapping
879  if (ZeroStartingSolution_) {
880  auto XView = X.getLocalViewHost(Tpetra::Access::ReadOnly);
881  auto YView = Y.getLocalViewHost(Tpetra::Access::ReadWrite);
882  Container_->DoJacobi(XView, YView, DampingFactor_);
883  starting_iteration = 1;
884  }
885  const scalar_type ONE = STS::one();
886  for (int j = starting_iteration; j < NumSweeps_; j++) {
887  applyMat(Y, AY);
888  AY.update(ONE, X, -ONE);
889  {
890  auto AYView = AY.getLocalViewHost(Tpetra::Access::ReadOnly);
891  auto YView = Y.getLocalViewHost(Tpetra::Access::ReadWrite);
892  Container_->DoJacobi(AYView, YView, DampingFactor_);
893  }
894  }
895  }
896 }
897 
898 template <class MatrixType, class ContainerType>
899 void BlockRelaxation<MatrixType, ContainerType>::
900  ApplyInverseGS(const MV& X, MV& Y) const {
901  using Teuchos::Ptr;
902  using Teuchos::ptr;
903  size_t numVecs = X.getNumVectors();
904  // Get view of X (is never modified in this function)
905  auto XView = X.getLocalViewHost(Tpetra::Access::ReadOnly);
906  auto YView = Y.getLocalViewHost(Tpetra::Access::ReadWrite);
907  // Pre-import Y, if parallel
908  Ptr<MV> Y2;
909  bool deleteY2 = false;
910  if (IsParallel_) {
911  Y2 = ptr(new MV(Importer_->getTargetMap(), numVecs));
912  deleteY2 = true;
913  } else
914  Y2 = ptr(&Y);
915  if (IsParallel_) {
916  for (int j = 0; j < NumSweeps_; ++j) {
917  // do import once per sweep
918  Y2->doImport(Y, *Importer_, Tpetra::INSERT);
919  auto Y2View = Y2->getLocalViewHost(Tpetra::Access::ReadWrite);
920  Container_->DoGaussSeidel(XView, YView, Y2View, DampingFactor_);
921  }
922  } else {
923  auto Y2View = Y2->getLocalViewHost(Tpetra::Access::ReadWrite);
924  for (int j = 0; j < NumSweeps_; ++j) {
925  Container_->DoGaussSeidel(XView, YView, Y2View, DampingFactor_);
926  }
927  }
928  if (deleteY2)
929  delete Y2.get();
930 }
931 
932 template <class MatrixType, class ContainerType>
933 void BlockRelaxation<MatrixType, ContainerType>::
934  ApplyInverseSGS(const MV& X, MV& Y) const {
935  using Teuchos::Ptr;
936  using Teuchos::ptr;
937  // Get view of X (is never modified in this function)
938  auto XView = X.getLocalViewHost(Tpetra::Access::ReadOnly);
939  auto YView = Y.getLocalViewHost(Tpetra::Access::ReadWrite);
940  // Pre-import Y, if parallel
941  Ptr<MV> Y2;
942  bool deleteY2 = false;
943  if (IsParallel_) {
944  Y2 = ptr(new MV(Importer_->getTargetMap(), X.getNumVectors()));
945  deleteY2 = true;
946  } else
947  Y2 = ptr(&Y);
948  if (IsParallel_) {
949  for (int j = 0; j < NumSweeps_; ++j) {
950  // do import once per sweep
951  Y2->doImport(Y, *Importer_, Tpetra::INSERT);
952  auto Y2View = Y2->getLocalViewHost(Tpetra::Access::ReadWrite);
953  Container_->DoSGS(XView, YView, Y2View, DampingFactor_);
954  }
955  } else {
956  auto Y2View = Y2->getLocalViewHost(Tpetra::Access::ReadWrite);
957  for (int j = 0; j < NumSweeps_; ++j) {
958  Container_->DoSGS(XView, YView, Y2View, DampingFactor_);
959  }
960  }
961  if (deleteY2)
962  delete Y2.get();
963 }
964 
965 template <class MatrixType, class ContainerType>
966 void BlockRelaxation<MatrixType, ContainerType>::computeImporter() const {
967  using Teuchos::Array;
968  using Teuchos::ArrayView;
969  using Teuchos::Comm;
970  using Teuchos::Ptr;
971  using Teuchos::RCP;
972  using Teuchos::rcp;
973  using Teuchos::rcp_dynamic_cast;
974  if (IsParallel_) {
975  if (hasBlockCrsMatrix_) {
976  const RCP<const block_crs_matrix_type> bcrs =
977  rcp_dynamic_cast<const block_crs_matrix_type>(A_);
978  int bs_ = bcrs->getBlockSize();
979  RCP<const map_type> oldDomainMap = A_->getDomainMap();
980  RCP<const map_type> oldColMap = A_->getColMap();
981  // Because A is a block CRS matrix, import will not do what you think it does
982  // We have to construct the correct maps for it
983  global_size_t numGlobalElements = oldColMap->getGlobalNumElements() * bs_;
984  global_ordinal_type indexBase = oldColMap->getIndexBase();
985  RCP<const Comm<int>> comm = oldColMap->getComm();
986  ArrayView<const global_ordinal_type> oldColElements = oldColMap->getLocalElementList();
987  Array<global_ordinal_type> newColElements(bs_ * oldColElements.size());
988  for (int i = 0; i < oldColElements.size(); i++) {
989  for (int j = 0; j < bs_; j++)
990  newColElements[i * bs_ + j] = oldColElements[i] * bs_ + j;
991  }
992  RCP<map_type> colMap(new map_type(numGlobalElements, newColElements, indexBase, comm));
993  // Create the importer
994  Importer_ = rcp(new import_type(oldDomainMap, colMap));
995  } else if (!A_.is_null()) {
996  Importer_ = A_->getGraph()->getImporter();
997  if (Importer_.is_null())
998  Importer_ = rcp(new import_type(A_->getDomainMap(), A_->getColMap()));
999  }
1000  }
1001  // otherwise, Importer_ is not needed and is left NULL
1002 }
1003 
1004 template <class MatrixType, class ContainerType>
1005 std::string
1007  description() const {
1008  std::ostringstream out;
1009 
1010  // Output is a valid YAML dictionary in flow style. If you don't
1011  // like everything on a single line, you should call describe()
1012  // instead.
1013  out << "\"Ifpack2::BlockRelaxation\": {";
1014  if (this->getObjectLabel() != "") {
1015  out << "Label: \"" << this->getObjectLabel() << "\", ";
1016  }
1017  // out << "Initialized: " << (isInitialized () ? "true" : "false") << ", ";
1018  // out << "Computed: " << (isComputed () ? "true" : "false") << ", ";
1019  if (A_.is_null()) {
1020  out << "Matrix: null, ";
1021  } else {
1022  // out << "Matrix: not null"
1023  // << ", Global matrix dimensions: ["
1024  out << "Global matrix dimensions: ["
1025  << A_->getGlobalNumRows() << ", " << A_->getGlobalNumCols() << "], ";
1026  }
1027 
1028  // It's useful to print this instance's relaxation method. If you
1029  // want more info than that, call describe() instead.
1030  out << "\"relaxation: type\": ";
1031  if (PrecType_ == Ifpack2::Details::JACOBI) {
1032  out << "Block Jacobi";
1033  } else if (PrecType_ == Ifpack2::Details::GS) {
1034  out << "Block Gauss-Seidel";
1035  } else if (PrecType_ == Ifpack2::Details::SGS) {
1036  out << "Block Symmetric Gauss-Seidel";
1037  } else if (PrecType_ == Ifpack2::Details::MTSPLITJACOBI) {
1038  out << "MT Split Jacobi";
1039  } else {
1040  out << "INVALID";
1041  }
1042 
1043  // BlockCrs if we have that
1044  if (hasBlockCrsMatrix_)
1045  out << ", BlockCrs";
1046 
1047  // Print the approximate # rows per part
1048  int approx_rows_per_part = A_->getLocalNumRows() / Partitioner_->numLocalParts();
1049  out << ", blocksize: " << approx_rows_per_part;
1050 
1051  out << ", overlap: " << OverlapLevel_;
1052 
1053  out << ", "
1054  << "sweeps: " << NumSweeps_ << ", "
1055  << "damping factor: " << DampingFactor_ << ", ";
1056 
1057  std::string containerType = ContainerType::getName();
1058  out << "block container: " << ((containerType == "Generic") ? containerType_ : containerType);
1059  if (List_.isParameter("partitioner: PDE equations"))
1060  out << ", dofs/node: " << List_.get<int>("partitioner: PDE equations");
1061 
1062  out << "}";
1063  return out.str();
1064 }
1065 
1066 template <class MatrixType, class ContainerType>
1069  const Teuchos::EVerbosityLevel verbLevel) const {
1070  using std::endl;
1071  using std::setw;
1073  using Teuchos::VERB_DEFAULT;
1074  using Teuchos::VERB_EXTREME;
1075  using Teuchos::VERB_HIGH;
1076  using Teuchos::VERB_LOW;
1077  using Teuchos::VERB_MEDIUM;
1078  using Teuchos::VERB_NONE;
1079 
1080  Teuchos::EVerbosityLevel vl = verbLevel;
1081  if (vl == VERB_DEFAULT) vl = VERB_LOW;
1082  const int myImageID = A_->getComm()->getRank();
1083 
1084  // Convention requires that describe() begin with a tab.
1085  Teuchos::OSTab tab(out);
1086 
1087  // none: print nothing
1088  // low: print O(1) info from node 0
1089  // medium:
1090  // high:
1091  // extreme:
1092  if (vl != VERB_NONE && myImageID == 0) {
1093  out << "Ifpack2::BlockRelaxation<"
1094  << TypeNameTraits<MatrixType>::name() << ", "
1095  << TypeNameTraits<ContainerType>::name() << " >:";
1096  Teuchos::OSTab tab1(out);
1097 
1098  if (this->getObjectLabel() != "") {
1099  out << "label: \"" << this->getObjectLabel() << "\"" << endl;
1100  }
1101  out << "initialized: " << (isInitialized() ? "true" : "false") << endl
1102  << "computed: " << (isComputed() ? "true" : "false") << endl;
1103 
1104  std::string precType;
1105  if (PrecType_ == Ifpack2::Details::JACOBI) {
1106  precType = "Block Jacobi";
1107  } else if (PrecType_ == Ifpack2::Details::GS) {
1108  precType = "Block Gauss-Seidel";
1109  } else if (PrecType_ == Ifpack2::Details::SGS) {
1110  precType = "Block Symmetric Gauss-Seidel";
1111  }
1112  out << "type: " << precType << endl
1113  << "global number of rows: " << A_->getGlobalNumRows() << endl
1114  << "global number of columns: " << A_->getGlobalNumCols() << endl
1115  << "number of sweeps: " << NumSweeps_ << endl
1116  << "damping factor: " << DampingFactor_ << endl
1117  << "nonsymmetric overlap combine" << nonsymCombine_ << endl
1118  << "backwards mode: "
1119  << ((PrecType_ == Ifpack2::Details::GS && DoBackwardGS_) ? "true" : "false")
1120  << endl
1121  << "zero starting solution: "
1122  << (ZeroStartingSolution_ ? "true" : "false") << endl;
1123  }
1124 }
1125 
1126 } // namespace Ifpack2
1127 
1128 // Macro that does explicit template instantiation (ETI) for
1129 // Ifpack2::BlockRelaxation. S, LO, GO, N correspond to the four
1130 // template parameters of Ifpack2::Preconditioner and
1131 // Tpetra::RowMatrix.
1132 //
1133 // We only instantiate for MatrixType = Tpetra::RowMatrix. There's no
1134 // need to instantiate for Tpetra::CrsMatrix too. All Ifpack2
1135 // preconditioners can and should do dynamic casts if they need a type
1136 // more specific than RowMatrix. This keeps build time short and
1137 // library and executable sizes small.
1138 
1139 #ifdef HAVE_IFPACK2_EXPLICIT_INSTANTIATION
1140 
1141 #define IFPACK2_BLOCKRELAXATION_INSTANT(S, LO, GO, N) \
1142  template class Ifpack2::BlockRelaxation< \
1143  Tpetra::RowMatrix<S, LO, GO, N>, \
1144  Ifpack2::Container<Tpetra::RowMatrix<S, LO, GO, N>>>;
1145 
1146 #endif // HAVE_IFPACK2_EXPLICIT_INSTANTIATION
1147 
1148 #endif // IFPACK2_BLOCKRELAXATION_DEF_HPP
Ifpack2::BlockRelaxation class declaration.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
The communicator over which the input matrix is distributed.
Definition: Ifpack2_BlockRelaxation_def.hpp:327
ParameterList & disableRecursiveValidation()
std::string description() const
A one-line description of this object.
Definition: Ifpack2_BlockRelaxation_def.hpp:1007
double getApplyTime() const
Returns the time spent in apply().
Definition: Ifpack2_BlockRelaxation_def.hpp:411
T & get(const std::string &name, T def_value)
static RCP< Time > getNewCounter(const std::string &name)
static RCP< Time > lookupCounter(const std::string &name)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
int getNumApply() const
Returns the number of calls to apply().
Definition: Ifpack2_BlockRelaxation_def.hpp:390
void getParameter(const Teuchos::ParameterList &params, const std::string &name, T &value)
Set a value from a ParameterList if a parameter with the specified name exists.
Definition: Ifpack2_Parameters.hpp:26
Teuchos::RCP< const map_type > getRangeMap() const
Returns the Tpetra::Map object associated with the range of this operator.
Definition: Ifpack2_BlockRelaxation_def.hpp:362
int getNumCompute() const
Returns the number of calls to compute().
Definition: Ifpack2_BlockRelaxation_def.hpp:384
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
void setParameters(const Teuchos::ParameterList &params)
Sets all the parameters for the preconditioner.
Definition: Ifpack2_BlockRelaxation_def.hpp:156
void compute()
compute the preconditioner for the specified matrix, diagonal perturbation thresholds and relaxation ...
Definition: Ifpack2_BlockRelaxation_def.hpp:742
Block relaxation preconditioners (or smoothers) for Tpetra::RowMatrix and Tpetra::CrsMatrix sparse ma...
Definition: Ifpack2_BlockRelaxation_decl.hpp:49
double getInitializeTime() const
Returns the time spent in initialize().
Definition: Ifpack2_BlockRelaxation_def.hpp:397
Declaration of a user-defined partitioner in which the user can define a partition of the graph...
Ifpack2::Partitioner:
Definition: Ifpack2_Partitioner.hpp:146
bool isParameter(const std::string &name) const
T * getRawPtr() const
bool remove(std::string const &name, bool throwIfNotExists=true)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
#define TEUCHOS_TEST_FOR_EXCEPT_MSG(throw_exception_test, msg)
double getComputeTime() const
Returns the time spent in compute().
Definition: Ifpack2_BlockRelaxation_def.hpp:404
size_t getNodeSmootherComplexity() const
Get a rough estimate of cost per iteration.
Definition: Ifpack2_BlockRelaxation_def.hpp:416
virtual void setMatrix(const Teuchos::RCP< const row_matrix_type > &A)
Change the matrix to be preconditioned.
Definition: Ifpack2_BlockRelaxation_def.hpp:31
virtual ~BlockRelaxation()
Destructor.
Definition: Ifpack2_BlockRelaxation_def.hpp:91
Teuchos::RCP< const map_type > getDomainMap() const
Returns the Tpetra::Map object associated with the domain of this operator.
Definition: Ifpack2_BlockRelaxation_def.hpp:349
Partition in which the user can define a nonoverlapping partition of the graph in any way they choose...
Definition: Ifpack2_Details_UserPartitioner_decl.hpp:36
void resize(size_type new_size, const value_type &x=value_type())
int getNumInitialize() const
Returns the number of calls to initialize().
Definition: Ifpack2_BlockRelaxation_def.hpp:378
void initialize()
Initialize.
Definition: Ifpack2_BlockRelaxation_def.hpp:555
void validateParameters(ParameterList const &validParamList, int const depth=1000, EValidateUsed const validateUsed=VALIDATE_USED_ENABLED, EValidateDefaults const validateDefaults=VALIDATE_DEFAULTS_ENABLED) const
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Print the object with some verbosity level to an FancyOStream object.
Definition: Ifpack2_BlockRelaxation_def.hpp:1068
MatrixType::local_ordinal_type local_ordinal_type
The type of local indices in the input MatrixType.
Definition: Ifpack2_BlockRelaxation_decl.hpp:65
void applyMat(const MV &X, MV &Y, Teuchos::ETransp mode=Teuchos::NO_TRANS) const
Applies the matrix to a Tpetra::MultiVector.
Definition: Ifpack2_BlockRelaxation_def.hpp:541
MatrixType::scalar_type scalar_type
The type of the entries of the input MatrixType.
Definition: Ifpack2_BlockRelaxation_decl.hpp:62
bool isType(const std::string &name) const
ParameterList & sublist(const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
Access only local rows and columns of a sparse matrix.
Definition: Ifpack2_LocalFilter_decl.hpp:127
static double wallTime()
static Teuchos::RCP< BaseContainer > build(std::string containerType, const Teuchos::RCP< const MatrixType > &A, const Teuchos::Array< Teuchos::Array< local_ordinal_type >> &partitions, const Teuchos::RCP< const import_type > importer, bool pointIndexed)
Build a specialization of Ifpack2::Container given a key that has been registered.
Definition: Ifpack2_ContainerFactory_def.hpp:54
Teuchos::RCP< const row_matrix_type > getMatrix() const
The input matrix of this preconditioner&#39;s constructor.
Definition: Ifpack2_BlockRelaxation_def.hpp:340
void getValidParameters(Teuchos::ParameterList &params)
Fills a list which contains all the parameters possibly used by Ifpack2.
Definition: Ifpack2_Parameters.cpp:18
Ifpack2::LinePartitioner: A class to define partitions into a set of lines.
Definition: Ifpack2_LinePartitioner_decl.hpp:45
A class to define linear partitions.
Definition: Ifpack2_LinearPartitioner_decl.hpp:27
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Return a list of all the parameters that this class accepts.
Definition: Ifpack2_BlockRelaxation_def.hpp:96
void apply(const MV &X, MV &Y, Teuchos::ETransp mode=Teuchos::NO_TRANS, scalar_type alpha=Teuchos::ScalarTraits< scalar_type >::one(), scalar_type beta=Teuchos::ScalarTraits< scalar_type >::zero()) const
Applies the preconditioner to X, returns the result in Y.
Definition: Ifpack2_BlockRelaxation_def.hpp:433
BlockRelaxation(const Teuchos::RCP< const row_matrix_type > &Matrix)
Constructor.
Definition: Ifpack2_BlockRelaxation_def.hpp:58
bool is_null() const