43#ifndef IFPACK2_HIPTMAIR_DEF_HPP
44#define IFPACK2_HIPTMAIR_DEF_HPP
46#include "Ifpack2_Details_OneLevelFactory.hpp"
47#include "Ifpack2_Parameters.hpp"
48#include "Teuchos_TimeMonitor.hpp"
49#include "Tpetra_MultiVector.hpp"
50#include "Tpetra_Details_residual.hpp"
51#include <Tpetra_RowMatrixTransposer.hpp>
58template <
class MatrixType>
60Hiptmair (
const Teuchos::RCP<const row_matrix_type>& A,
61 const Teuchos::RCP<const row_matrix_type>& PtAP,
62 const Teuchos::RCP<const row_matrix_type>& P,
63 const Teuchos::RCP<const row_matrix_type>& Pt) :
69 precType1_ (
"CHEBYSHEV"),
70 precType2_ (
"CHEBYSHEV"),
72 ZeroStartingSolution_ (true),
73 ImplicitTranspose_ (Pt.is_null()),
75 IsInitialized_ (false),
80 InitializeTime_ (0.0),
88template <
class MatrixType>
90Hiptmair (
const Teuchos::RCP<const row_matrix_type>& A):
96 precType1_ (
"CHEBYSHEV"),
97 precType2_ (
"CHEBYSHEV"),
99 ZeroStartingSolution_ (true),
100 ImplicitTranspose_ (true),
102 IsInitialized_ (false),
107 InitializeTime_ (0.0),
113template <
class MatrixType>
116template <
class MatrixType>
121 using Teuchos::ParameterList;
122 using Teuchos::Exceptions::InvalidParameterName;
123 using Teuchos::Exceptions::InvalidParameterType;
125 ParameterList params = plist;
132 std::string precType1 = precType1_;
133 std::string precType2 = precType2_;
134 std::string preOrPost = preOrPost_;
135 Teuchos::ParameterList precList1 = precList1_;
136 Teuchos::ParameterList precList2 = precList2_;
137 bool zeroStartingSolution = ZeroStartingSolution_;
138 bool implicitTranspose = ImplicitTranspose_;
140 precType1 = params.get(
"hiptmair: smoother type 1", precType1);
141 precType2 = params.get(
"hiptmair: smoother type 2", precType2);
142 precList1 = params.get(
"hiptmair: smoother list 1", precList1);
143 precList2 = params.get(
"hiptmair: smoother list 2", precList2);
144 preOrPost = params.get(
"hiptmair: pre or post", preOrPost);
145 zeroStartingSolution = params.get(
"hiptmair: zero starting solution",
146 zeroStartingSolution);
147 implicitTranspose = params.get(
"hiptmair: implicit transpose", implicitTranspose);
152 PtAP_ = params.get<RCP<row_matrix_type> >(
"PtAP");
154 P_ = params.get<RCP<row_matrix_type> >(
"P");
155 if (params.isType<RCP<row_matrix_type> >(
"Pt"))
156 Pt_ = params.get<RCP<row_matrix_type> >(
"Pt");
160 precType1_ = precType1;
161 precType2_ = precType2;
162 precList1_ = precList1;
163 precList2_ = precList2;
164 preOrPost_ = preOrPost;
165 ZeroStartingSolution_ = zeroStartingSolution;
166 ImplicitTranspose_ = implicitTranspose;
170template <
class MatrixType>
171Teuchos::RCP<const Teuchos::Comm<int> >
173 TEUCHOS_TEST_FOR_EXCEPTION(
174 A_.is_null (), std::runtime_error,
"Ifpack2::Hiptmair::getComm: "
175 "The input matrix A is null. Please call setMatrix() with a nonnull "
176 "input matrix before calling this method.");
177 return A_->getComm ();
181template <
class MatrixType>
182Teuchos::RCP<const Tpetra::RowMatrix<typename MatrixType::scalar_type,typename MatrixType::local_ordinal_type,typename MatrixType::global_ordinal_type,typename MatrixType::node_type> >
188template <
class MatrixType>
189Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,typename MatrixType::global_ordinal_type,typename MatrixType::node_type> >
192 TEUCHOS_TEST_FOR_EXCEPTION(
193 A_.is_null (), std::runtime_error,
"Ifpack2::Hiptmair::getDomainMap: "
194 "The input matrix A is null. Please call setMatrix() with a nonnull "
195 "input matrix before calling this method.");
196 return A_->getDomainMap ();
200template <
class MatrixType>
201Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,typename MatrixType::global_ordinal_type,typename MatrixType::node_type> >
204 TEUCHOS_TEST_FOR_EXCEPTION(
205 A_.is_null (), std::runtime_error,
"Ifpack2::Hiptmair::getRangeMap: "
206 "The input matrix A is null. Please call setMatrix() with a nonnull "
207 "input matrix before calling this method.");
208 return A_->getRangeMap ();
212template <
class MatrixType>
220template <
class MatrixType>
222 return NumInitialize_;
226template <
class MatrixType>
232template <
class MatrixType>
238template <
class MatrixType>
240 return InitializeTime_;
244template <
class MatrixType>
250template <
class MatrixType>
256template <
class MatrixType>
259 using Teuchos::ParameterList;
263 const char methodName[] =
"Ifpack2::Hiptmair::initialize";
265 TEUCHOS_TEST_FOR_EXCEPTION(
266 A_.is_null (), std::runtime_error,
"Ifpack2::Hiptmair::initialize: "
267 "The input matrix A is null. Please call setMatrix() with a nonnull "
268 "input matrix before calling this method.");
271 IsInitialized_ =
false;
274 Teuchos::RCP<Teuchos::Time> timer =
275 Teuchos::TimeMonitor::getNewCounter (methodName);
277 double startTime = timer->wallTime();
280 Teuchos::TimeMonitor timeMon (*timer);
284 ifpack2_prec1_=factory.
create(precType1_,A_);
285 ifpack2_prec1_->initialize();
286 ifpack2_prec1_->setParameters(precList1_);
288 ifpack2_prec2_=factory.
create(precType2_,PtAP_);
289 ifpack2_prec2_->initialize();
290 ifpack2_prec2_->setParameters(precList2_);
293 IsInitialized_ =
true;
295 InitializeTime_ += (timer->wallTime() - startTime);
299template <
class MatrixType>
302 const char methodName[] =
"Ifpack2::Hiptmair::initialize";
304 TEUCHOS_TEST_FOR_EXCEPTION(
305 A_.is_null (), std::runtime_error,
"Ifpack2::Hiptmair::compute: "
306 "The input matrix A is null. Please call setMatrix() with a nonnull "
307 "input matrix before calling this method.");
310 if (! isInitialized ()) {
314 Teuchos::RCP<Teuchos::Time> timer =
315 Teuchos::TimeMonitor::getNewCounter (methodName);
317 double startTime = timer->wallTime();
319 Teuchos::TimeMonitor timeMon (*timer);
320 ifpack2_prec1_->compute();
321 ifpack2_prec2_->compute();
323 if (!ImplicitTranspose_ && Pt_.is_null()) {
324 using crs_type = Tpetra::CrsMatrix<typename MatrixType::scalar_type,typename MatrixType::local_ordinal_type,typename MatrixType::global_ordinal_type,typename MatrixType::node_type>;
325 Teuchos::RCP<const crs_type> crsP = Teuchos::rcp_dynamic_cast<const crs_type>(P_);
326 if (!crsP.is_null()) {
327 using transposer_type = Tpetra::RowMatrixTransposer<typename MatrixType::scalar_type,typename MatrixType::local_ordinal_type,typename MatrixType::global_ordinal_type,typename MatrixType::node_type>;
328 Pt_ = transposer_type(crsP).createTranspose();
330 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::runtime_error,
"Ifpack2::Hiptmair::compute: "
331 "ImplicitTranspose == false, but no Pt was provided and transposing P was not possible.");
337 ComputeTime_ += (timer->wallTime() - startTime);
341template <
class MatrixType>
343apply (
const Tpetra::MultiVector<
typename MatrixType::scalar_type,
344 typename MatrixType::local_ordinal_type,
345 typename MatrixType::global_ordinal_type,
346 typename MatrixType::node_type>& X,
347 Tpetra::MultiVector<
typename MatrixType::scalar_type,
348 typename MatrixType::local_ordinal_type,
349 typename MatrixType::global_ordinal_type,
350 typename MatrixType::node_type>& Y,
351 Teuchos::ETransp mode,
352 typename MatrixType::scalar_type alpha,
353 typename MatrixType::scalar_type beta)
const
357 using Teuchos::rcpFromRef;
360 TEUCHOS_TEST_FOR_EXCEPTION(
361 ! isComputed (), std::runtime_error,
362 "Ifpack2::Hiptmair::apply: You must call compute() before you may call apply().");
363 TEUCHOS_TEST_FOR_EXCEPTION(
364 X.getNumVectors () != Y.getNumVectors (), std::invalid_argument,
365 "Ifpack2::Hiptmair::apply: The MultiVector inputs X and Y do not have the "
366 "same number of columns. X.getNumVectors() = " << X.getNumVectors ()
367 <<
" != Y.getNumVectors() = " << Y.getNumVectors () <<
".");
370 TEUCHOS_TEST_FOR_EXCEPTION(
371 alpha != STS::one (), std::logic_error,
372 "Ifpack2::Hiptmair::apply: alpha != 1 has not been implemented.");
373 TEUCHOS_TEST_FOR_EXCEPTION(
374 beta != STS::zero (), std::logic_error,
375 "Ifpack2::Hiptmair::apply: zero != 0 has not been implemented.");
376 TEUCHOS_TEST_FOR_EXCEPTION(
377 mode != Teuchos::NO_TRANS, std::logic_error,
378 "Ifpack2::Hiptmair::apply: mode != Teuchos::NO_TRANS has not been implemented.");
380 const std::string timerName (
"Ifpack2::Hiptmair::apply");
381 Teuchos::RCP<Teuchos::Time> timer = Teuchos::TimeMonitor::lookupCounter (timerName);
382 if (timer.is_null ()) {
383 timer = Teuchos::TimeMonitor::getNewCounter (timerName);
385 double startTime = timer->wallTime();
387 Teuchos::TimeMonitor timeMon (*timer);
394 Xcopy = rcp (
new MV (X, Teuchos::Copy));
396 Xcopy = rcpFromRef (X);
400 RCP<MV> Ycopy = rcpFromRef (Y);
401 if (ZeroStartingSolution_) {
402 Ycopy->putScalar (STS::zero ());
406 applyHiptmairSmoother (*Xcopy, *Ycopy);
410 ApplyTime_ += (timer->wallTime() - startTime);
414template<
class MatrixType>
417updateCachedMultiVectors (
const Teuchos::RCP<
const Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type>>& map1,
418 const Teuchos::RCP<
const Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type>>& map2,
419 size_t numVecs)
const
425 if (cachedResidual1_.is_null () ||
426 map1.get () != cachedResidual1_->getMap ().get () ||
427 cachedResidual1_->getNumVectors () != numVecs) {
429 cachedResidual1_ = Teuchos::rcp (
new MV (map1, numVecs,
false));
430 cachedSolution1_ = Teuchos::rcp (
new MV (map1, numVecs,
false));
432 if (cachedResidual2_.is_null () ||
433 map2.get () != cachedResidual2_->getMap ().get () ||
434 cachedResidual2_->getNumVectors () != numVecs) {
436 cachedResidual2_ = Teuchos::rcp (
new MV (map2, numVecs,
false));
437 cachedSolution2_ = Teuchos::rcp (
new MV (map2, numVecs,
false));
442template <
class MatrixType>
445 typename MatrixType::local_ordinal_type,
446 typename MatrixType::global_ordinal_type,
447 typename MatrixType::node_type>& X,
448 Tpetra::MultiVector<
typename MatrixType::scalar_type,
449 typename MatrixType::local_ordinal_type,
450 typename MatrixType::global_ordinal_type,
451 typename MatrixType::node_type>& Y)
const
453 const scalar_type ZERO = STS::zero ();
454 const scalar_type ONE = STS::one ();
456 const std::string timerName1 (
"Ifpack2::Hiptmair::apply 1");
457 const std::string timerName2 (
"Ifpack2::Hiptmair::apply 2");
459 Teuchos::RCP<Teuchos::Time> timer1 = Teuchos::TimeMonitor::lookupCounter (timerName1);
460 if (timer1.is_null ()) {
461 timer1 = Teuchos::TimeMonitor::getNewCounter (timerName1);
463 Teuchos::RCP<Teuchos::Time> timer2 = Teuchos::TimeMonitor::lookupCounter (timerName2);
464 if (timer2.is_null ()) {
465 timer2 = Teuchos::TimeMonitor::getNewCounter (timerName2);
469#ifdef IFPACK2_DEBUG_SMOOTHER
470 int mypid = X.getMap()->getComm()->getRank();
471 Teuchos::Array<double> ttt(1);
472 printf(
"\n--------------------------------\n");
473 printf(
"Coming into matrix Hiptmair\n");
475 if (!mypid) printf(
"\t||x|| = %15.10e\n", ttt[0]);
477 if (!mypid) printf(
"\t||rhs|| = %15.10e\n", ttt[0]);
479 double normA = A_->getFrobeniusNorm();
480 if (!mypid) printf(
"\t||A|| = %15.10e\n", normA);
481 Tpetra::Vector<
typename MatrixType::scalar_type,
482 typename MatrixType::local_ordinal_type,
483 typename MatrixType::global_ordinal_type,
484 typename MatrixType::node_type> d(A_->getRowMap());
485 A_->getLocalDiagCopy(d);
487 if (!mypid) printf(
"\t||diag(A)|| = %15.10e\n", ttt[0]);
493 updateCachedMultiVectors (A_->getRowMap (),
497 if (preOrPost_ ==
"pre" || preOrPost_ ==
"both") {
499 Teuchos::TimeMonitor timeMon (*timer1);
500 Tpetra::Details::residual(*A_,Y,X,*cachedResidual1_);
501 cachedSolution1_->putScalar (ZERO);
502 ifpack2_prec1_->apply (*cachedResidual1_, *cachedSolution1_);
503 Y.update (ONE, *cachedSolution1_, ONE);
510 Teuchos::TimeMonitor timeMon (*timer2);
511 Tpetra::Details::residual(*A_,Y,X,*cachedResidual1_);
512#ifdef IFPACK2_DEBUG_SMOOTHER
513 if (!mypid) printf(
" After smoothing on edges\n");
515 if (!mypid) printf(
"\t||x|| = %15.10e\n", ttt[0]);
516 cachedResidual1_->norm2(ttt());
517 if (!mypid) printf(
"\t||res|| = %15.10e\n", ttt[0]);
523 Pt_->apply (*cachedResidual1_, *cachedResidual2_, Teuchos::NO_TRANS);
525 P_->apply (*cachedResidual1_, *cachedResidual2_, Teuchos::TRANS);
526 cachedSolution2_->putScalar (ZERO);
528#ifdef IFPACK2_DEBUG_SMOOTHER
529 if (!mypid)printf(
" Before smoothing on nodes\n");
530 cachedSolution2_->norm2(ttt());
531 if (!mypid)printf(
"\t||x_nodal|| = %15.10e\n",ttt[0]);
532 cachedResidual2_->norm2(ttt());
533 if (!mypid)printf(
"\t||rhs_nodal|| = %15.10e\n", ttt[0]);
535 auto An = ifpack2_prec2_->getMatrix();
536 double normA = An->getFrobeniusNorm();
537 if (!mypid) printf(
"\t||An|| = %15.10e\n", normA);
538 Tpetra::Vector<
typename MatrixType::scalar_type,
539 typename MatrixType::local_ordinal_type,
540 typename MatrixType::global_ordinal_type,
541 typename MatrixType::node_type> d(An->getRowMap());
542 An->getLocalDiagCopy(d);
544 if (!mypid) printf(
"\t||diag(An)|| = %15.10e\n", ttt[0]);
549 ifpack2_prec2_->apply (*cachedResidual2_, *cachedSolution2_);
551#ifdef IFPACK2_DEBUG_SMOOTHER
552 if (!mypid)printf(
" After smoothing on nodes\n");
553 cachedSolution2_->norm2(ttt());
554 if (!mypid)printf(
"\t||x_nodal|| = %15.10e\n",ttt[0]);
555 cachedResidual2_->norm2(ttt());
556 if (!mypid)printf(
"\t||rhs_nodal|| = %15.10e\n", ttt[0]);
560 P_->apply (*cachedSolution2_, Y, Teuchos::NO_TRANS, ONE, ONE);
563 if (preOrPost_ ==
"post" || preOrPost_ ==
"both") {
565 Teuchos::TimeMonitor timeMon (*timer1);
566 Tpetra::Details::residual(*A_,Y,X,*cachedResidual1_);
567 cachedSolution1_->putScalar (ZERO);
568 ifpack2_prec1_->apply (*cachedResidual1_, *cachedSolution1_);
569 Y.update (ONE, *cachedSolution1_, ONE);
572#ifdef IFPACK2_DEBUG_SMOOTHER
573 if (!mypid)printf(
" After updating edge solution\n");
575 if (!mypid)printf(
"\t||x|| = %15.10e\n",ttt[0]);
576 if (!mypid)printf(
"--------------------------------\n");
582template <
class MatrixType>
585 std::ostringstream os;
590 os <<
"\"Ifpack2::Hiptmair\": {";
591 if (this->getObjectLabel () !=
"") {
592 os <<
"Label: \"" << this->getObjectLabel () <<
"\", ";
594 os <<
"Initialized: " << (isInitialized () ?
"true" :
"false") <<
", "
595 <<
"Computed: " << (isComputed () ?
"true" :
"false") <<
", ";
598 os <<
"Matrix: null, ";
601 os <<
"Matrix: not null"
602 <<
", Global matrix dimensions: ["
603 << A_->getGlobalNumRows () <<
", " << A_->getGlobalNumCols () <<
"], ";
606 os <<
"Smoother 1: ";
607 os << ifpack2_prec1_->description() <<
", ";
608 os <<
"Smoother 2: ";
609 os << ifpack2_prec2_->description();
616template <
class MatrixType>
618describe (Teuchos::FancyOStream &out,
619 const Teuchos::EVerbosityLevel verbLevel)
const
623 using Teuchos::VERB_DEFAULT;
624 using Teuchos::VERB_NONE;
625 using Teuchos::VERB_LOW;
626 using Teuchos::VERB_MEDIUM;
627 using Teuchos::VERB_HIGH;
628 using Teuchos::VERB_EXTREME;
630 const Teuchos::EVerbosityLevel vl =
631 (verbLevel == VERB_DEFAULT) ? VERB_LOW : verbLevel;
633 if (vl != VERB_NONE) {
635 Teuchos::OSTab tab0 (out);
636 out <<
"\"Ifpack2::Hiptmair\":";
638 Teuchos::OSTab tab1 (out);
639 if (this->getObjectLabel () !=
"") {
640 out <<
"Label: " << this->getObjectLabel () << endl;
642 out <<
"Initialized: " << (isInitialized () ?
"true" :
"false") << endl
643 <<
"Computed: " << (isComputed () ?
"true" :
"false") << endl
644 <<
"Global number of rows: " << A_->getGlobalNumRows () << endl
645 <<
"Global number of columns: " << A_->getGlobalNumCols () << endl
648 out <<
" null" << endl;
650 A_->describe (out, vl);
652 out <<
"Smoother 1: ";
653 ifpack2_prec1_->describe(out, vl);
654 out <<
"Smoother 2: ";
655 ifpack2_prec2_->describe(out, vl);
661#define IFPACK2_HIPTMAIR_INSTANT(S,LO,GO,N) \
662 template class Ifpack2::Hiptmair< Tpetra::RowMatrix<S, LO, GO, N> >;
"Factory" for creating single-level preconditioners.
Definition: Ifpack2_Details_OneLevelFactory_decl.hpp:124
Teuchos::RCP< prec_type > create(const std::string &precType, const Teuchos::RCP< const row_matrix_type > &matrix) const
Create an instance of Preconditioner given the string name of the preconditioner type.
Definition: Ifpack2_Details_OneLevelFactory_def.hpp:84
Wrapper for Hiptmair smoothers.
Definition: Ifpack2_Hiptmair_decl.hpp:76
void initialize()
Do any initialization that depends on the input matrix's structure.
Definition: Ifpack2_Hiptmair_def.hpp:257
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, putting the result in Y.
Definition: Ifpack2_Hiptmair_def.hpp:343
int getNumCompute() const
Returns the number of calls to Compute().
Definition: Ifpack2_Hiptmair_def.hpp:227
void compute()
Do any initialization that depends on the input matrix's values.
Definition: Ifpack2_Hiptmair_def.hpp:300
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_Hiptmair_def.hpp:618
MatrixType::local_ordinal_type local_ordinal_type
The type of local indices in the input MatrixType.
Definition: Ifpack2_Hiptmair_decl.hpp:85
std::string description() const
Return a simple one-line description of this object.
Definition: Ifpack2_Hiptmair_def.hpp:583
double getApplyTime() const
Returns the time spent in apply().
Definition: Ifpack2_Hiptmair_def.hpp:251
Teuchos::RCP< const Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > > getRangeMap() const
Tpetra::Map representing the range of this operator.
Definition: Ifpack2_Hiptmair_def.hpp:202
void updateCachedMultiVectors(const Teuchos::RCP< const Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > > &map1, const Teuchos::RCP< const Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > > &map2, size_t numVecs) const
A service routine for updating the cached MultiVectors.
Definition: Ifpack2_Hiptmair_def.hpp:417
MatrixType::scalar_type scalar_type
The type of the entries of the input MatrixType.
Definition: Ifpack2_Hiptmair_decl.hpp:82
Hiptmair(const Teuchos::RCP< const row_matrix_type > &A)
Constructor that takes 1 Tpetra matrix (assumes we'll get the rest off the parameter list)
Definition: Ifpack2_Hiptmair_def.hpp:90
int getNumInitialize() const
Returns the number of calls to Initialize().
Definition: Ifpack2_Hiptmair_def.hpp:221
int getNumApply() const
Returns the number of calls to apply().
Definition: Ifpack2_Hiptmair_def.hpp:233
virtual ~Hiptmair()
Destructor.
Definition: Ifpack2_Hiptmair_def.hpp:114
void setParameters(const Teuchos::ParameterList ¶ms)
Set the preconditioner's parameters.
Definition: Ifpack2_Hiptmair_def.hpp:117
MatrixType::node_type node_type
The Node type used by the input MatrixType.
Definition: Ifpack2_Hiptmair_decl.hpp:91
Teuchos::RCP< const Tpetra::RowMatrix< scalar_type, local_ordinal_type, global_ordinal_type, node_type > > getMatrix() const
Returns a reference to the matrix to be preconditioned.
Definition: Ifpack2_Hiptmair_def.hpp:183
double getInitializeTime() const
Returns the time spent in Initialize().
Definition: Ifpack2_Hiptmair_def.hpp:239
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Returns the operator's communicator.
Definition: Ifpack2_Hiptmair_def.hpp:172
MatrixType::global_ordinal_type global_ordinal_type
The type of global indices in the input MatrixType.
Definition: Ifpack2_Hiptmair_decl.hpp:88
Teuchos::RCP< const Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > > getDomainMap() const
Tpetra::Map representing the domain of this operator.
Definition: Ifpack2_Hiptmair_def.hpp:190
double getComputeTime() const
Returns the time spent in Compute().
Definition: Ifpack2_Hiptmair_def.hpp:245
bool hasTransposeApply() const
Whether this object's apply() method can apply the transpose (or conjugate transpose,...
Definition: Ifpack2_Hiptmair_def.hpp:213
Preconditioners and smoothers for Tpetra sparse matrices.
Definition: Ifpack2_AdditiveSchwarz_decl.hpp:74