10#ifndef IFPACK2_RELAXATION_DEF_HPP
11#define IFPACK2_RELAXATION_DEF_HPP
13#include "Teuchos_StandardParameterEntryValidators.hpp"
14#include "Teuchos_TimeMonitor.hpp"
15#include "Tpetra_CrsMatrix.hpp"
16#include "Tpetra_BlockCrsMatrix.hpp"
17#include "Tpetra_BlockView.hpp"
19#include "Ifpack2_Details_getCrsMatrix.hpp"
21#include "MatrixMarket_Tpetra.hpp"
22#include "Tpetra_Details_residual.hpp"
26#include "KokkosSparse_gauss_seidel.hpp"
30class NonnegativeIntValidator :
public Teuchos::ParameterEntryValidator {
33 NonnegativeIntValidator() {}
36 Teuchos::ParameterEntryValidator::ValidStringsList validStringValues()
const {
42 validate(
const Teuchos::ParameterEntry& entry,
43 const std::string& paramName,
44 const std::string& sublistName)
const {
46 Teuchos::any anyVal = entry.getAny(
true);
47 const std::string entryName = entry.getAny(
false).typeName();
49 TEUCHOS_TEST_FOR_EXCEPTION(
50 anyVal.type() !=
typeid(
int),
51 Teuchos::Exceptions::InvalidParameterType,
52 "Parameter \"" << paramName <<
"\" in sublist \"" << sublistName
53 <<
"\" has the wrong type." << endl
54 <<
"Parameter: " << paramName
56 <<
"Type specified: " << entryName << endl
57 <<
"Type required: int" << endl);
59 const int val = Teuchos::any_cast<int>(anyVal);
60 TEUCHOS_TEST_FOR_EXCEPTION(
61 val < 0, Teuchos::Exceptions::InvalidParameterValue,
62 "Parameter \"" << paramName <<
"\" in sublist \"" << sublistName
63 <<
"\" is negative." << endl
64 <<
"Parameter: " << paramName
66 <<
"Value specified: " << val << endl
67 <<
"Required range: [0, INT_MAX]" << endl);
71 const std::string getXMLTypeName()
const {
72 return "NonnegativeIntValidator";
77 printDoc(
const std::string& docString,
78 std::ostream& out)
const {
79 Teuchos::StrUtils::printLines(out,
"# ", docString);
80 out <<
"#\tValidator Used: " << std::endl;
81 out <<
"#\t\tNonnegativeIntValidator" << std::endl;
88template <class Scalar, const bool isOrdinal = Teuchos::ScalarTraits<Scalar>::isOrdinal>
92 static const Scalar eps();
96template <
class Scalar>
97class SmallTraits<Scalar, true> {
99 static const Scalar eps() {
100 return Teuchos::ScalarTraits<Scalar>::one();
105template <
class Scalar>
106class SmallTraits<Scalar, false> {
108 static const Scalar eps() {
109 return Teuchos::ScalarTraits<Scalar>::eps();
114template <
class Scalar,
115 const bool isComplex = Teuchos::ScalarTraits<Scalar>::isComplex>
118template <
class Scalar>
119struct RealTraits<Scalar, false> {
120 using val_type = Scalar;
121 using mag_type = Scalar;
122 static KOKKOS_INLINE_FUNCTION mag_type real(
const val_type& z) {
127template <
class Scalar>
128struct RealTraits<Scalar, true> {
129 using val_type = Scalar;
130 using mag_type =
typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
131 static KOKKOS_INLINE_FUNCTION mag_type real(
const val_type& z) {
132 return KokkosKernels::ArithTraits<val_type>::real(z);
136template <
class Scalar>
137KOKKOS_INLINE_FUNCTION
typename RealTraits<Scalar>::mag_type
138getRealValue(
const Scalar& z) {
139 return RealTraits<Scalar>::real(z);
146template <
class MatrixType>
147void Relaxation<MatrixType>::
148 updateCachedMultiVector(
const Teuchos::RCP<
const Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type>>& map,
149 size_t numVecs)
const {
152 if (cachedMV_.is_null() ||
153 map.get() != cachedMV_->getMap().get() ||
154 cachedMV_->getNumVectors() != numVecs) {
155 using MV = Tpetra::MultiVector<scalar_type, local_ordinal_type,
156 global_ordinal_type, node_type>;
157 cachedMV_ = Teuchos::rcp(
new MV(map, numVecs,
false));
161template <
class MatrixType>
163 setMatrix(
const Teuchos::RCP<const row_matrix_type>& A) {
164 if (A.getRawPtr() != A_.getRawPtr()) {
165 Importer_ = Teuchos::null;
166 pointImporter_ = Teuchos::null;
167 Diagonal_ = Teuchos::null;
168 isInitialized_ =
false;
170 diagOffsets_ = Kokkos::View<size_t*, device_type>();
171 savedDiagOffsets_ =
false;
172 hasBlockCrsMatrix_ =
false;
173 serialGaussSeidel_ = Teuchos::null;
175 IsParallel_ = (A->getRowMap()->getComm()->getSize() > 1);
181template <
class MatrixType>
183 Relaxation(
const Teuchos::RCP<const row_matrix_type>& A)
185 , IsParallel_((A.is_null() || A->getRowMap().is_null() || A->getRowMap()->getComm().is_null()) ? false :
186 A->getRowMap()->getComm()->getSize() > 1) {
187 this->setObjectLabel(
"Ifpack2::Relaxation");
190template <
class MatrixType>
191Teuchos::RCP<const Teuchos::ParameterList>
193 using Teuchos::Array;
194 using Teuchos::ParameterList;
195 using Teuchos::parameterList;
198 using Teuchos::rcp_const_cast;
199 using Teuchos::rcp_implicit_cast;
200 using Teuchos::setStringToIntegralParameter;
201 typedef Teuchos::ParameterEntryValidator PEV;
203 if (validParams_.is_null()) {
204 RCP<ParameterList> pl = parameterList(
"Ifpack2::Relaxation");
208 Array<std::string> precTypes(8);
209 precTypes[0] =
"Jacobi";
210 precTypes[1] =
"Gauss-Seidel";
211 precTypes[2] =
"Symmetric Gauss-Seidel";
212 precTypes[3] =
"MT Gauss-Seidel";
213 precTypes[4] =
"MT Symmetric Gauss-Seidel";
214 precTypes[5] =
"Richardson";
215 precTypes[6] =
"Two-stage Gauss-Seidel";
216 precTypes[7] =
"Two-stage Symmetric Gauss-Seidel";
217 Array<Details::RelaxationType> precTypeEnums(8);
218 precTypeEnums[0] = Details::JACOBI;
219 precTypeEnums[1] = Details::GS;
220 precTypeEnums[2] = Details::SGS;
221 precTypeEnums[3] = Details::MTGS;
222 precTypeEnums[4] = Details::MTSGS;
223 precTypeEnums[5] = Details::RICHARDSON;
224 precTypeEnums[6] = Details::GS2;
225 precTypeEnums[7] = Details::SGS2;
226 const std::string defaultPrecType(
"Jacobi");
227 setStringToIntegralParameter<Details::RelaxationType>(
"relaxation: type",
228 defaultPrecType,
"Relaxation method", precTypes(), precTypeEnums(),
231 const int numSweeps = 1;
232 RCP<PEV> numSweepsValidator =
233 rcp_implicit_cast<PEV>(rcp(
new NonnegativeIntValidator));
234 pl->set(
"relaxation: sweeps", numSweeps,
"Number of relaxation sweeps",
235 rcp_const_cast<const PEV>(numSweepsValidator));
238 const int numOuterSweeps = 1;
239 RCP<PEV> numOuterSweepsValidator =
240 rcp_implicit_cast<PEV>(rcp(
new NonnegativeIntValidator));
241 pl->set(
"relaxation: outer sweeps", numOuterSweeps,
"Number of outer local relaxation sweeps for two-stage GS",
242 rcp_const_cast<const PEV>(numOuterSweepsValidator));
244 const int numInnerSweeps = 1;
245 RCP<PEV> numInnerSweepsValidator =
246 rcp_implicit_cast<PEV>(rcp(
new NonnegativeIntValidator));
247 pl->set(
"relaxation: inner sweeps", numInnerSweeps,
"Number of inner local relaxation sweeps for two-stage GS",
248 rcp_const_cast<const PEV>(numInnerSweepsValidator));
251 pl->set(
"relaxation: inner damping factor", innerDampingFactor,
"Damping factor for the inner sweep of two-stage GS");
253 const bool innerSpTrsv =
false;
254 pl->set(
"relaxation: inner sparse-triangular solve", innerSpTrsv,
"Specify whether to use sptrsv instead of JR iterations for two-stage GS");
256 const bool compactForm =
false;
257 pl->set(
"relaxation: compact form", compactForm,
"Specify whether to use compact form of recurrence for two-stage GS");
260 pl->set(
"relaxation: damping factor", dampingFactor);
262 const bool zeroStartingSolution =
true;
263 pl->set(
"relaxation: zero starting solution", zeroStartingSolution);
265 const bool doBackwardGS =
false;
266 pl->set(
"relaxation: backward mode", doBackwardGS);
268 const bool doL1Method =
false;
269 pl->set(
"relaxation: use l1", doL1Method);
271 const magnitude_type l1eta = (STM::one() + STM::one() + STM::one()) /
272 (STM::one() + STM::one());
273 pl->set(
"relaxation: l1 eta", l1eta);
276 pl->set(
"relaxation: min diagonal value", minDiagonalValue);
278 const bool fixTinyDiagEntries =
false;
279 pl->set(
"relaxation: fix tiny diagonal entries", fixTinyDiagEntries);
281 const bool checkDiagEntries =
false;
282 pl->set(
"relaxation: check diagonal entries", checkDiagEntries);
284 Teuchos::ArrayRCP<local_ordinal_type> localSmoothingIndices = Teuchos::null;
285 pl->set(
"relaxation: local smoothing indices", localSmoothingIndices);
287 const bool is_matrix_structurally_symmetric =
false;
288 pl->set(
"relaxation: symmetric matrix structure", is_matrix_structurally_symmetric);
290 const bool ifpack2_dump_matrix =
false;
291 pl->set(
"relaxation: ifpack2 dump matrix", ifpack2_dump_matrix);
293 const int cluster_size = 1;
294 pl->set(
"relaxation: mtgs cluster size", cluster_size);
296 pl->set(
"relaxation: mtgs coloring algorithm",
"Default");
298 const int long_row_threshold = 0;
299 pl->set(
"relaxation: long row threshold", long_row_threshold);
301 const bool timer_for_apply =
true;
302 pl->set(
"timer for apply", timer_for_apply);
304 validParams_ = rcp_const_cast<const ParameterList>(pl);
309template <
class MatrixType>
311 using Teuchos::getIntegralValue;
312 using Teuchos::getStringValue;
313 using Teuchos::ParameterList;
315 typedef scalar_type ST;
317 if (pl.isType<
double>(
"relaxation: damping factor")) {
320 ST df = pl.get<
double>(
"relaxation: damping factor");
321 pl.remove(
"relaxation: damping factor");
322 pl.set(
"relaxation: damping factor", df);
327 const Details::RelaxationType precType =
328 getIntegralValue<Details::RelaxationType>(pl,
"relaxation: type");
329 const std::string precTypeStr = getStringValue<Details::RelaxationType>(pl,
"relaxation: type");
331 pl.set<std::string>(
"relaxation: type", precTypeStr);
332 pl.get<std::string>(
"relaxation: type");
333 const int numSweeps = pl.get<
int>(
"relaxation: sweeps");
334 const ST dampingFactor = pl.get<ST>(
"relaxation: damping factor");
335 const bool zeroStartSol = pl.get<
bool>(
"relaxation: zero starting solution");
336 const bool doBackwardGS = pl.get<
bool>(
"relaxation: backward mode");
337 const bool doL1Method = pl.get<
bool>(
"relaxation: use l1");
338 const magnitude_type l1Eta = pl.get<magnitude_type>(
"relaxation: l1 eta");
339 const ST minDiagonalValue = pl.get<ST>(
"relaxation: min diagonal value");
340 const bool fixTinyDiagEntries = pl.get<
bool>(
"relaxation: fix tiny diagonal entries");
341 const bool checkDiagEntries = pl.get<
bool>(
"relaxation: check diagonal entries");
342 const bool is_matrix_structurally_symmetric = pl.get<
bool>(
"relaxation: symmetric matrix structure");
343 const bool ifpack2_dump_matrix = pl.get<
bool>(
"relaxation: ifpack2 dump matrix");
344 const bool timer_for_apply = pl.get<
bool>(
"timer for apply");
345 int cluster_size = 1;
346 if (pl.isParameter(
"relaxation: mtgs cluster size"))
347 cluster_size = pl.get<
int>(
"relaxation: mtgs cluster size");
348 int long_row_threshold = 0;
349 if (pl.isParameter(
"relaxation: long row threshold"))
350 long_row_threshold = pl.get<
int>(
"relaxation: long row threshold");
351 std::string color_algo_name = pl.get<std::string>(
"relaxation: mtgs coloring algorithm");
353 for (
char& c : color_algo_name)
355 if (color_algo_name ==
"default")
356 this->mtColoringAlgorithm_ = KokkosGraph::COLORING_DEFAULT;
357 else if (color_algo_name ==
"serial")
358 this->mtColoringAlgorithm_ = KokkosGraph::COLORING_SERIAL;
359 else if (color_algo_name ==
"vb")
360 this->mtColoringAlgorithm_ = KokkosGraph::COLORING_VB;
361 else if (color_algo_name ==
"vbbit")
362 this->mtColoringAlgorithm_ = KokkosGraph::COLORING_VBBIT;
363 else if (color_algo_name ==
"vbcs")
364 this->mtColoringAlgorithm_ = KokkosGraph::COLORING_VBCS;
365 else if (color_algo_name ==
"vbd")
366 this->mtColoringAlgorithm_ = KokkosGraph::COLORING_VBD;
367 else if (color_algo_name ==
"vbdbit")
368 this->mtColoringAlgorithm_ = KokkosGraph::COLORING_VBDBIT;
369 else if (color_algo_name ==
"eb")
370 this->mtColoringAlgorithm_ = KokkosGraph::COLORING_EB;
372 std::ostringstream msg;
373 msg <<
"Ifpack2::Relaxation: 'relaxation: mtgs coloring algorithm' = '" << color_algo_name <<
"' is not valid.\n";
374 msg <<
"Choices (not case sensitive) are: Default, Serial, VB, VBBIT, VBCS, VBD, VBDBIT, EB.";
375 TEUCHOS_TEST_FOR_EXCEPTION(
376 true, std::invalid_argument, msg.str());
379 Teuchos::ArrayRCP<local_ordinal_type> localSmoothingIndices = pl.get<Teuchos::ArrayRCP<local_ordinal_type>>(
"relaxation: local smoothing indices");
382 if (!std::is_same<double, ST>::value && pl.isType<
double>(
"relaxation: inner damping factor")) {
385 ST df = pl.get<
double>(
"relaxation: inner damping factor");
386 pl.remove(
"relaxation: inner damping factor");
387 pl.set(
"relaxation: inner damping factor", df);
390 if (long_row_threshold > 0) {
391 TEUCHOS_TEST_FOR_EXCEPTION(
392 cluster_size != 1, std::invalid_argument,
393 "Ifpack2::Relaxation: "
394 "Requested long row MTGS/MTSGS algorithm and cluster GS/SGS, but those are not compatible.");
395 TEUCHOS_TEST_FOR_EXCEPTION(
396 precType != Details::RelaxationType::MTGS && precType != Details::RelaxationType::MTSGS,
397 std::invalid_argument,
398 "Ifpack2::Relaxation: "
399 "Requested long row MTGS/MTSGS algorithm, but this is only compatible with preconditioner types "
400 "'MT Gauss-Seidel' and 'MT Symmetric Gauss-Seidel'.");
403 const ST innerDampingFactor = pl.get<ST>(
"relaxation: inner damping factor");
404 const int numInnerSweeps = pl.get<
int>(
"relaxation: inner sweeps");
405 const int numOuterSweeps = pl.get<
int>(
"relaxation: outer sweeps");
406 const bool innerSpTrsv = pl.get<
bool>(
"relaxation: inner sparse-triangular solve");
407 const bool compactForm = pl.get<
bool>(
"relaxation: compact form");
410 PrecType_ = precType;
411 NumSweeps_ = numSweeps;
412 DampingFactor_ = dampingFactor;
413 ZeroStartingSolution_ = zeroStartSol;
414 DoBackwardGS_ = doBackwardGS;
415 DoL1Method_ = doL1Method;
417 MinDiagonalValue_ = minDiagonalValue;
418 fixTinyDiagEntries_ = fixTinyDiagEntries;
419 checkDiagEntries_ = checkDiagEntries;
420 clusterSize_ = cluster_size;
421 longRowThreshold_ = long_row_threshold;
422 is_matrix_structurally_symmetric_ = is_matrix_structurally_symmetric;
423 ifpack2_dump_matrix_ = ifpack2_dump_matrix;
424 localSmoothingIndices_ = localSmoothingIndices;
426 NumInnerSweeps_ = numInnerSweeps;
427 NumOuterSweeps_ = numOuterSweeps;
428 InnerSpTrsv_ = innerSpTrsv;
429 InnerDampingFactor_ = innerDampingFactor;
430 CompactForm_ = compactForm;
431 TimerForApply_ = timer_for_apply;
434template <
class MatrixType>
438 this->setParametersImpl(
const_cast<Teuchos::ParameterList&
>(pl));
441template <
class MatrixType>
442Teuchos::RCP<const Teuchos::Comm<int>>
444 TEUCHOS_TEST_FOR_EXCEPTION(
445 A_.is_null(), std::runtime_error,
446 "Ifpack2::Relaxation::getComm: "
447 "The input matrix A is null. Please call setMatrix() with a nonnull "
448 "input matrix before calling this method.");
449 return A_->getRowMap()->getComm();
452template <
class MatrixType>
453Teuchos::RCP<const typename Relaxation<MatrixType>::row_matrix_type>
458template <
class MatrixType>
459Teuchos::RCP<
const Tpetra::Map<
typename MatrixType::local_ordinal_type,
460 typename MatrixType::global_ordinal_type,
461 typename MatrixType::node_type>>
463 TEUCHOS_TEST_FOR_EXCEPTION(
464 A_.is_null(), std::runtime_error,
465 "Ifpack2::Relaxation::getDomainMap: "
466 "The input matrix A is null. Please call setMatrix() with a nonnull "
467 "input matrix before calling this method.");
468 return A_->getDomainMap();
471template <
class MatrixType>
472Teuchos::RCP<
const Tpetra::Map<
typename MatrixType::local_ordinal_type,
473 typename MatrixType::global_ordinal_type,
474 typename MatrixType::node_type>>
476 TEUCHOS_TEST_FOR_EXCEPTION(
477 A_.is_null(), std::runtime_error,
478 "Ifpack2::Relaxation::getRangeMap: "
479 "The input matrix A is null. Please call setMatrix() with a nonnull "
480 "input matrix before calling this method.");
481 return A_->getRangeMap();
484template <
class MatrixType>
489template <
class MatrixType>
491 return (NumInitialize_);
494template <
class MatrixType>
496 return (NumCompute_);
499template <
class MatrixType>
504template <
class MatrixType>
506 return (InitializeTime_);
509template <
class MatrixType>
511 return (ComputeTime_);
514template <
class MatrixType>
519template <
class MatrixType>
521 return (ComputeFlops_);
524template <
class MatrixType>
526 return (ApplyFlops_);
529template <
class MatrixType>
531 TEUCHOS_TEST_FOR_EXCEPTION(
532 A_.is_null(), std::runtime_error,
533 "Ifpack2::Relaxation::getNodeSmootherComplexity: "
534 "The input matrix A is null. Please call setMatrix() with a nonnull "
535 "input matrix, then call compute(), before calling this method.");
537 return A_->getLocalNumRows() + A_->getLocalNumEntries();
540template <
class MatrixType>
542 apply(
const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
543 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
550 using Teuchos::rcpFromRef;
554 TEUCHOS_TEST_FOR_EXCEPTION(
555 A_.is_null(), std::runtime_error,
556 "Ifpack2::Relaxation::apply: "
557 "The input matrix A is null. Please call setMatrix() with a nonnull "
558 "input matrix, then call compute(), before calling this method.");
559 TEUCHOS_TEST_FOR_EXCEPTION(
562 "Ifpack2::Relaxation::apply: You must call compute() on this Ifpack2 "
563 "preconditioner instance before you may call apply(). You may call "
564 "isComputed() to find out if compute() has been called already.");
565 TEUCHOS_TEST_FOR_EXCEPTION(
566 X.getNumVectors() != Y.getNumVectors(),
568 "Ifpack2::Relaxation::apply: X and Y have different numbers of columns. "
570 << X.getNumVectors() <<
" columns, but Y has "
571 << Y.getNumVectors() <<
" columns.");
572 TEUCHOS_TEST_FOR_EXCEPTION(
573 beta != STS::zero(), std::logic_error,
574 "Ifpack2::Relaxation::apply: beta = " << beta <<
" != 0 case not "
577 Teuchos::RCP<Teuchos::Time> timer;
578 const std::string timerName(
"Ifpack2::Relaxation::apply");
579 if (TimerForApply_) {
580 timer = Teuchos::TimeMonitor::lookupCounter(timerName);
581 if (timer.is_null()) {
582 timer = Teuchos::TimeMonitor::getNewCounter(timerName);
586 Teuchos::Time time = Teuchos::Time(timerName);
587 double startTime = time.wallTime();
590 Teuchos::RCP<Teuchos::TimeMonitor> timeMon;
592 timeMon = Teuchos::rcp(
new Teuchos::TimeMonitor(*timer));
595 if (alpha == STS::zero()) {
597 Y.putScalar(STS::zero());
604 Xcopy = rcp(
new MV(X, Teuchos::Copy));
606 Xcopy = rcpFromRef(X);
614 case Ifpack2::Details::JACOBI:
615 ApplyInverseJacobi(*Xcopy, Y);
617 case Ifpack2::Details::GS:
618 ApplyInverseSerialGS(*Xcopy, Y, DoBackwardGS_ ? Tpetra::Backward : Tpetra::Forward);
620 case Ifpack2::Details::SGS:
621 ApplyInverseSerialGS(*Xcopy, Y, Tpetra::Symmetric);
623 case Ifpack2::Details::MTGS:
624 case Ifpack2::Details::GS2:
625 ApplyInverseMTGS_CrsMatrix(*Xcopy, Y, DoBackwardGS_ ? Tpetra::Backward : Tpetra::Forward);
627 case Ifpack2::Details::MTSGS:
628 case Ifpack2::Details::SGS2:
629 ApplyInverseMTGS_CrsMatrix(*Xcopy, Y, Tpetra::Symmetric);
631 case Ifpack2::Details::RICHARDSON:
632 ApplyInverseRichardson(*Xcopy, Y);
636 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::logic_error,
637 "Ifpack2::Relaxation::apply: Invalid preconditioner type enum value "
638 << PrecType_ <<
". Please report this bug to the Ifpack2 developers.");
640 if (alpha != STS::one()) {
642 const double numGlobalRows = as<double>(A_->getGlobalNumRows());
643 const double numVectors = as<double>(Y.getNumVectors());
644 ApplyFlops_ += numGlobalRows * numVectors;
648 ApplyTime_ += (time.wallTime() - startTime);
652template <
class MatrixType>
654 applyMat(
const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
655 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
656 Teuchos::ETransp mode)
const {
657 TEUCHOS_TEST_FOR_EXCEPTION(
658 A_.is_null(), std::runtime_error,
659 "Ifpack2::Relaxation::applyMat: "
660 "The input matrix A is null. Please call setMatrix() with a nonnull "
661 "input matrix, then call compute(), before calling this method.");
662 TEUCHOS_TEST_FOR_EXCEPTION(
663 !isComputed(), std::runtime_error,
664 "Ifpack2::Relaxation::applyMat: "
665 "isComputed() must be true before you may call applyMat(). "
666 "Please call compute() before calling this method.");
667 TEUCHOS_TEST_FOR_EXCEPTION(
668 X.getNumVectors() != Y.getNumVectors(), std::invalid_argument,
669 "Ifpack2::Relaxation::applyMat: X.getNumVectors() = " << X.getNumVectors()
670 <<
" != Y.getNumVectors() = " << Y.getNumVectors() <<
".");
671 A_->apply(X, Y, mode);
674template <
class MatrixType>
676 const char methodName[] =
"Ifpack2::Relaxation::initialize";
678 TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error, methodName <<
": The "
679 "input matrix A is null. Please call setMatrix() with "
680 "a nonnull input matrix before calling this method.");
682 Teuchos::RCP<Teuchos::Time> timer =
683 Teuchos::TimeMonitor::getNewCounter(methodName);
685 double startTime = timer->wallTime();
688 Teuchos::TimeMonitor timeMon(*timer);
689 isInitialized_ =
false;
692 auto rowMap = A_->getRowMap();
693 auto comm = rowMap.is_null() ? Teuchos::null : rowMap->getComm();
694 IsParallel_ = !comm.is_null() && comm->getSize() > 1;
704 Importer_ = IsParallel_ ? A_->getGraph()->getImporter() : Teuchos::null;
707 Teuchos::RCP<const block_crs_matrix_type> A_bcrs =
708 Teuchos::rcp_dynamic_cast<const block_crs_matrix_type>(A_);
709 hasBlockCrsMatrix_ = !A_bcrs.is_null();
712 serialGaussSeidel_ = Teuchos::null;
714 if (PrecType_ == Details::MTGS || PrecType_ == Details::MTSGS ||
715 PrecType_ == Details::GS2 || PrecType_ == Details::SGS2) {
716 auto crsMat = Details::getCrsMatrix(A_);
717 TEUCHOS_TEST_FOR_EXCEPTION(crsMat.is_null(), std::logic_error, methodName <<
": "
718 "Multithreaded Gauss-Seidel methods currently only work "
719 "when the input matrix is a Tpetra::CrsMatrix.");
724 if (ifpack2_dump_matrix_) {
725 static int sequence_number = 0;
726 const std::string file_name =
"Ifpack2_MT_GS_" +
727 std::to_string(sequence_number++) +
".mtx";
728 using writer_type = Tpetra::MatrixMarket::Writer<crs_matrix_type>;
729 writer_type::writeSparseFile(file_name, crsMat);
732 this->mtKernelHandle_ = Teuchos::rcp(
new mt_kernel_handle_type());
733 if (mtKernelHandle_->get_gs_handle() ==
nullptr) {
734 if (PrecType_ == Details::GS2 || PrecType_ == Details::SGS2)
735 mtKernelHandle_->create_gs_handle(KokkosSparse::GS_TWOSTAGE);
736 else if (this->clusterSize_ == 1) {
737 mtKernelHandle_->create_gs_handle(KokkosSparse::GS_DEFAULT, this->mtColoringAlgorithm_);
738 mtKernelHandle_->get_point_gs_handle()->set_long_row_threshold(longRowThreshold_);
740 mtKernelHandle_->create_gs_handle(KokkosSparse::CLUSTER_DEFAULT, this->clusterSize_, this->mtColoringAlgorithm_);
742 local_matrix_device_type kcsr = crsMat->getLocalMatrixDevice();
743 if (PrecType_ == Details::GS2 || PrecType_ == Details::SGS2) {
745 mtKernelHandle_->set_gs_set_num_inner_sweeps(NumInnerSweeps_);
746 mtKernelHandle_->set_gs_set_num_outer_sweeps(NumOuterSweeps_);
747 mtKernelHandle_->set_gs_set_inner_damp_factor(InnerDampingFactor_);
748 mtKernelHandle_->set_gs_twostage(!InnerSpTrsv_, A_->getLocalNumRows());
749 mtKernelHandle_->set_gs_twostage_compact_form(CompactForm_);
752 KokkosSparse::gauss_seidel_symbolic(
753 mtKernelHandle_.getRawPtr(),
754 A_->getLocalNumRows(),
755 A_->getLocalNumCols(),
758 is_matrix_structurally_symmetric_);
762 InitializeTime_ += (timer->wallTime() - startTime);
764 isInitialized_ =
true;
768template <
typename BlockDiagView>
769struct InvertDiagBlocks {
770 typedef typename BlockDiagView::size_type Size;
773 typedef Kokkos::MemoryTraits<Kokkos::Unmanaged> Unmanaged;
774 template <
typename View>
775 using UnmanagedView = Kokkos::View<
typename View::data_type,
typename View::array_layout,
776 typename View::device_type, Unmanaged>;
778 typedef typename BlockDiagView::non_const_value_type Scalar;
779 typedef typename BlockDiagView::device_type Device;
780 typedef Kokkos::View<Scalar**, Kokkos::LayoutRight, Device> RWrk;
781 typedef Kokkos::View<int**, Kokkos::LayoutRight, Device> IWrk;
783 UnmanagedView<BlockDiagView> block_diag_;
787 UnmanagedView<RWrk> rwrk_;
789 UnmanagedView<IWrk> iwrk_;
792 InvertDiagBlocks(BlockDiagView& block_diag)
793 : block_diag_(block_diag) {
794 const auto blksz = block_diag.extent(1);
795 Kokkos::resize(rwrk_buf_, block_diag_.extent(0), blksz);
797 Kokkos::resize(iwrk_buf_, block_diag_.extent(0), blksz);
801 KOKKOS_INLINE_FUNCTION
802 void operator()(
const Size i,
int& jinfo)
const {
803 auto D_cur = Kokkos::subview(block_diag_, i, Kokkos::ALL(), Kokkos::ALL());
804 auto ipiv = Kokkos::subview(iwrk_, i, Kokkos::ALL());
805 auto work = Kokkos::subview(rwrk_, i, Kokkos::ALL());
807 Tpetra::GETF2(D_cur, ipiv, info);
812 Tpetra::GETRI(D_cur, ipiv, work, info);
818template <
class MatrixType>
819void Relaxation<MatrixType>::computeBlockCrs() {
821 using Teuchos::Array;
822 using Teuchos::ArrayRCP;
823 using Teuchos::ArrayView;
828 using Teuchos::rcp_dynamic_cast;
829 using Teuchos::REDUCE_MAX;
830 using Teuchos::REDUCE_MIN;
831 using Teuchos::REDUCE_SUM;
832 using Teuchos::reduceAll;
833 typedef local_ordinal_type LO;
835 const std::string timerName(
"Ifpack2::Relaxation::computeBlockCrs");
836 Teuchos::RCP<Teuchos::Time> timer = Teuchos::TimeMonitor::lookupCounter(timerName);
837 if (timer.is_null()) {
838 timer = Teuchos::TimeMonitor::getNewCounter(timerName);
840 double startTime = timer->wallTime();
842 Teuchos::TimeMonitor timeMon(*timer);
844 TEUCHOS_TEST_FOR_EXCEPTION(
845 A_.is_null(), std::runtime_error,
846 "Ifpack2::Relaxation::"
847 "computeBlockCrs: The input matrix A is null. Please call setMatrix() "
848 "with a nonnull input matrix, then call initialize(), before calling "
850 auto blockCrsA = rcp_dynamic_cast<const block_crs_matrix_type>(A_);
851 TEUCHOS_TEST_FOR_EXCEPTION(
852 blockCrsA.is_null(), std::logic_error,
853 "Ifpack2::Relaxation::"
854 "computeBlockCrs: A_ is not a BlockCrsMatrix, but it should be if we "
855 "got this far. Please report this bug to the Ifpack2 developers.");
857 const scalar_type one = STS::one();
862 const LO lclNumMeshRows =
863 blockCrsA->getCrsGraph().getLocalNumRows();
864 const LO blockSize = blockCrsA->getBlockSize();
866 if (!savedDiagOffsets_) {
867 blockDiag_ = block_diag_type();
868 blockDiag_ = block_diag_type(
"Ifpack2::Relaxation::blockDiag_",
869 lclNumMeshRows, blockSize, blockSize);
870 if (Teuchos::as<LO>(diagOffsets_.extent(0)) < lclNumMeshRows) {
873 diagOffsets_ = Kokkos::View<size_t*, device_type>();
874 diagOffsets_ = Kokkos::View<size_t*, device_type>(
"offsets", lclNumMeshRows);
876 blockCrsA->getCrsGraph().getLocalDiagOffsets(diagOffsets_);
877 TEUCHOS_TEST_FOR_EXCEPTION(
static_cast<size_t>(diagOffsets_.extent(0)) !=
878 static_cast<size_t>(blockDiag_.extent(0)),
879 std::logic_error,
"diagOffsets_.extent(0) = " << diagOffsets_.extent(0) <<
" != blockDiag_.extent(0) = " << blockDiag_.extent(0) <<
". Please report this bug to the Ifpack2 developers.");
880 savedDiagOffsets_ =
true;
882 blockCrsA->getLocalDiagCopy(blockDiag_, diagOffsets_);
889 unmanaged_block_diag_type blockDiag = blockDiag_;
891 if (DoL1Method_ && IsParallel_) {
892 const scalar_type two = one + one;
893 const size_t maxLength = A_->getLocalMaxNumRowEntries();
894 nonconst_local_inds_host_view_type indices(
"indices", maxLength);
895 nonconst_values_host_view_type values_(
"values", maxLength * blockSize * blockSize);
896 size_t numEntries = 0;
898 for (LO i = 0; i < lclNumMeshRows; ++i) {
900 blockCrsA->getLocalRowCopy(i, indices, values_, numEntries);
901 scalar_type* values =
reinterpret_cast<scalar_type*
>(values_.data());
903 auto diagBlock = Kokkos::subview(blockDiag, i, ALL(), ALL());
904 for (LO subRow = 0; subRow < blockSize; ++subRow) {
905 magnitude_type diagonal_boost = STM::zero();
906 for (
size_t k = 0; k < numEntries; ++k) {
907 if (indices[k] >= lclNumMeshRows) {
908 const size_t offset = blockSize * blockSize * k + subRow * blockSize;
909 for (LO subCol = 0; subCol < blockSize; ++subCol) {
910 diagonal_boost += STS::magnitude(values[offset + subCol] / two);
914 if (STS::magnitude(diagBlock(subRow, subRow)) < L1Eta_ * diagonal_boost) {
915 diagBlock(subRow, subRow) += diagonal_boost;
923 Impl::InvertDiagBlocks<unmanaged_block_diag_type> idb(blockDiag);
924 typedef typename unmanaged_block_diag_type::execution_space exec_space;
925 typedef Kokkos::RangePolicy<exec_space, LO> range_type;
927 Kokkos::parallel_reduce(range_type(0, lclNumMeshRows), idb, info);
932 TEUCHOS_TEST_FOR_EXCEPTION(info > 0, std::runtime_error,
"GETF2 or GETRI failed on = " << info <<
" diagonal blocks.");
938 const int numResults = 2;
940 int lclResults[2], gblResults[2];
941 lclResults[0] = info;
942 lclResults[1] = -info;
945 reduceAll<int, int>(*(A_->getGraph()->getComm()), REDUCE_MIN,
946 numResults, lclResults, gblResults);
947 TEUCHOS_TEST_FOR_EXCEPTION(gblResults[0] != 0 || gblResults[1] != 0, std::runtime_error,
948 "Ifpack2::Relaxation::compute: When processing the input "
949 "Tpetra::BlockCrsMatrix, one or more diagonal block LU factorizations "
950 "failed on one or more (MPI) processes.");
952 serialGaussSeidel_ = rcp(
new SerialGaussSeidel(blockCrsA, blockDiag_, localSmoothingIndices_, DampingFactor_));
955 ComputeTime_ += (timer->wallTime() - startTime);
960template <
class MatrixType>
962 using Teuchos::Array;
963 using Teuchos::ArrayRCP;
964 using Teuchos::ArrayView;
969 using Teuchos::REDUCE_MAX;
970 using Teuchos::REDUCE_MIN;
971 using Teuchos::REDUCE_SUM;
972 using Teuchos::reduceAll;
976 using IST =
typename vector_type::impl_scalar_type;
977 using KAT = KokkosKernels::ArithTraits<IST>;
979 const char methodName[] =
"Ifpack2::Relaxation::compute";
983 TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error, methodName <<
": "
984 "The input matrix A is null. Please call setMatrix() with a nonnull "
985 "input matrix, then call initialize(), before calling this method.");
988 if (!isInitialized()) {
992 if (hasBlockCrsMatrix_) {
997 Teuchos::RCP<Teuchos::Time> timer =
998 Teuchos::TimeMonitor::getNewCounter(methodName);
999 double startTime = timer->wallTime();
1002 Teuchos::TimeMonitor timeMon(*timer);
1011 IST oneOverMinDiagVal = KAT::one() /
static_cast<IST
>(SmallTraits<scalar_type>::eps());
1012 if (MinDiagonalValue_ != zero)
1013 oneOverMinDiagVal = KAT::one() /
static_cast<IST
>(MinDiagonalValue_);
1016 const magnitude_type minDiagValMag = STS::magnitude(MinDiagonalValue_);
1018 const LO numMyRows =
static_cast<LO
>(A_->getLocalNumRows());
1020 TEUCHOS_TEST_FOR_EXCEPTION(NumSweeps_ < 0, std::logic_error, methodName <<
": NumSweeps_ = " << NumSweeps_ <<
" < 0. "
1021 "Please report this bug to the Ifpack2 developers.");
1022 IsComputed_ =
false;
1024 if (Diagonal_.is_null()) {
1027 Diagonal_ = rcp(
new vector_type(A_->getRowMap(),
false));
1030 if (checkDiagEntries_) {
1036 size_t numSmallDiagEntries = 0;
1037 size_t numZeroDiagEntries = 0;
1038 size_t numNegDiagEntries = 0;
1045 A_->getLocalDiagCopy(*Diagonal_);
1046 std::unique_ptr<vector_type> origDiag;
1047 origDiag = std::unique_ptr<vector_type>(
new vector_type(*Diagonal_, Teuchos::Copy));
1048 auto diag2d = Diagonal_->getLocalViewHost(Tpetra::Access::ReadWrite);
1049 auto diag = Kokkos::subview(diag2d, Kokkos::ALL(), 0);
1056 if (numMyRows != 0) {
1058 minMagDiagEntryMag = d_0_mag;
1059 maxMagDiagEntryMag = d_0_mag;
1068 for (LO i = 0; i < numMyRows; ++i) {
1069 const IST d_i = diag(i);
1073 const auto d_i_real = getRealValue(d_i);
1077 if (d_i_real < STM::zero()) {
1078 ++numNegDiagEntries;
1080 if (d_i_mag < minMagDiagEntryMag) {
1081 minMagDiagEntryMag = d_i_mag;
1083 if (d_i_mag > maxMagDiagEntryMag) {
1084 maxMagDiagEntryMag = d_i_mag;
1087 if (fixTinyDiagEntries_) {
1089 if (d_i_mag <= minDiagValMag) {
1090 ++numSmallDiagEntries;
1091 if (d_i_mag == STM::zero()) {
1092 ++numZeroDiagEntries;
1094 diag(i) = oneOverMinDiagVal;
1096 diag(i) = KAT::one() / d_i;
1100 if (d_i_mag <= minDiagValMag) {
1101 ++numSmallDiagEntries;
1102 if (d_i_mag == STM::zero()) {
1103 ++numZeroDiagEntries;
1106 diag(i) = KAT::one() / d_i;
1124 const Comm<int>& comm = *(A_->getRowMap()->getComm());
1127 Array<magnitude_type> localVals(2);
1128 localVals[0] = minMagDiagEntryMag;
1130 localVals[1] = -maxMagDiagEntryMag;
1131 Array<magnitude_type> globalVals(2);
1132 reduceAll<int, magnitude_type>(comm, REDUCE_MIN, 2,
1133 localVals.getRawPtr(),
1134 globalVals.getRawPtr());
1135 globalMinMagDiagEntryMag_ = globalVals[0];
1136 globalMaxMagDiagEntryMag_ = -globalVals[1];
1138 Array<size_t> localCounts(3);
1139 localCounts[0] = numSmallDiagEntries;
1140 localCounts[1] = numZeroDiagEntries;
1141 localCounts[2] = numNegDiagEntries;
1142 Array<size_t> globalCounts(3);
1143 reduceAll<int, size_t>(comm, REDUCE_SUM, 3,
1144 localCounts.getRawPtr(),
1145 globalCounts.getRawPtr());
1146 globalNumSmallDiagEntries_ = globalCounts[0];
1147 globalNumZeroDiagEntries_ = globalCounts[1];
1148 globalNumNegDiagEntries_ = globalCounts[2];
1152 vector_type diff(A_->getRowMap());
1153 diff.reciprocal(*origDiag);
1154 diff.update(-one, *Diagonal_, one);
1155 globalDiagNormDiff_ = diff.norm2();
1162 bool debugAgainstSlowPath =
false;
1164 auto crsMat = Details::getCrsMatrix(A_);
1166 if (crsMat.get() && crsMat->isFillComplete()) {
1171 if (invDiagKernel_.is_null())
1174 invDiagKernel_->setMatrix(crsMat);
1175 invDiagKernel_->compute(*Diagonal_,
1176 DoL1Method_ && IsParallel_, L1Eta_,
1177 fixTinyDiagEntries_, minDiagValMag);
1178 savedDiagOffsets_ =
true;
1183 if (crsMat.is_null() || !crsMat->isFillComplete() || debugAgainstSlowPath) {
1191 if (debugAgainstSlowPath)
1192 Diagonal = rcp(
new vector_type(A_->getRowMap()));
1206 if (DoL1Method_ && IsParallel_) {
1208 auto diag =
Diagonal->getLocalViewHost(Tpetra::Access::ReadWrite);
1210 const size_t maxLength = A_row.getLocalMaxNumRowEntries();
1211 nonconst_local_inds_host_view_type indices(
"indices", maxLength);
1212 nonconst_values_host_view_type values(
"values", maxLength);
1215 for (LO i = 0; i < numMyRows; ++i) {
1216 A_row.getLocalRowCopy(i, indices, values, numEntries);
1218 for (
size_t k = 0; k < numEntries; ++k) {
1219 if (indices[k] >= numMyRows) {
1220 diagonal_boost += STS::magnitude(values[k] / two);
1223 if (KAT::magnitude(diag(i, 0)) < L1Eta_ * diagonal_boost) {
1224 diag(i, 0) += diagonal_boost;
1232 if (fixTinyDiagEntries_) {
1236 auto localDiag =
Diagonal->getLocalViewDevice(Tpetra::Access::ReadWrite);
1237 Kokkos::parallel_for(
1238 Kokkos::RangePolicy<MyExecSpace>(0, localDiag.extent(0)),
1240 auto d_i = localDiag(i, 0);
1243 if (d_i_mag <= minDiagValMag) {
1244 d_i = oneOverMinDiagVal;
1248 d_i = IST(KAT::one() / d_i);
1250 localDiag(i, 0) = d_i;
1256 if (debugAgainstSlowPath) {
1258 Diagonal->update(STS::one(), *Diagonal_, -STS::one());
1262 TEUCHOS_TEST_FOR_EXCEPTION(err > 100 * STM::eps(), std::logic_error, methodName <<
": "
1263 <<
"\"fast-path\" diagonal computation failed. "
1264 "\\|D1 - D2\\|_inf = "
1272 if (STS::isComplex) {
1273 ComputeFlops_ += 4.0 * numMyRows;
1275 ComputeFlops_ += numMyRows;
1278 if (PrecType_ == Ifpack2::Details::MTGS ||
1279 PrecType_ == Ifpack2::Details::MTSGS ||
1280 PrecType_ == Ifpack2::Details::GS2 ||
1281 PrecType_ == Ifpack2::Details::SGS2) {
1283 using scalar_view_t =
typename local_matrix_device_type::values_type;
1285 TEUCHOS_TEST_FOR_EXCEPTION(crsMat.is_null(), std::logic_error, methodName <<
": "
1286 "Multithreaded Gauss-Seidel methods currently only work "
1287 "when the input matrix is a Tpetra::CrsMatrix.");
1288 local_matrix_device_type kcsr = crsMat->getLocalMatrixDevice();
1292 auto diagView_2d = Diagonal_->getLocalViewDevice(Tpetra::Access::ReadWrite);
1293 scalar_view_t diagView_1d = Kokkos::subview(diagView_2d, Kokkos::ALL(), 0);
1294 KokkosSparse::gauss_seidel_numeric(
1295 mtKernelHandle_.getRawPtr(),
1296 A_->getLocalNumRows(),
1297 A_->getLocalNumCols(),
1302 is_matrix_structurally_symmetric_);
1303 }
else if (PrecType_ == Ifpack2::Details::GS || PrecType_ == Ifpack2::Details::SGS) {
1305 serialGaussSeidel_ = rcp(
new SerialGaussSeidel(crsMat, Diagonal_, localSmoothingIndices_, DampingFactor_));
1307 serialGaussSeidel_ = rcp(
new SerialGaussSeidel(A_, Diagonal_, localSmoothingIndices_, DampingFactor_));
1311 ComputeTime_ += (timer->wallTime() - startTime);
1316template <
class MatrixType>
1318 ApplyInverseRichardson(
const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
1319 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y)
const {
1321 const double numGlobalRows = as<double>(A_->getGlobalNumRows());
1322 const double numVectors = as<double>(X.getNumVectors());
1323 if (ZeroStartingSolution_) {
1327 Y.scale(DampingFactor_, X);
1333 double flopUpdate = 0.0;
1334 if (DampingFactor_ == STS::one()) {
1336 flopUpdate = numGlobalRows * numVectors;
1340 flopUpdate = numGlobalRows * numVectors;
1342 ApplyFlops_ += flopUpdate;
1343 if (NumSweeps_ == 1) {
1349 const int startSweep = ZeroStartingSolution_ ? 1 : 0;
1352 updateCachedMultiVector(Y.getMap(), as<size_t>(numVectors));
1354 for (
int j = startSweep; j < NumSweeps_; ++j) {
1356 Tpetra::Details::residual(*A_, Y, X, *cachedMV_);
1357 Y.update(DampingFactor_, *cachedMV_, STS::one());
1371 const double numGlobalNonzeros = as<double>(A_->getGlobalNumEntries());
1372 const double dampingFlops = (DampingFactor_ == STS::one()) ? 0.0 : 1.0;
1373 ApplyFlops_ += as<double>(NumSweeps_ - startSweep) * numVectors *
1374 (2.0 * numGlobalNonzeros + dampingFlops);
1377template <
class MatrixType>
1378void Relaxation<MatrixType>::
1379 ApplyInverseJacobi(
const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
1380 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y)
const {
1382 if (hasBlockCrsMatrix_) {
1383 ApplyInverseJacobi_BlockCrsMatrix(X, Y);
1387 const double numGlobalRows = as<double>(A_->getGlobalNumRows());
1388 const double numVectors = as<double>(X.getNumVectors());
1389 if (ZeroStartingSolution_) {
1394 Y.elementWiseMultiply(DampingFactor_, *Diagonal_, X, STS::zero());
1400 double flopUpdate = 0.0;
1401 if (DampingFactor_ == STS::one()) {
1403 flopUpdate = numGlobalRows * numVectors;
1407 flopUpdate = 2.0 * numGlobalRows * numVectors;
1409 ApplyFlops_ += flopUpdate;
1410 if (NumSweeps_ == 1) {
1416 const int startSweep = ZeroStartingSolution_ ? 1 : 0;
1419 updateCachedMultiVector(Y.getMap(), as<size_t>(numVectors));
1421 for (
int j = startSweep; j < NumSweeps_; ++j) {
1423 Tpetra::Details::residual(*A_, Y, X, *cachedMV_);
1424 Y.elementWiseMultiply(DampingFactor_, *Diagonal_, *cachedMV_, STS::one());
1438 const double numGlobalNonzeros = as<double>(A_->getGlobalNumEntries());
1439 const double dampingFlops = (DampingFactor_ == STS::one()) ? 0.0 : 1.0;
1440 ApplyFlops_ += as<double>(NumSweeps_ - startSweep) * numVectors *
1441 (2.0 * numGlobalRows + 2.0 * numGlobalNonzeros + dampingFlops);
1444template <
class MatrixType>
1445void Relaxation<MatrixType>::
1446 ApplyInverseJacobi_BlockCrsMatrix(
const Tpetra::MultiVector<scalar_type,
1448 global_ordinal_type,
1450 Tpetra::MultiVector<scalar_type,
1452 global_ordinal_type,
1453 node_type>& Y)
const {
1454 using Tpetra::BlockMultiVector;
1455 using BMV = BlockMultiVector<scalar_type, local_ordinal_type,
1456 global_ordinal_type, node_type>;
1458 const block_crs_matrix_type* blockMatConst =
1459 dynamic_cast<const block_crs_matrix_type*
>(A_.getRawPtr());
1460 TEUCHOS_TEST_FOR_EXCEPTION(blockMatConst ==
nullptr, std::logic_error,
1461 "This method should "
1462 "never be called if the matrix A_ is not a BlockCrsMatrix. "
1463 "Please report this bug to the Ifpack2 developers.");
1468 block_crs_matrix_type* blockMat =
1469 const_cast<block_crs_matrix_type*
>(blockMatConst);
1471 auto meshRowMap = blockMat->getRowMap();
1472 auto meshColMap = blockMat->getColMap();
1473 const local_ordinal_type blockSize = blockMat->getBlockSize();
1475 BMV X_blk(X, *meshColMap, blockSize);
1476 BMV Y_blk(Y, *meshRowMap, blockSize);
1478 if (ZeroStartingSolution_) {
1482 Y_blk.blockWiseMultiply(DampingFactor_, blockDiag_, X_blk);
1483 if (NumSweeps_ == 1) {
1488 auto pointRowMap = Y.getMap();
1489 const size_t numVecs = X.getNumVectors();
1493 BMV A_times_Y(*meshRowMap, *pointRowMap, blockSize, numVecs);
1497 const int startSweep = ZeroStartingSolution_ ? 1 : 0;
1499 for (
int j = startSweep; j < NumSweeps_; ++j) {
1500 blockMat->applyBlock(Y_blk, A_times_Y);
1502 Y_blk.blockJacobiUpdate(DampingFactor_, blockDiag_,
1503 X_blk, A_times_Y, STS::one());
1507template <
class MatrixType>
1508void Relaxation<MatrixType>::
1509 ApplyInverseSerialGS(
const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
1510 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
1511 Tpetra::ESweepDirection direction)
const {
1512 using this_type = Relaxation<MatrixType>;
1522 auto blockCrsMat = Teuchos::rcp_dynamic_cast<const block_crs_matrix_type>(A_);
1523 auto crsMat = Details::getCrsMatrix(A_);
1524 if (blockCrsMat.get()) {
1525 const_cast<this_type&
>(*this).ApplyInverseSerialGS_BlockCrsMatrix(*blockCrsMat, X, Y, direction);
1526 }
else if (crsMat.get()) {
1527 ApplyInverseSerialGS_CrsMatrix(*crsMat, X, Y, direction);
1529 ApplyInverseSerialGS_RowMatrix(X, Y, direction);
1533template <
class MatrixType>
1534void Relaxation<MatrixType>::
1535 ApplyInverseSerialGS_RowMatrix(
const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
1536 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
1537 Tpetra::ESweepDirection direction)
const {
1538 using Teuchos::Array;
1539 using Teuchos::ArrayRCP;
1540 using Teuchos::ArrayView;
1544 using Teuchos::rcpFromRef;
1545 typedef Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type> MV;
1550 if (ZeroStartingSolution_) {
1551 Y.putScalar(STS::zero());
1554 size_t NumVectors = X.getNumVectors();
1558 if (Importer_.is_null()) {
1559 updateCachedMultiVector(Y.getMap(), NumVectors);
1561 updateCachedMultiVector(Importer_->getTargetMap(), NumVectors);
1568 for (
int j = 0; j < NumSweeps_; ++j) {
1571 if (Importer_.is_null()) {
1577 Y2->doImport(Y, *Importer_, Tpetra::INSERT);
1580 serialGaussSeidel_->apply(*Y2, X, direction);
1584 Tpetra::deep_copy(Y, *Y2);
1589 const double dampingFlops = (DampingFactor_ == STS::one()) ? 0.0 : 1.0;
1590 const double numVectors = as<double>(X.getNumVectors());
1591 const double numGlobalRows = as<double>(A_->getGlobalNumRows());
1592 const double numGlobalNonzeros = as<double>(A_->getGlobalNumEntries());
1593 ApplyFlops_ += 2.0 * NumSweeps_ * numVectors *
1594 (2.0 * numGlobalRows + 2.0 * numGlobalNonzeros + dampingFlops);
1597template <
class MatrixType>
1598void Relaxation<MatrixType>::
1599 ApplyInverseSerialGS_CrsMatrix(
const crs_matrix_type& A,
1600 const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& B,
1601 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
1602 Tpetra::ESweepDirection direction)
const {
1603 using Teuchos::null;
1606 using Teuchos::rcp_const_cast;
1607 using Teuchos::rcpFromRef;
1608 typedef scalar_type Scalar;
1609 const char prefix[] =
"Ifpack2::Relaxation::SerialGS: ";
1610 const scalar_type ZERO = Teuchos::ScalarTraits<Scalar>::zero();
1612 TEUCHOS_TEST_FOR_EXCEPTION(
1613 !A.isFillComplete(), std::runtime_error,
1614 prefix <<
"The matrix is not fill complete.");
1615 TEUCHOS_TEST_FOR_EXCEPTION(
1616 NumSweeps_ < 0, std::invalid_argument,
1617 prefix <<
"The number of sweeps must be nonnegative, "
1618 "but you provided numSweeps = "
1619 << NumSweeps_ <<
" < 0.");
1621 if (NumSweeps_ == 0) {
1625 RCP<const import_type> importer = A.getGraph()->getImporter();
1627 RCP<const map_type> domainMap = A.getDomainMap();
1628 RCP<const map_type> rangeMap = A.getRangeMap();
1629 RCP<const map_type> rowMap = A.getGraph()->getRowMap();
1630 RCP<const map_type> colMap = A.getGraph()->getColMap();
1636 TEUCHOS_TEST_FOR_EXCEPTION(
1637 !X.getMap()->isSameAs(*domainMap), std::runtime_error,
1638 "Tpetra::CrsMatrix::gaussSeidelCopy requires that the input "
1639 "multivector X be in the domain Map of the matrix.");
1640 TEUCHOS_TEST_FOR_EXCEPTION(
1641 !B.getMap()->isSameAs(*rangeMap), std::runtime_error,
1642 "Tpetra::CrsMatrix::gaussSeidelCopy requires that the input "
1643 "B be in the range Map of the matrix.");
1644 TEUCHOS_TEST_FOR_EXCEPTION(
1645 !Diagonal_->getMap()->isSameAs(*rowMap), std::runtime_error,
1646 "Tpetra::CrsMatrix::gaussSeidelCopy requires that the input "
1647 "D be in the row Map of the matrix.");
1648 TEUCHOS_TEST_FOR_EXCEPTION(
1649 !rowMap->isSameAs(*rangeMap), std::runtime_error,
1650 "Tpetra::CrsMatrix::gaussSeidelCopy requires that the row Map and the "
1651 "range Map be the same (in the sense of Tpetra::Map::isSameAs).");
1652 TEUCHOS_TEST_FOR_EXCEPTION(
1653 !domainMap->isSameAs(*rangeMap), std::runtime_error,
1654 "Tpetra::CrsMatrix::gaussSeidelCopy requires that the domain Map and "
1655 "the range Map of the matrix be the same.");
1666 RCP<multivector_type> X_colMap;
1667 RCP<multivector_type> X_domainMap;
1668 bool copyBackOutput =
false;
1669 if (importer.is_null()) {
1670 X_colMap = Teuchos::rcpFromRef(X);
1671 X_domainMap = Teuchos::rcpFromRef(X);
1677 if (ZeroStartingSolution_) {
1678 X_colMap->putScalar(ZERO);
1682 updateCachedMultiVector(colMap, X.getNumVectors());
1683 X_colMap = cachedMV_;
1684 X_domainMap = X_colMap->offsetViewNonConst(domainMap, 0);
1686 if (ZeroStartingSolution_) {
1688 X_colMap->putScalar(ZERO);
1698 X_colMap->doImport(X, *importer, Tpetra::INSERT);
1700 copyBackOutput =
true;
1703 for (
int sweep = 0; sweep < NumSweeps_; ++sweep) {
1704 if (!importer.is_null() && sweep > 0) {
1707 X_colMap->doImport(*X_domainMap, *importer, Tpetra::INSERT);
1710 serialGaussSeidel_->apply(*X_colMap, B, direction);
1713 if (copyBackOutput) {
1715 deep_copy(X, *X_domainMap);
1716 }
catch (std::exception& e) {
1717 TEUCHOS_TEST_FOR_EXCEPTION(
1718 true, std::runtime_error, prefix <<
"deep_copy(X, *X_domainMap) "
1719 "threw an exception: "
1735 const double dampingFlops = (DampingFactor_ == STS::one()) ? 0.0 : 1.0;
1736 const double numVectors = X.getNumVectors();
1737 const double numGlobalRows = A_->getGlobalNumRows();
1738 const double numGlobalNonzeros = A_->getGlobalNumEntries();
1739 ApplyFlops_ += NumSweeps_ * numVectors *
1740 (2.0 * numGlobalRows + 2.0 * numGlobalNonzeros + dampingFlops);
1743template <
class MatrixType>
1744void Relaxation<MatrixType>::
1745 ApplyInverseSerialGS_BlockCrsMatrix(
const block_crs_matrix_type& A,
1746 const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
1747 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
1748 Tpetra::ESweepDirection direction) {
1751 using Teuchos::rcpFromRef;
1752 using Tpetra::INSERT;
1761 block_multivector_type yBlock(Y, *(A.getGraph()->getDomainMap()), A.getBlockSize());
1762 const block_multivector_type xBlock(X, *(A.getColMap()), A.getBlockSize());
1764 bool performImport =
false;
1765 RCP<block_multivector_type> yBlockCol;
1766 if (Importer_.is_null()) {
1767 yBlockCol = rcpFromRef(yBlock);
1769 if (yBlockColumnPointMap_.is_null() ||
1770 yBlockColumnPointMap_->getNumVectors() != yBlock.getNumVectors() ||
1771 yBlockColumnPointMap_->getBlockSize() != yBlock.getBlockSize()) {
1772 yBlockColumnPointMap_ =
1773 rcp(
new block_multivector_type(*(A.getColMap()), A.getBlockSize(),
1774 static_cast<local_ordinal_type
>(yBlock.getNumVectors())));
1776 yBlockCol = yBlockColumnPointMap_;
1777 if (pointImporter_.is_null()) {
1778 auto srcMap = rcp(
new map_type(yBlock.getPointMap()));
1779 auto tgtMap = rcp(
new map_type(yBlockCol->getPointMap()));
1780 pointImporter_ = rcp(
new import_type(srcMap, tgtMap));
1782 performImport =
true;
1785 multivector_type yBlock_mv;
1786 multivector_type yBlockCol_mv;
1787 RCP<const multivector_type> yBlockColPointDomain;
1788 if (performImport) {
1789 yBlock_mv = yBlock.getMultiVectorView();
1790 yBlockCol_mv = yBlockCol->getMultiVectorView();
1791 yBlockColPointDomain =
1792 yBlockCol_mv.offsetView(A.getDomainMap(), 0);
1795 if (ZeroStartingSolution_) {
1796 yBlockCol->putScalar(STS::zero());
1797 }
else if (performImport) {
1798 yBlockCol_mv.doImport(yBlock_mv, *pointImporter_, Tpetra::INSERT);
1801 for (
int sweep = 0; sweep < NumSweeps_; ++sweep) {
1802 if (performImport && sweep > 0) {
1803 yBlockCol_mv.doImport(yBlock_mv, *pointImporter_, Tpetra::INSERT);
1805 serialGaussSeidel_->applyBlock(*yBlockCol, xBlock, direction);
1806 if (performImport) {
1807 Tpetra::deep_copy(Y, *yBlockColPointDomain);
1812template <
class MatrixType>
1813void Relaxation<MatrixType>::
1814 ApplyInverseMTGS_CrsMatrix(
1815 const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& B,
1816 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
1817 Tpetra::ESweepDirection direction)
const {
1819 using Teuchos::null;
1822 using Teuchos::rcp_const_cast;
1823 using Teuchos::rcpFromRef;
1825 typedef scalar_type Scalar;
1827 const char prefix[] =
"Ifpack2::Relaxation::(reordered)MTGaussSeidel: ";
1828 const Scalar ZERO = Teuchos::ScalarTraits<Scalar>::zero();
1830 auto crsMat = Details::getCrsMatrix(A_);
1831 TEUCHOS_TEST_FOR_EXCEPTION(crsMat.is_null(), std::logic_error,
1832 "Ifpack2::Relaxation::apply: "
1833 "Multithreaded Gauss-Seidel methods currently only work when the "
1834 "input matrix is a Tpetra::CrsMatrix.");
1837 TEUCHOS_TEST_FOR_EXCEPTION(!localSmoothingIndices_.is_null(), std::logic_error,
1838 "Ifpack2's implementation of Multithreaded Gauss-Seidel does not "
1839 "implement the case where the user supplies an iteration order. "
1840 "This error used to appear as \"MT GaussSeidel ignores the given "
1842 "I tried to add more explanation, but I didn't implement \"MT "
1843 "GaussSeidel\" [sic]. "
1844 "You'll have to ask the person who did.");
1846 TEUCHOS_TEST_FOR_EXCEPTION(!crsMat->isFillComplete(), std::runtime_error, prefix <<
"The "
1847 "input CrsMatrix is not fill complete. Please call fillComplete "
1848 "on the matrix, then do setup again, before calling apply(). "
1849 "\"Do setup\" means that if only the matrix's values have changed "
1850 "since last setup, you need only call compute(). If the matrix's "
1851 "structure may also have changed, you must first call initialize(), "
1852 "then call compute(). If you have not set up this preconditioner "
1853 "for this matrix before, you must first call initialize(), then "
1855 TEUCHOS_TEST_FOR_EXCEPTION(NumSweeps_ < 0, std::logic_error, prefix <<
": NumSweeps_ = " << NumSweeps_ <<
" < 0. Please report this bug to the Ifpack2 "
1857 if (NumSweeps_ == 0) {
1861 RCP<const import_type> importer = crsMat->getGraph()->getImporter();
1862 TEUCHOS_TEST_FOR_EXCEPTION(
1863 !crsMat->getGraph()->getExporter().is_null(), std::runtime_error,
1864 "This method's implementation currently requires that the matrix's row, "
1865 "domain, and range Maps be the same. This cannot be the case, because "
1866 "the matrix has a nontrivial Export object.");
1868 RCP<const map_type> domainMap = crsMat->getDomainMap();
1869 RCP<const map_type> colMap = crsMat->getGraph()->getColMap();
1870 [[maybe_unused]] RCP<const map_type> rangeMap = crsMat->getRangeMap();
1871 [[maybe_unused]] RCP<const map_type> rowMap = crsMat->getGraph()->getRowMap();
1877 TEUCHOS_TEST_FOR_EXCEPTION(
1878 !X.getMap()->isSameAs(*domainMap), std::runtime_error,
1879 "Ifpack2::Relaxation::MTGaussSeidel requires that the input "
1880 "multivector X be in the domain Map of the matrix.");
1881 TEUCHOS_TEST_FOR_EXCEPTION(
1882 !B.getMap()->isSameAs(*rangeMap), std::runtime_error,
1883 "Ifpack2::Relaxation::MTGaussSeidel requires that the input "
1884 "B be in the range Map of the matrix.");
1885 TEUCHOS_TEST_FOR_EXCEPTION(
1886 !rowMap->isSameAs(*rangeMap), std::runtime_error,
1887 "Ifpack2::Relaxation::MTGaussSeidel requires that the row Map and the "
1888 "range Map be the same (in the sense of Tpetra::Map::isSameAs).");
1889 TEUCHOS_TEST_FOR_EXCEPTION(
1890 !domainMap->isSameAs(*rangeMap), std::runtime_error,
1891 "Ifpack2::Relaxation::MTGaussSeidel requires that the domain Map and "
1892 "the range Map of the matrix be the same.");
1903 RCP<multivector_type> X_colMap;
1904 RCP<multivector_type> X_domainMap;
1905 bool copyBackOutput =
false;
1906 if (importer.is_null()) {
1907 if (X.isConstantStride()) {
1908 X_colMap = rcpFromRef(X);
1909 X_domainMap = rcpFromRef(X);
1916 if (ZeroStartingSolution_) {
1917 X_colMap->putScalar(ZERO);
1925 updateCachedMultiVector(colMap, as<size_t>(X.getNumVectors()));
1926 X_colMap = cachedMV_;
1930 X_domainMap = X_colMap;
1931 if (!ZeroStartingSolution_) {
1933 deep_copy(*X_domainMap, X);
1934 }
catch (std::exception& e) {
1935 std::ostringstream os;
1936 os <<
"Ifpack2::Relaxation::MTGaussSeidel: "
1937 "deep_copy(*X_domainMap, X) threw an exception: "
1939 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::runtime_error, e.what());
1942 copyBackOutput =
true;
1955 updateCachedMultiVector(colMap, as<size_t>(X.getNumVectors()));
1956 X_colMap = cachedMV_;
1958 X_domainMap = X_colMap->offsetViewNonConst(domainMap, 0);
1960 if (ZeroStartingSolution_) {
1962 X_colMap->putScalar(ZERO);
1972 X_colMap->doImport(X, *importer, Tpetra::CombineMode::INSERT);
1974 copyBackOutput =
true;
1980 RCP<const multivector_type> B_in;
1981 if (B.isConstantStride()) {
1982 B_in = rcpFromRef(B);
1987 RCP<multivector_type> B_in_nonconst = rcp(
new multivector_type(rowMap, B.getNumVectors()));
1989 deep_copy(*B_in_nonconst, B);
1990 }
catch (std::exception& e) {
1991 std::ostringstream os;
1992 os <<
"Ifpack2::Relaxation::MTGaussSeidel: "
1993 "deep_copy(*B_in_nonconst, B) threw an exception: "
1995 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::runtime_error, e.what());
1997 B_in = rcp_const_cast<const multivector_type>(B_in_nonconst);
2011 local_matrix_device_type kcsr = crsMat->getLocalMatrixDevice();
2013 bool update_y_vector =
true;
2015 bool zero_x_vector =
false;
2017 for (
int sweep = 0; sweep < NumSweeps_; ++sweep) {
2018 if (!importer.is_null() && sweep > 0) {
2021 X_colMap->doImport(*X_domainMap, *importer, Tpetra::CombineMode::INSERT);
2024 if (direction == Tpetra::Symmetric) {
2025 KokkosSparse::symmetric_gauss_seidel_apply(mtKernelHandle_.getRawPtr(), A_->getLocalNumRows(), A_->getLocalNumCols(),
2026 kcsr.graph.row_map, kcsr.graph.entries, kcsr.values,
2027 X_colMap->getLocalViewDevice(Tpetra::Access::ReadWrite),
2028 B_in->getLocalViewDevice(Tpetra::Access::ReadOnly),
2029 zero_x_vector, update_y_vector, DampingFactor_, 1);
2030 }
else if (direction == Tpetra::Forward) {
2031 KokkosSparse::forward_sweep_gauss_seidel_apply(mtKernelHandle_.getRawPtr(), A_->getLocalNumRows(), A_->getLocalNumCols(),
2032 kcsr.graph.row_map, kcsr.graph.entries, kcsr.values,
2033 X_colMap->getLocalViewDevice(Tpetra::Access::ReadWrite),
2034 B_in->getLocalViewDevice(Tpetra::Access::ReadOnly),
2035 zero_x_vector, update_y_vector, DampingFactor_, 1);
2036 }
else if (direction == Tpetra::Backward) {
2037 KokkosSparse::backward_sweep_gauss_seidel_apply(mtKernelHandle_.getRawPtr(), A_->getLocalNumRows(), A_->getLocalNumCols(),
2038 kcsr.graph.row_map, kcsr.graph.entries, kcsr.values,
2039 X_colMap->getLocalViewDevice(Tpetra::Access::ReadWrite),
2040 B_in->getLocalViewDevice(Tpetra::Access::ReadOnly),
2041 zero_x_vector, update_y_vector, DampingFactor_, 1);
2043 TEUCHOS_TEST_FOR_EXCEPTION(
2044 true, std::invalid_argument,
2045 prefix <<
"The 'direction' enum does not have any of its valid "
2046 "values: Forward, Backward, or Symmetric.");
2048 update_y_vector =
false;
2051 if (copyBackOutput) {
2053 deep_copy(X, *X_domainMap);
2054 }
catch (std::exception& e) {
2055 TEUCHOS_TEST_FOR_EXCEPTION(
2056 true, std::runtime_error, prefix <<
"deep_copy(X, *X_domainMap) "
2057 "threw an exception: "
2062 const double dampingFlops = (DampingFactor_ == STS::one()) ? 0.0 : 1.0;
2063 const double numVectors = as<double>(X.getNumVectors());
2064 const double numGlobalRows = as<double>(A_->getGlobalNumRows());
2065 const double numGlobalNonzeros = as<double>(A_->getGlobalNumEntries());
2066 double ApplyFlops = NumSweeps_ * numVectors *
2067 (2.0 * numGlobalRows + 2.0 * numGlobalNonzeros + dampingFlops);
2068 if (direction == Tpetra::Symmetric)
2070 ApplyFlops_ += ApplyFlops;
2073template <
class MatrixType>
2075 std::ostringstream os;
2080 os <<
"\"Ifpack2::Relaxation\": {";
2082 os <<
"Initialized: " << (isInitialized() ?
"true" :
"false") <<
", "
2083 <<
"Computed: " << (isComputed() ?
"true" :
"false") <<
", ";
2089 if (PrecType_ == Ifpack2::Details::JACOBI) {
2091 }
else if (PrecType_ == Ifpack2::Details::GS) {
2092 os <<
"Gauss-Seidel";
2093 }
else if (PrecType_ == Ifpack2::Details::SGS) {
2094 os <<
"Symmetric Gauss-Seidel";
2095 }
else if (PrecType_ == Ifpack2::Details::MTGS) {
2096 os <<
"MT Gauss-Seidel";
2097 }
else if (PrecType_ == Ifpack2::Details::MTSGS) {
2098 os <<
"MT Symmetric Gauss-Seidel";
2099 }
else if (PrecType_ == Ifpack2::Details::GS2) {
2100 os <<
"Two-stage Gauss-Seidel";
2101 }
else if (PrecType_ == Ifpack2::Details::SGS2) {
2102 os <<
"Two-stage Symmetric Gauss-Seidel";
2106 if (hasBlockCrsMatrix_)
2110 <<
"sweeps: " << NumSweeps_ <<
", "
2111 <<
"damping factor: " << DampingFactor_ <<
", ";
2113 if (PrecType_ == Ifpack2::Details::MTGS || PrecType_ == Ifpack2::Details::MTSGS) {
2114 os <<
"\"relaxation: mtgs cluster size\": " << clusterSize_ <<
", ";
2115 os <<
"\"relaxation: long row threshold\": " << longRowThreshold_ <<
", ";
2116 os <<
"\"relaxation: symmetric matrix structure\": " << (is_matrix_structurally_symmetric_ ?
"true" :
"false") <<
", ";
2117 os <<
"\"relaxation: relaxation: mtgs coloring algorithm\": ";
2118 switch (mtColoringAlgorithm_) {
2119 case KokkosGraph::COLORING_DEFAULT:
2122 case KokkosGraph::COLORING_SERIAL:
2125 case KokkosGraph::COLORING_VB:
2128 case KokkosGraph::COLORING_VBBIT:
2131 case KokkosGraph::COLORING_VBCS:
2134 case KokkosGraph::COLORING_VBD:
2137 case KokkosGraph::COLORING_VBDBIT:
2140 case KokkosGraph::COLORING_EB:
2149 if (PrecType_ == Ifpack2::Details::GS2 ||
2150 PrecType_ == Ifpack2::Details::SGS2) {
2151 os <<
"outer sweeps: " << NumOuterSweeps_ <<
", "
2152 <<
"inner sweeps: " << NumInnerSweeps_ <<
", "
2153 <<
"inner damping factor: " << InnerDampingFactor_ <<
", ";
2157 os <<
"use l1: " << DoL1Method_ <<
", "
2158 <<
"l1 eta: " << L1Eta_ <<
", ";
2162 os <<
"Matrix: null";
2164 os <<
"Global matrix dimensions: ["
2165 << A_->getGlobalNumRows() <<
", " << A_->getGlobalNumCols() <<
"]"
2166 <<
", Global nnz: " << A_->getGlobalNumEntries();
2173template <
class MatrixType>
2175 describe(Teuchos::FancyOStream& out,
2176 const Teuchos::EVerbosityLevel verbLevel)
const {
2178 using Teuchos::OSTab;
2179 using Teuchos::TypeNameTraits;
2180 using Teuchos::VERB_DEFAULT;
2181 using Teuchos::VERB_EXTREME;
2182 using Teuchos::VERB_HIGH;
2183 using Teuchos::VERB_LOW;
2184 using Teuchos::VERB_MEDIUM;
2185 using Teuchos::VERB_NONE;
2187 const Teuchos::EVerbosityLevel vl =
2188 (verbLevel == VERB_DEFAULT) ? VERB_LOW : verbLevel;
2190 const int myRank = this->getComm()->getRank();
2198 if (vl != VERB_NONE && myRank == 0) {
2202 out <<
"\"Ifpack2::Relaxation\":" << endl;
2204 out <<
"MatrixType: \"" << TypeNameTraits<MatrixType>::name() <<
"\""
2206 if (this->getObjectLabel() !=
"") {
2207 out <<
"Label: " << this->getObjectLabel() << endl;
2209 out <<
"Initialized: " << (isInitialized() ?
"true" :
"false") << endl
2210 <<
"Computed: " << (isComputed() ?
"true" :
"false") << endl
2211 <<
"Parameters: " << endl;
2214 out <<
"\"relaxation: type\": ";
2215 if (PrecType_ == Ifpack2::Details::JACOBI) {
2217 }
else if (PrecType_ == Ifpack2::Details::GS) {
2218 out <<
"Gauss-Seidel";
2219 }
else if (PrecType_ == Ifpack2::Details::SGS) {
2220 out <<
"Symmetric Gauss-Seidel";
2221 }
else if (PrecType_ == Ifpack2::Details::MTGS) {
2222 out <<
"MT Gauss-Seidel";
2223 }
else if (PrecType_ == Ifpack2::Details::MTSGS) {
2224 out <<
"MT Symmetric Gauss-Seidel";
2225 }
else if (PrecType_ == Ifpack2::Details::GS2) {
2226 out <<
"Two-stage Gauss-Seidel";
2227 }
else if (PrecType_ == Ifpack2::Details::SGS2) {
2228 out <<
"Two-stage Symmetric Gauss-Seidel";
2235 <<
"\"relaxation: sweeps\": " << NumSweeps_ << endl
2236 <<
"\"relaxation: damping factor\": " << DampingFactor_ << endl
2237 <<
"\"relaxation: min diagonal value\": " << MinDiagonalValue_ << endl
2238 <<
"\"relaxation: zero starting solution\": " << ZeroStartingSolution_ << endl
2239 <<
"\"relaxation: backward mode\": " << DoBackwardGS_ << endl
2240 <<
"\"relaxation: use l1\": " << DoL1Method_ << endl
2241 <<
"\"relaxation: l1 eta\": " << L1Eta_ << endl;
2242 if (PrecType_ == Ifpack2::Details::MTGS || PrecType_ == Ifpack2::Details::MTSGS) {
2243 out <<
"\"relaxation: mtgs cluster size\": " << clusterSize_ << endl;
2244 out <<
"\"relaxation: long row threshold\": " << longRowThreshold_ << endl;
2245 out <<
"\"relaxation: symmetric matrix structure\": " << (is_matrix_structurally_symmetric_ ?
"true" :
"false") << endl;
2246 out <<
"\"relaxation: relaxation: mtgs coloring algorithm\": ";
2247 switch (mtColoringAlgorithm_) {
2248 case KokkosGraph::COLORING_DEFAULT:
2251 case KokkosGraph::COLORING_SERIAL:
2254 case KokkosGraph::COLORING_VB:
2257 case KokkosGraph::COLORING_VBBIT:
2260 case KokkosGraph::COLORING_VBCS:
2263 case KokkosGraph::COLORING_VBD:
2266 case KokkosGraph::COLORING_VBDBIT:
2269 case KokkosGraph::COLORING_EB:
2277 if (PrecType_ == Ifpack2::Details::GS2 || PrecType_ == Ifpack2::Details::SGS2) {
2278 out <<
"\"relaxation: inner damping factor\": " << InnerDampingFactor_ << endl;
2279 out <<
"\"relaxation: outer sweeps\" : " << NumOuterSweeps_ << endl;
2280 out <<
"\"relaxation: inner sweeps\" : " << NumInnerSweeps_ << endl;
2283 out <<
"Computed quantities:" << endl;
2286 out <<
"Global number of rows: " << A_->getGlobalNumRows() << endl
2287 <<
"Global number of columns: " << A_->getGlobalNumCols() << endl;
2289 if (checkDiagEntries_ && isComputed()) {
2290 out <<
"Properties of input diagonal entries:" << endl;
2293 out <<
"Magnitude of minimum-magnitude diagonal entry: "
2294 << globalMinMagDiagEntryMag_ << endl
2295 <<
"Magnitude of maximum-magnitude diagonal entry: "
2296 << globalMaxMagDiagEntryMag_ << endl
2297 <<
"Number of diagonal entries with small magnitude: "
2298 << globalNumSmallDiagEntries_ << endl
2299 <<
"Number of zero diagonal entries: "
2300 << globalNumZeroDiagEntries_ << endl
2301 <<
"Number of diagonal entries with negative real part: "
2302 << globalNumNegDiagEntries_ << endl
2303 <<
"Abs 2-norm diff between computed and actual inverse "
2304 <<
"diagonal: " << globalDiagNormDiff_ << endl;
2308 out <<
"Saved diagonal offsets: "
2309 << (savedDiagOffsets_ ?
"true" :
"false") << endl;
2311 out <<
"Call counts and total times (in seconds): " << endl;
2314 out <<
"initialize: " << endl;
2317 out <<
"Call count: " << NumInitialize_ << endl;
2318 out <<
"Total time: " << InitializeTime_ << endl;
2320 out <<
"compute: " << endl;
2323 out <<
"Call count: " << NumCompute_ << endl;
2324 out <<
"Total time: " << ComputeTime_ << endl;
2326 out <<
"apply: " << endl;
2329 out <<
"Call count: " << NumApply_ << endl;
2330 out <<
"Total time: " << ApplyTime_ << endl;
2338#define IFPACK2_RELAXATION_INSTANT(S, LO, GO, N) \
2339 template class Ifpack2::Relaxation<Tpetra::RowMatrix<S, LO, GO, N>>;
Declaration of Ifpack2::Details::Behavior, a class that describes Ifpack2's run-time behavior.
File for utility functions.
static bool debug()
Whether Ifpack2 is in debug mode.
Definition Ifpack2_Details_Behavior.cpp:31
Ifpack2's implementation of Trilinos::Details::LinearSolver interface.
Definition Ifpack2_Details_LinearSolver_decl.hpp:75
Diagonal preconditioner.
Definition Ifpack2_Diagonal_decl.hpp:45
Relaxation preconditioners for Tpetra::RowMatrix and Tpetra::CrsMatrix sparse matrices.
Definition Ifpack2_Relaxation_decl.hpp:215
Relaxation(const Teuchos::RCP< const row_matrix_type > &A)
Constructor.
Definition Ifpack2_Relaxation_def.hpp:183
MatrixType::global_ordinal_type global_ordinal_type
The type of global indices in the input MatrixType.
Definition Ifpack2_Relaxation_decl.hpp:227
void setParameters(const Teuchos::ParameterList ¶ms)
Set the relaxation / preconditioner parameters.
Definition Ifpack2_Relaxation_def.hpp:435
MatrixType::node_type node_type
The Node type used by the input MatrixType.
Definition Ifpack2_Relaxation_decl.hpp:230
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
The communicator over which the matrix and vectors are distributed.
Definition Ifpack2_Relaxation_def.hpp:443
Teuchos::RCP< const Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > > getDomainMap() const
Returns the Tpetra::Map object associated with the domain of this operator.
Definition Ifpack2_Relaxation_def.hpp:462
double getApplyTime() const
Total time in seconds spent in all calls to apply().
Definition Ifpack2_Relaxation_def.hpp:515
int getNumCompute() const
Total number of calls to compute().
Definition Ifpack2_Relaxation_def.hpp:495
Teuchos::RCP< const row_matrix_type > getMatrix() const
The matrix to be preconditioned.
Definition Ifpack2_Relaxation_def.hpp:454
void compute()
Compute the preconditioner ("numeric setup");.
Definition Ifpack2_Relaxation_def.hpp:961
void initialize()
Initialize the preconditioner ("symbolic setup").
Definition Ifpack2_Relaxation_def.hpp:675
double getComputeTime() const
Total time in seconds spent in all calls to compute().
Definition Ifpack2_Relaxation_def.hpp:510
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Print the object's attributes to the given output stream.
Definition Ifpack2_Relaxation_def.hpp:2175
std::string description() const
A simple one-line description of this object.
Definition Ifpack2_Relaxation_def.hpp:2074
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Return a list of all the parameters that this class accepts.
Definition Ifpack2_Relaxation_def.hpp:192
double getInitializeTime() const
Total time in seconds spent in all calls to initialize().
Definition Ifpack2_Relaxation_def.hpp:505
virtual void setMatrix(const Teuchos::RCP< const row_matrix_type > &A)
Change the matrix to be preconditioned.
Definition Ifpack2_Relaxation_def.hpp:163
MatrixType::scalar_type scalar_type
The type of the entries of the input MatrixType.
Definition Ifpack2_Relaxation_decl.hpp:221
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, returning the result in Y.
Definition Ifpack2_Relaxation_def.hpp:542
MatrixType::local_ordinal_type local_ordinal_type
The type of local indices in the input MatrixType.
Definition Ifpack2_Relaxation_decl.hpp:224
void applyMat(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) const
Apply the input matrix to X, returning the result in Y.
Definition Ifpack2_Relaxation_def.hpp:654
Tpetra::RowMatrix< scalar_type, local_ordinal_type, global_ordinal_type, node_type > row_matrix_type
Tpetra::RowMatrix specialization used by this class.
Definition Ifpack2_Relaxation_decl.hpp:241
Teuchos::ScalarTraits< scalar_type >::magnitudeType magnitude_type
The type of the magnitude (absolute value) of a matrix entry.
Definition Ifpack2_Relaxation_decl.hpp:236
size_t getNodeSmootherComplexity() const
Get a rough estimate of cost per iteration.
Definition Ifpack2_Relaxation_def.hpp:530
int getNumApply() const
Total number of calls to apply().
Definition Ifpack2_Relaxation_def.hpp:500
int getNumInitialize() const
Total number of calls to initialize().
Definition Ifpack2_Relaxation_def.hpp:490
double getComputeFlops() const
Total number of floating-point operations over all calls to compute().
Definition Ifpack2_Relaxation_def.hpp:520
bool hasTransposeApply() const
Whether apply() and applyMat() let you apply the transpose or conjugate transpose.
Definition Ifpack2_Relaxation_def.hpp:485
Teuchos::RCP< const Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > > getRangeMap() const
Returns the Tpetra::Map object associated with the range of this operator.
Definition Ifpack2_Relaxation_def.hpp:475
double getApplyFlops() const
Total number of floating-point operations over all calls to apply().
Definition Ifpack2_Relaxation_def.hpp:525
Preconditioners and smoothers for Tpetra sparse matrices.
Definition Ifpack2_AdditiveSchwarz_decl.hpp:40
void getValidParameters(Teuchos::ParameterList ¶ms)
Fills a list which contains all the parameters possibly used by Ifpack2.
Definition Ifpack2_Parameters.cpp:18