Ifpack2 Templated Preconditioning Package  Version 1.0
Ifpack2_LocalSparseTriangularSolver_def.hpp
1 /*@HEADER
2 // ***********************************************************************
3 //
4 // Ifpack2: Templated Object-Oriented Algebraic Preconditioner Package
5 // Copyright (2009) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 //@HEADER
41 */
42 
43 #ifndef IFPACK2_LOCALSPARSETRIANGULARSOLVER_DEF_HPP
44 #define IFPACK2_LOCALSPARSETRIANGULARSOLVER_DEF_HPP
45 
46 #include "Tpetra_CrsMatrix.hpp"
47 #include "Tpetra_DefaultPlatform.hpp"
48 #include "Teuchos_StandardParameterEntryValidators.hpp"
49 
50 #ifdef HAVE_IFPACK2_SHYLUHTS
51 # include "shylu_hts.hpp"
52 #endif
53 
54 namespace Ifpack2 {
55 
56 namespace Details {
57 struct TrisolverType {
58  enum Enum {
59  Internal,
60  HTS
61  };
62 
63  static void loadPLTypeOption (Teuchos::Array<std::string>& type_strs, Teuchos::Array<Enum>& type_enums) {
64  type_strs.resize(2);
65  type_strs[0] = "Internal";
66  type_strs[1] = "HTS";
67  type_enums.resize(2);
68  type_enums[0] = Internal;
69  type_enums[1] = HTS;
70  }
71 };
72 }
73 
74 template<class MatrixType>
75 class LocalSparseTriangularSolver<MatrixType>::HtsImpl {
76 public:
77  typedef Tpetra::CrsMatrix<scalar_type, local_ordinal_type, global_ordinal_type, node_type> crs_matrix_type;
78 
79  void reset () {
80 #ifdef HAVE_IFPACK2_SHYLUHTS
81  Timpl_ = Teuchos::null;
82  levelset_block_size_ = 1;
83 #endif
84  }
85 
86  void setParameters (const Teuchos::ParameterList& pl) {
87 #ifdef HAVE_IFPACK2_SHYLUHTS
88  const char* block_size_s = "trisolver: block size";
89  if (pl.isParameter(block_size_s)) {
90  TEUCHOS_TEST_FOR_EXCEPT_MSG( ! pl.isType<int>(block_size_s),
91  "The parameter \"" << block_size_s << "\" must be of type int.");
92  levelset_block_size_ = pl.get<int>(block_size_s);
93  }
94  if (levelset_block_size_ < 1)
95  levelset_block_size_ = 1;
96 #endif
97  }
98 
99  // HTS has the phases symbolic+numeric, numeric, and apply. Hence the first
100  // call to compute() will trigger the symbolic+numeric phase, and subsequent
101  // calls (with the same Timpl_) will trigger the numeric phase. In the call to
102  // initialize(), essentially nothing happens.
103  void initialize (const crs_matrix_type& /* unused */) {
104 #ifdef HAVE_IFPACK2_SHYLUHTS
105  reset();
106  transpose_ = conjugate_ = false;
107 #endif
108  }
109 
110  void compute (const crs_matrix_type& T_in, const Teuchos::RCP<Teuchos::FancyOStream>& out) {
111 #ifdef HAVE_IFPACK2_SHYLUHTS
112  using Teuchos::ArrayRCP;
113 
114  Teuchos::ArrayRCP<const size_t> rowptr;
115  Teuchos::ArrayRCP<const local_ordinal_type> colidx;
116  Teuchos::ArrayRCP<const scalar_type> val;
117  T_in.getAllValues(rowptr, colidx, val);
118 
119  Teuchos::RCP<HtsCrsMatrix> T_hts = Teuchos::rcpWithDealloc(
120  HTST::make_CrsMatrix(rowptr.size() - 1,
121  rowptr.getRawPtr(), colidx.getRawPtr(), val.getRawPtr(),
122  transpose_, conjugate_),
123  HtsCrsMatrixDeleter());
124 
125  if (Teuchos::nonnull(Timpl_)) {
126  // Reuse the nonzero pattern.
127  HTST::reprocess_numeric(Timpl_.get(), T_hts.get());
128  } else {
129  // Build from scratch.
130  if (T_in.getCrsGraph().is_null()) {
131  if (Teuchos::nonnull(out))
132  *out << "HTS compute failed because T_in.getCrsGraph().is_null().\n";
133  return;
134  }
135  if ( ! T_in.getCrsGraph()->isSorted()) {
136  if (Teuchos::nonnull(out))
137  *out << "HTS compute failed because ! T_in.getCrsGraph().isSorted().\n";
138  return;
139  }
140  if ( ! T_in.isStorageOptimized()) {
141  if (Teuchos::nonnull(out))
142  *out << "HTS compute failed because ! T_in.isStorageOptimized().\n";
143  return;
144  }
145 
146  typename HTST::PreprocessArgs args;
147  args.T = T_hts.get();
148  args.max_nrhs = 1;
149  args.nthreads = omp_get_max_threads();
150  args.save_for_reprocess = true;
151  typename HTST::Options opts;
152  opts.levelset_block_size = levelset_block_size_;
153  args.options = &opts;
154 
155  try {
156  Timpl_ = Teuchos::rcpWithDealloc(HTST::preprocess(args), TImplDeleter());
157  } catch (const std::exception& e) {
158  if (Teuchos::nonnull(out))
159  *out << "HTS preprocess threw: " << e.what() << "\n";
160  }
161  }
162 #endif
163  }
164 
165  // HTS may not be able to handle a matrix, so query whether compute()
166  // succeeded.
167  bool isComputed () {
168 #ifdef HAVE_IFPACK2_SHYLUHTS
169  return Teuchos::nonnull(Timpl_);
170 #else
171  return false;
172 #endif
173  }
174 
175  // Y := beta * Y + alpha * (M * X)
176  void localApply (const MV& X, MV& Y,
177  const Teuchos::ETransp mode,
178  const scalar_type& alpha, const scalar_type& beta) const {
179 #ifdef HAVE_IFPACK2_SHYLUHTS
180  const auto& X_view = X.template getLocalView<Kokkos::HostSpace>();
181  const auto& Y_view = Y.template getLocalView<Kokkos::HostSpace>();
182  // Only does something if #rhs > current capacity.
183  HTST::reset_max_nrhs(Timpl_.get(), X_view.dimension_1());
184  // Switch alpha and beta because of HTS's opposite convention.
185  HTST::solve_omp(Timpl_.get(), X_view.data(), X_view.dimension_1(), Y_view.data(), beta, alpha);
186 #endif
187  }
188 
189 private:
190 #ifdef HAVE_IFPACK2_SHYLUHTS
191  typedef ::Experimental::HTS<local_ordinal_type, size_t, scalar_type> HTST;
192  typedef typename HTST::Impl TImpl;
193  typedef typename HTST::CrsMatrix HtsCrsMatrix;
194 
195  struct TImplDeleter {
196  void free (TImpl* impl) {
197  HTST::delete_Impl(impl);
198  }
199  };
200 
201  struct HtsCrsMatrixDeleter {
202  void free (HtsCrsMatrix* T) {
203  HTST::delete_CrsMatrix(T);
204  }
205  };
206 
207  Teuchos::RCP<TImpl> Timpl_;
208  bool transpose_, conjugate_;
209  int levelset_block_size_;
210 #endif
211 };
212 
213 template<class MatrixType>
215 LocalSparseTriangularSolver (const Teuchos::RCP<const row_matrix_type>& A) :
216  A_ (A)
217 {
218  initializeState();
219  typedef typename Tpetra::CrsMatrix<scalar_type, local_ordinal_type,
220  global_ordinal_type, node_type> crs_matrix_type;
221  if (! A.is_null ()) {
222  Teuchos::RCP<const crs_matrix_type> A_crs =
223  Teuchos::rcp_dynamic_cast<const crs_matrix_type> (A);
224  TEUCHOS_TEST_FOR_EXCEPTION
225  (A_crs.is_null (), std::invalid_argument,
226  "Ifpack2::LocalSparseTriangularSolver constructor: "
227  "The input matrix A is not a Tpetra::CrsMatrix.");
228  A_crs_ = A_crs;
229  }
230 }
231 
232 template<class MatrixType>
234 LocalSparseTriangularSolver (const Teuchos::RCP<const row_matrix_type>& A,
235  const Teuchos::RCP<Teuchos::FancyOStream>& out) :
236  A_ (A),
237  out_ (out)
238 {
239  initializeState();
240  if (! out_.is_null ()) {
241  *out_ << ">>> DEBUG Ifpack2::LocalSparseTriangularSolver constructor"
242  << std::endl;
243  }
244  typedef typename Tpetra::CrsMatrix<scalar_type, local_ordinal_type,
245  global_ordinal_type, node_type> crs_matrix_type;
246  if (! A.is_null ()) {
247  Teuchos::RCP<const crs_matrix_type> A_crs =
248  Teuchos::rcp_dynamic_cast<const crs_matrix_type> (A);
249  TEUCHOS_TEST_FOR_EXCEPTION
250  (A_crs.is_null (), std::invalid_argument,
251  "Ifpack2::LocalSparseTriangularSolver constructor: "
252  "The input matrix A is not a Tpetra::CrsMatrix.");
253  A_crs_ = A_crs;
254  }
255 }
256 
257 template<class MatrixType>
260 {
261  initializeState();
262 }
263 
264 template<class MatrixType>
266 LocalSparseTriangularSolver (const bool /* unused */, const Teuchos::RCP<Teuchos::FancyOStream>& out) :
267  out_ (out)
268 {
269  initializeState();
270  if (! out_.is_null ()) {
271  *out_ << ">>> DEBUG Ifpack2::LocalSparseTriangularSolver constructor"
272  << std::endl;
273  }
274 }
275 
276 template<class MatrixType>
278 {
279  isInitialized_ = false;
280  isComputed_ = false;
281  numInitialize_ = 0;
282  numCompute_ = 0;
283  numApply_ = 0;
284  initializeTime_ = 0.0;
285  computeTime_ = 0.0;
286  applyTime_ = 0.0;
287 }
288 
289 template<class MatrixType>
292 {}
293 
294 template<class MatrixType>
295 void
297 setParameters (const Teuchos::ParameterList& pl)
298 {
299  using Teuchos::RCP;
300  using Teuchos::ParameterList;
301  using Teuchos::Array;
302 
303  Details::TrisolverType::Enum trisolverType = Details::TrisolverType::Internal;
304  do {
305  static const char typeName[] = "trisolver: type";
306 
307  if ( ! pl.isType<std::string>(typeName)) break;
308 
309  // Map std::string <-> TrisolverType::Enum.
310  Array<std::string> trisolverTypeStrs;
311  Array<Details::TrisolverType::Enum> trisolverTypeEnums;
312  Details::TrisolverType::loadPLTypeOption (trisolverTypeStrs, trisolverTypeEnums);
313  Teuchos::StringToIntegralParameterEntryValidator<Details::TrisolverType::Enum>
314  s2i(trisolverTypeStrs (), trisolverTypeEnums (), typeName, false);
315 
316  trisolverType = s2i.getIntegralValue(pl.get<std::string>(typeName));
317  } while (0);
318 
319  if (trisolverType == Details::TrisolverType::HTS) {
320  htsImpl_ = Teuchos::rcp (new HtsImpl ());
321  htsImpl_->setParameters (pl);
322  }
323 }
324 
325 template<class MatrixType>
326 void
329 {
330  const char prefix[] = "Ifpack2::LocalSparseTriangularSolver::initialize: ";
331  if (! out_.is_null ()) {
332  *out_ << ">>> DEBUG " << prefix << std::endl;
333  }
334 
335  TEUCHOS_TEST_FOR_EXCEPTION
336  (A_.is_null (), std::runtime_error, prefix << "You must call "
337  "setMatrix() with a nonnull input matrix before you may call "
338  "initialize() or compute().");
339  if (A_crs_.is_null ()) {
340  typedef typename Tpetra::CrsMatrix<scalar_type, local_ordinal_type,
341  global_ordinal_type, node_type> crs_matrix_type;
342  Teuchos::RCP<const crs_matrix_type> A_crs =
343  Teuchos::rcp_dynamic_cast<const crs_matrix_type> (A_);
344  TEUCHOS_TEST_FOR_EXCEPTION
345  (A_crs.is_null (), std::invalid_argument, prefix <<
346  "The input matrix A is not a Tpetra::CrsMatrix.");
347  A_crs_ = A_crs;
348  }
349  auto G = A_->getGraph ();
350  TEUCHOS_TEST_FOR_EXCEPTION
351  (G.is_null (), std::logic_error, prefix << "A_ and A_crs_ are nonnull, "
352  "but A_'s RowGraph G is null. "
353  "Please report this bug to the Ifpack2 developers.");
354  // At this point, the graph MUST be fillComplete. The "initialize"
355  // (symbolic) part of setup only depends on the graph structure, so
356  // the matrix itself need not be fill complete.
357  TEUCHOS_TEST_FOR_EXCEPTION
358  (! G->isFillComplete (), std::runtime_error, "If you call this method, "
359  "the matrix's graph must be fill complete. It is not.");
360 
361  if (Teuchos::nonnull (htsImpl_))
362  htsImpl_->initialize (*A_crs_);
363 
364  isInitialized_ = true;
365  ++numInitialize_;
366 }
367 
368 template<class MatrixType>
369 void
372 {
373  const char prefix[] = "Ifpack2::LocalSparseTriangularSolver::compute: ";
374  if (! out_.is_null ()) {
375  *out_ << ">>> DEBUG " << prefix << std::endl;
376  }
377 
378  TEUCHOS_TEST_FOR_EXCEPTION
379  (A_.is_null (), std::runtime_error, prefix << "You must call "
380  "setMatrix() with a nonnull input matrix before you may call "
381  "initialize() or compute().");
382  TEUCHOS_TEST_FOR_EXCEPTION
383  (A_crs_.is_null (), std::logic_error, prefix << "A_ is nonnull, but "
384  "A_crs_ is null. Please report this bug to the Ifpack2 developers.");
385  // At this point, the matrix MUST be fillComplete.
386  TEUCHOS_TEST_FOR_EXCEPTION
387  (! A_crs_->isFillComplete (), std::runtime_error, "If you call this "
388  "method, the matrix must be fill complete. It is not.");
389 
390  if (! isInitialized_) {
391  initialize ();
392  }
393  TEUCHOS_TEST_FOR_EXCEPTION
394  (! isInitialized_, std::logic_error, prefix << "initialize() should have "
395  "been called by this point, but isInitialized_ is false. "
396  "Please report this bug to the Ifpack2 developers.");
397 
398  if (Teuchos::nonnull (htsImpl_))
399  htsImpl_->compute (*A_crs_, out_);
400 
401  isComputed_ = true;
402  ++numCompute_;
403 }
404 
405 template<class MatrixType>
407 apply (const Tpetra::MultiVector<scalar_type, local_ordinal_type,
409  Tpetra::MultiVector<scalar_type, local_ordinal_type,
411  Teuchos::ETransp mode,
412  scalar_type alpha,
413  scalar_type beta) const
414 {
415  using Teuchos::RCP;
416  using Teuchos::rcp;
417  using Teuchos::rcpFromRef;
418  typedef scalar_type ST;
419  typedef Teuchos::ScalarTraits<ST> STS;
420  const char prefix[] = "Ifpack2::LocalSparseTriangularSolver::apply: ";
421  if (! out_.is_null ()) {
422  *out_ << ">>> DEBUG " << prefix;
423  if (A_crs_.is_null ()) {
424  *out_ << "A_crs_ is null!" << std::endl;
425  }
426  else {
427  const std::string uplo = A_crs_->isUpperTriangular () ? "U" :
428  (A_crs_->isLowerTriangular () ? "L" : "N");
429  const std::string trans = (mode == Teuchos::CONJ_TRANS) ? "C" :
430  (mode == Teuchos::TRANS ? "T" : "N");
431  const std::string diag =
432  (A_crs_->getNodeNumDiags () < A_crs_->getNodeNumRows ()) ? "U" : "N";
433  *out_ << "uplo=\"" << uplo
434  << "\", trans=\"" << trans
435  << "\", diag=\"" << diag << "\"" << std::endl;
436  }
437  }
438 
439  TEUCHOS_TEST_FOR_EXCEPTION
440  (! isComputed (), std::runtime_error, prefix << "If compute() has not yet "
441  "been called, or if you have changed the matrix via setMatrix(), you must "
442  "call compute() before you may call this method.");
443  // If isComputed() is true, it's impossible for the matrix to be
444  // null, or for it not to be a Tpetra::CrsMatrix.
445  TEUCHOS_TEST_FOR_EXCEPTION
446  (A_.is_null (), std::logic_error, prefix << "A_ is null. "
447  "Please report this bug to the Ifpack2 developers.");
448  TEUCHOS_TEST_FOR_EXCEPTION
449  (A_crs_.is_null (), std::logic_error, prefix << "A_crs_ is null. "
450  "Please report this bug to the Ifpack2 developers.");
451  // However, it _is_ possible that the user called resumeFill() on
452  // the matrix, after calling compute(). This is NOT allowed.
453  TEUCHOS_TEST_FOR_EXCEPTION
454  (! A_crs_->isFillComplete (), std::runtime_error, "If you call this "
455  "method, the matrix must be fill complete. It is not. This means that "
456  " you must have called resumeFill() on the matrix before calling apply(). "
457  "This is NOT allowed. Note that this class may use the matrix's data in "
458  "place without copying it. Thus, you cannot change the matrix and expect "
459  "the solver to stay the same. If you have changed the matrix, first call "
460  "fillComplete() on it, then call compute() on this object, before you call"
461  " apply(). You do NOT need to call setMatrix, as long as the matrix "
462  "itself (that is, its address in memory) is the same.");
463 
464  auto G = A_->getGraph ();
465  TEUCHOS_TEST_FOR_EXCEPTION
466  (G.is_null (), std::logic_error, prefix << "A_ and A_crs_ are nonnull, "
467  "but A_'s RowGraph G is null. "
468  "Please report this bug to the Ifpack2 developers.");
469  auto importer = G->getImporter ();
470  auto exporter = G->getExporter ();
471 
472  if (! importer.is_null ()) {
473  if (X_colMap_.is_null () || X_colMap_->getNumVectors () != X.getNumVectors ()) {
474  X_colMap_ = rcp (new MV (importer->getTargetMap (), X.getNumVectors ()));
475  }
476  else {
477  X_colMap_->putScalar (STS::zero ());
478  }
479  // See discussion of Github Issue #672 for why the Import needs to
480  // use the ZERO CombineMode. The case where the Export is
481  // nontrivial is likely never exercised.
482  X_colMap_->doImport (X, *importer, Tpetra::ZERO);
483  }
484  RCP<const MV> X_cur = importer.is_null () ? rcpFromRef (X) :
485  Teuchos::rcp_const_cast<const MV> (X_colMap_);
486 
487  if (! exporter.is_null ()) {
488  if (Y_rowMap_.is_null () || Y_rowMap_->getNumVectors () != Y.getNumVectors ()) {
489  Y_rowMap_ = rcp (new MV (exporter->getSourceMap (), Y.getNumVectors ()));
490  }
491  else {
492  Y_rowMap_->putScalar (STS::zero ());
493  }
494  Y_rowMap_->doExport (Y, *importer, Tpetra::ADD);
495  }
496  RCP<MV> Y_cur = exporter.is_null () ? rcpFromRef (Y) : Y_rowMap_;
497 
498  localApply (*X_cur, *Y_cur, mode, alpha, beta);
499 
500  if (! exporter.is_null ()) {
501  Y.putScalar (STS::zero ());
502  Y.doExport (*Y_cur, *exporter, Tpetra::ADD);
503  }
504 
505  ++numApply_;
506 }
507 
508 template<class MatrixType>
509 void
511 localApply (const MV& X,
512  MV& Y,
513  const Teuchos::ETransp mode,
514  const scalar_type& alpha,
515  const scalar_type& beta) const
516 {
517  if (mode == Teuchos::NO_TRANS && Teuchos::nonnull (htsImpl_) &&
518  htsImpl_->isComputed ()) {
519  htsImpl_->localApply (X, Y, mode, alpha, beta);
520  return;
521  }
522 
523  using Teuchos::RCP;
524  typedef scalar_type ST;
525  typedef Teuchos::ScalarTraits<ST> STS;
526 
527  if (beta == STS::zero ()) {
528  if (alpha == STS::zero ()) {
529  Y.putScalar (STS::zero ()); // Y := 0 * Y (ignore contents of Y)
530  }
531  else { // alpha != 0
532  A_crs_->template localSolve<ST, ST> (X, Y, mode);
533  if (alpha != STS::one ()) {
534  Y.scale (alpha);
535  }
536  }
537  }
538  else { // beta != 0
539  if (alpha == STS::zero ()) {
540  Y.scale (beta); // Y := beta * Y
541  }
542  else { // alpha != 0
543  MV Y_tmp (Y, Teuchos::Copy);
544  A_crs_->template localSolve<ST, ST> (X, Y_tmp, mode); // Y_tmp := M * X
545  Y.update (alpha, Y_tmp, beta); // Y := beta * Y + alpha * Y_tmp
546  }
547  }
548 }
549 
550 
551 template <class MatrixType>
552 int
555  return numInitialize_;
556 }
557 
558 template <class MatrixType>
559 int
561 getNumCompute () const {
562  return numCompute_;
563 }
564 
565 template <class MatrixType>
566 int
568 getNumApply () const {
569  return numApply_;
570 }
571 
572 template <class MatrixType>
573 double
576  return initializeTime_;
577 }
578 
579 template<class MatrixType>
580 double
582 getComputeTime () const {
583  return computeTime_;
584 }
585 
586 template<class MatrixType>
587 double
589 getApplyTime() const {
590  return applyTime_;
591 }
592 
593 template <class MatrixType>
594 std::string
596 description () const
597 {
598  std::ostringstream os;
599 
600  // Output is a valid YAML dictionary in flow style. If you don't
601  // like everything on a single line, you should call describe()
602  // instead.
603  os << "\"Ifpack2::LocalSparseTriangularSolver\": {";
604  if (this->getObjectLabel () != "") {
605  os << "Label: \"" << this->getObjectLabel () << "\", ";
606  }
607  os << "Initialized: " << (isInitialized () ? "true" : "false") << ", "
608  << "Computed: " << (isComputed () ? "true" : "false") << ", ";
609 
610  if (A_.is_null ()) {
611  os << "Matrix: null";
612  }
613  else {
614  os << "Matrix: not null"
615  << ", Global matrix dimensions: ["
616  << A_->getGlobalNumRows () << ", "
617  << A_->getGlobalNumCols () << "]";
618  }
619 
620  if (Teuchos::nonnull (htsImpl_))
621  os << ", HTS computed: " << (htsImpl_->isComputed () ? "true" : "false");
622 
623  os << "}";
624  return os.str ();
625 }
626 
627 template <class MatrixType>
629 describe (Teuchos::FancyOStream& out,
630  const Teuchos::EVerbosityLevel verbLevel) const
631 {
632  using std::endl;
633  // Default verbosity level is VERB_LOW, which prints only on Process
634  // 0 of the matrix's communicator.
635  const Teuchos::EVerbosityLevel vl
636  = (verbLevel == Teuchos::VERB_DEFAULT) ? Teuchos::VERB_LOW : verbLevel;
637 
638  if (vl != Teuchos::VERB_NONE) {
639  // Print only on Process 0 in the matrix's communicator. If the
640  // matrix is null, though, we have to get the communicator from
641  // somewhere, so we ask Tpetra for its default communicator. If
642  // MPI is enabled, this wraps MPI_COMM_WORLD or a clone thereof.
643  auto comm = A_.is_null () ?
644  Tpetra::DefaultPlatform::getDefaultPlatform ().getComm () :
645  A_->getComm ();
646 
647  // Users aren't supposed to do anything with the matrix on
648  // processes where its communicator is null.
649  if (! comm.is_null () && comm->getRank () == 0) {
650  // By convention, describe() should always begin with a tab.
651  Teuchos::OSTab tab0 (out);
652  // Output is in YAML format. We have to escape the class name,
653  // because it has a colon.
654  out << "\"Ifpack2::LocalSparseTriangularSolver\":" << endl;
655  Teuchos::OSTab tab1 (out);
656  out << "Scalar: " << Teuchos::TypeNameTraits<scalar_type>::name () << endl
657  << "LocalOrdinal: " << Teuchos::TypeNameTraits<local_ordinal_type>::name () << endl
658  << "GlobalOrdinal: " << Teuchos::TypeNameTraits<global_ordinal_type>::name () << endl
659  << "Node: " << Teuchos::TypeNameTraits<node_type>::name () << endl;
660  }
661  }
662 }
663 
664 template <class MatrixType>
665 Teuchos::RCP<const typename LocalSparseTriangularSolver<MatrixType>::map_type>
667 getDomainMap () const
668 {
669  TEUCHOS_TEST_FOR_EXCEPTION
670  (A_.is_null (), std::runtime_error,
671  "Ifpack2::LocalSparseTriangularSolver::getDomainMap: "
672  "The matrix is null. Please call setMatrix() with a nonnull input "
673  "before calling this method.");
674  return A_->getDomainMap ();
675 }
676 
677 template <class MatrixType>
678 Teuchos::RCP<const typename LocalSparseTriangularSolver<MatrixType>::map_type>
680 getRangeMap () const
681 {
682  TEUCHOS_TEST_FOR_EXCEPTION
683  (A_.is_null (), std::runtime_error,
684  "Ifpack2::LocalSparseTriangularSolver::getRangeMap: "
685  "The matrix is null. Please call setMatrix() with a nonnull input "
686  "before calling this method.");
687  return A_->getRangeMap ();
688 }
689 
690 template<class MatrixType>
692 setMatrix (const Teuchos::RCP<const row_matrix_type>& A)
693 {
694  const char prefix[] = "Ifpack2::LocalSparseTriangularSolver::setMatrix: ";
695 
696  // If the pointer didn't change, do nothing. This is reasonable
697  // because users are supposed to call this method with the same
698  // object over all participating processes, and pointer identity
699  // implies object identity.
700  if (A.getRawPtr () != A_.getRawPtr ()) {
701  // Check in serial or one-process mode if the matrix is square.
702  TEUCHOS_TEST_FOR_EXCEPTION
703  (! A.is_null () && A->getComm ()->getSize () == 1 &&
704  A->getNodeNumRows () != A->getNodeNumCols (),
705  std::runtime_error, prefix << "If A's communicator only contains one "
706  "process, then A must be square. Instead, you provided a matrix A with "
707  << A->getNodeNumRows () << " rows and " << A->getNodeNumCols ()
708  << " columns.");
709 
710  // It's legal for A to be null; in that case, you may not call
711  // initialize() until calling setMatrix() with a nonnull input.
712  // Regardless, setting the matrix invalidates the preconditioner.
713  isInitialized_ = false;
714  isComputed_ = false;
715 
716  typedef typename Tpetra::CrsMatrix<scalar_type, local_ordinal_type,
717  global_ordinal_type, node_type> crs_matrix_type;
718  if (A.is_null ()) {
719  A_crs_ = Teuchos::null;
720  A_ = Teuchos::null;
721  }
722  else { // A is not null
723  Teuchos::RCP<const crs_matrix_type> A_crs =
724  Teuchos::rcp_dynamic_cast<const crs_matrix_type> (A);
725  TEUCHOS_TEST_FOR_EXCEPTION
726  (A_crs.is_null (), std::invalid_argument, prefix <<
727  "The input matrix A is not a Tpetra::CrsMatrix.");
728  A_crs_ = A_crs;
729  A_ = A;
730  }
731 
732  if (Teuchos::nonnull (htsImpl_))
733  htsImpl_->reset ();
734  } // pointers are not the same
735 }
736 
737 } // namespace Ifpack2
738 
739 #define IFPACK2_LOCALSPARSETRIANGULARSOLVER_INSTANT(S,LO,GO,N) \
740  template class Ifpack2::LocalSparseTriangularSolver< Tpetra::RowMatrix<S, LO, GO, N> >;
741 
742 #endif // IFPACK2_LOCALSPARSETRIANGULARSOLVER_DEF_HPP
void apply(const Tpetra::MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > &X, Tpetra::MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > &Y, Teuchos::ETransp mode=Teuchos::NO_TRANS, scalar_type alpha=Teuchos::ScalarTraits< scalar_type >::one(), scalar_type beta=Teuchos::ScalarTraits< scalar_type >::zero()) const
Apply the preconditioner to X, and put the result in Y.
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:407
bool isInitialized() const
Return true if the preconditioner has been successfully initialized.
Definition: Ifpack2_LocalSparseTriangularSolver_decl.hpp:198
int getNumInitialize() const
Return the number of calls to initialize().
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:554
Teuchos::RCP< const map_type > getDomainMap() const
The domain of this operator.
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:667
Teuchos::RCP< const map_type > getRangeMap() const
The range of this operator.
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:680
int getNumCompute() const
Return the number of calls to compute().
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:561
double getApplyTime() const
Return the time spent in apply().
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:589
void compute()
"Numeric" phase of setup
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:371
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Print this object with given verbosity to the given output stream.
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:629
MatrixType::global_ordinal_type global_ordinal_type
Type of the global indices of the input matrix.
Definition: Ifpack2_LocalSparseTriangularSolver_decl.hpp:99
Ifpack2 implementation details.
MatrixType::node_type node_type
Node type of the input matrix.
Definition: Ifpack2_LocalSparseTriangularSolver_decl.hpp:101
bool isComputed() const
Return true if compute() has been called.
Definition: Ifpack2_LocalSparseTriangularSolver_decl.hpp:209
double getComputeTime() const
Return the time spent in compute().
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:582
int getNumApply() const
Return the number of calls to apply().
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:568
"Preconditioner" that solves local sparse triangular systems.
Definition: Ifpack2_LocalSparseTriangularSolver_decl.hpp:83
void initialize()
"Symbolic" phase of setup
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:328
virtual void setMatrix(const Teuchos::RCP< const row_matrix_type > &A)
Set this preconditioner&#39;s matrix.
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:692
double getInitializeTime() const
Return the time spent in initialize().
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:575
MatrixType::local_ordinal_type local_ordinal_type
Type of the local indices of the input matrix.
Definition: Ifpack2_LocalSparseTriangularSolver_decl.hpp:97
void setParameters(const Teuchos::ParameterList &params)
Set this object&#39;s parameters.
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:297
MatrixType::scalar_type scalar_type
Type of the entries of the input matrix.
Definition: Ifpack2_LocalSparseTriangularSolver_decl.hpp:95
std::string description() const
A one-line description of this object.
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:596
Preconditioners and smoothers for Tpetra sparse matrices.
Definition: Ifpack2_AdditiveSchwarz_decl.hpp:72
virtual ~LocalSparseTriangularSolver()
Destructor (virtual for memory safety).
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:291
LocalSparseTriangularSolver()
Constructor that takes no input matrix.
Definition: Ifpack2_LocalSparseTriangularSolver_def.hpp:259