488 if (KAT::magnitude(myRow.value(entryIdx)) > KAT::magnitude(tol)) {
489 diagVals(rowIdx, 0) = KAT::one() / myRow.value(entryIdx);
491 diagVals(rowIdx, 0) = valReplacement_dev;
497 if (!foundDiagEntry) {
498 diagVals(rowIdx, 0) = KAT::zero();
502 Kokkos::parallel_for(
503 "Utilities::GetMatrixDiagonalInverse",
504 Kokkos::RangePolicy<ordinal_type, execution_space>(0, numRows),
505 KOKKOS_LAMBDA(
const ordinal_type rowIdx) {
506 auto myRow = localMatrix.rowConst(rowIdx);
507 for (ordinal_type entryIdx = 0; entryIdx < myRow.length; ++entryIdx) {
508 diagVals(rowIdx, 0) += KAT::magnitude(myRow.value(entryIdx));
510 if (KAT::magnitude(diagVals(rowIdx, 0)) > KAT::magnitude(tol))
511 diagVals(rowIdx, 0) = KAT::one() / diagVals(rowIdx, 0);
513 diagVals(rowIdx, 0) = valReplacement_dev;
519template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
520Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
522 GetLumpedMatrixDiagonal(Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>
const& A,
const bool doReciprocal,
525 const bool replaceSingleEntryRowWithZero,
526 const bool useAverageAbsDiagVal) {
527 typedef Teuchos::ScalarTraits<Scalar> TST;
529 RCP<Vector> diag = Teuchos::null;
530 const Scalar zero = TST::zero();
531 const Scalar one = TST::one();
532 const Scalar two = one + one;
534 Teuchos::RCP<const Matrix> rcpA = Teuchos::rcpFromRef(A);
536 RCP<const Xpetra::BlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>> bA =
537 Teuchos::rcp_dynamic_cast<const Xpetra::BlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>(rcpA);
538 if (bA == Teuchos::null) {
539 RCP<const Map> rowMap = rcpA->getRowMap();
540 diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(rowMap,
false);
542 if (rowMap->lib() == Xpetra::UnderlyingLib::UseTpetra) {
543 Teuchos::TimeMonitor MM = *Teuchos::TimeMonitor::getNewTimer(
"UtilitiesBase::GetLumpedMatrixDiagonal (Kokkos implementation)");
545 using local_vector_type =
typename Vector::dual_view_type::t_dev_um;
546 using local_matrix_type =
typename Matrix::local_matrix_device_type;
547 using execution_space =
typename local_vector_type::execution_space;
550 using values_type =
typename local_matrix_type::values_type;
551 using scalar_type =
typename values_type::non_const_value_type;
552 using mag_type =
typename KokkosKernels::ArithTraits<scalar_type>::mag_type;
553 using KAT_S =
typename KokkosKernels::ArithTraits<scalar_type>;
554 using KAT_M =
typename KokkosKernels::ArithTraits<mag_type>;
555 using size_type =
typename local_matrix_type::non_const_size_type;
557 local_vector_type diag_dev = diag->getLocalViewDevice(Tpetra::Access::OverwriteAll);
558 local_matrix_type local_mat_dev = rcpA->getLocalMatrixDevice();
559 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(diag_dev.extent(0)));
560 scalar_type valReplacement_dev = valReplacement;
563 Kokkos::View<int*, execution_space> nnzPerRow(
"nnz per rows", diag_dev.extent(0));
564 Kokkos::View<scalar_type*, execution_space> regSum(
"regSum", diag_dev.extent(0));
565 Kokkos::View<mag_type, execution_space> avgAbsDiagVal_dev(
"avgAbsDiagVal");
566 Kokkos::View<int, execution_space> numDiagsEqualToOne_dev(
"numDiagsEqualToOne");
569 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"GetLumpedMatrixDiagonal: parallel_for (doReciprocal)");
570 Kokkos::parallel_for(
571 "GetLumpedMatrixDiagonal", my_policy,
572 KOKKOS_LAMBDA(
const int rowIdx) {
573 diag_dev(rowIdx, 0) = KAT_S::zero();
574 for (size_type entryIdx = local_mat_dev.graph.row_map(rowIdx);
575 entryIdx < local_mat_dev.graph.row_map(rowIdx + 1);
577 regSum(rowIdx) += local_mat_dev.values(entryIdx);
578 if (KAT_M::zero() < KAT_S::abs(local_mat_dev.values(entryIdx))) {
581 diag_dev(rowIdx, 0) += KAT_S::abs(local_mat_dev.values(entryIdx));
582 if (rowIdx == local_mat_dev.graph.entries(entryIdx)) {
583 Kokkos::atomic_add(&avgAbsDiagVal_dev(), KAT_S::abs(local_mat_dev.values(entryIdx)));
587 if (nnzPerRow(rowIdx) == 1 && KAT_S::magnitude(diag_dev(rowIdx, 0)) == KAT_M::one()) {
588 Kokkos::atomic_add(&numDiagsEqualToOne_dev(), 1);
592 if (useAverageAbsDiagVal) {
593 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"GetLumpedMatrixDiagonal: useAverageAbsDiagVal");
594 typename Kokkos::View<mag_type, execution_space>::host_mirror_type avgAbsDiagVal = Kokkos::create_mirror_view(avgAbsDiagVal_dev);
595 Kokkos::deep_copy(avgAbsDiagVal, avgAbsDiagVal_dev);
596 int numDiagsEqualToOne;
597 Kokkos::deep_copy(numDiagsEqualToOne, numDiagsEqualToOne_dev);
599 tol = TST::magnitude(100 * Teuchos::ScalarTraits<Scalar>::eps()) * (avgAbsDiagVal() - numDiagsEqualToOne) / (rowMap->getLocalNumElements() - numDiagsEqualToOne);
603 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"ComputeLumpedDiagonalInverse: parallel_for (doReciprocal)");
604 Kokkos::parallel_for(
605 "ComputeLumpedDiagonalInverse", my_policy,
606 KOKKOS_LAMBDA(
const int rowIdx) {
607 if (replaceSingleEntryRowWithZero && nnzPerRow(rowIdx) <= 1) {
608 diag_dev(rowIdx, 0) = KAT_S::zero();
609 }
else if ((diag_dev(rowIdx, 0) != KAT_S::zero()) && (KAT_S::magnitude(diag_dev(rowIdx, 0)) < KAT_S::magnitude(2 * regSum(rowIdx)))) {
610 diag_dev(rowIdx, 0) = KAT_S::one() / KAT_S::magnitude(2 * regSum(rowIdx));
612 if (KAT_S::magnitude(diag_dev(rowIdx, 0)) > tol) {
613 diag_dev(rowIdx, 0) = KAT_S::one() / diag_dev(rowIdx, 0);
615 diag_dev(rowIdx, 0) = valReplacement_dev;
622 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"GetLumpedMatrixDiagonal: parallel_for");
623 Kokkos::parallel_for(
624 "GetLumpedMatrixDiagonal", my_policy,
625 KOKKOS_LAMBDA(
const int rowIdx) {
626 diag_dev(rowIdx, 0) = KAT_S::zero();
627 for (size_type entryIdx = local_mat_dev.graph.row_map(rowIdx);
628 entryIdx < local_mat_dev.graph.row_map(rowIdx + 1);
630 diag_dev(rowIdx, 0) += KAT_S::magnitude(local_mat_dev.values(entryIdx));
636 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"UtilitiesBase: GetLumpedMatrixDiagonal: (Teuchos implementation)");
637 ArrayRCP<Scalar> diagVals = diag->getDataNonConst(0);
638 Teuchos::Array<Scalar> regSum(diag->getLocalLength());
639 Teuchos::ArrayView<const LocalOrdinal> cols;
640 Teuchos::ArrayView<const Scalar> vals;
642 std::vector<int> nnzPerRow(rowMap->getLocalNumElements());
647 const Magnitude zeroMagn = TST::magnitude(zero);
648 Magnitude avgAbsDiagVal = TST::magnitude(zero);
649 int numDiagsEqualToOne = 0;
650 for (
size_t i = 0; i < rowMap->getLocalNumElements(); ++i) {
652 rcpA->getLocalRowView(i, cols, vals);
655 regSum[i] += vals[j];
656 const Magnitude rowEntryMagn = TST::magnitude(vals[j]);
657 if (rowEntryMagn > zeroMagn)
659 diagVals[i] += rowEntryMagn;
660 if (
static_cast<size_t>(cols[j]) == i)
661 avgAbsDiagVal += rowEntryMagn;
663 if (nnzPerRow[i] == 1 && TST::magnitude(diagVals[i]) == 1.)
664 numDiagsEqualToOne++;
666 if (useAverageAbsDiagVal)
667 tol = TST::magnitude(100 * Teuchos::ScalarTraits<Scalar>::eps()) * (avgAbsDiagVal - numDiagsEqualToOne) / (rowMap->getLocalNumElements() - numDiagsEqualToOne);
669 for (
size_t i = 0; i < rowMap->getLocalNumElements(); ++i) {
670 if (replaceSingleEntryRowWithZero && nnzPerRow[i] <=
static_cast<int>(1))
672 else if ((diagVals[i] != zero) && (TST::magnitude(diagVals[i]) < TST::magnitude(two * regSum[i])))
673 diagVals[i] = one / TST::magnitude((two * regSum[i]));
675 if (TST::magnitude(diagVals[i]) > tol)
676 diagVals[i] = one / diagVals[i];
678 diagVals[i] = valReplacement;
685 TEUCHOS_TEST_FOR_EXCEPTION(doReciprocal, Xpetra::Exceptions::RuntimeError,
686 "UtilitiesBase::GetLumpedMatrixDiagonal(): extracting reciprocal of diagonal of a blocked matrix is not supported");
687 diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(bA->getRangeMapExtractor()->getFullMap(),
true);
689 for (
size_t row = 0; row < bA->Rows(); ++row) {
690 for (
size_t col = 0; col < bA->Cols(); ++col) {
691 if (!bA->getMatrix(row, col).is_null()) {
693 bool bThyraMode = bA->getRangeMapExtractor()->getThyraMode() && (Teuchos::rcp_dynamic_cast<Xpetra::BlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>(bA->getMatrix(row, col)) == Teuchos::null);
694 RCP<Vector> ddtemp = bA->getRangeMapExtractor()->ExtractVector(diag, row, bThyraMode);
695 RCP<const Vector> dd = GetLumpedMatrixDiagonal(*(bA->getMatrix(row, col)));
696 ddtemp->update(Teuchos::as<Scalar>(1.0), *dd, Teuchos::as<Scalar>(1.0));
697 bA->getRangeMapExtractor()->InsertVector(ddtemp, row, diag, bThyraMode);
706template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
707Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
711 RCP<const Map> rowMap = A.getRowMap();
712 auto diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(rowMap,
false);
715 using local_vector_type =
typename Vector::dual_view_type::t_dev_um;
716 using local_matrix_type =
typename Matrix::local_matrix_device_type;
717 using execution_space =
typename local_vector_type::execution_space;
718 using values_type =
typename local_matrix_type::values_type;
719 using scalar_type =
typename values_type::non_const_value_type;
720 using KAT_S =
typename KokkosKernels::ArithTraits<scalar_type>;
722 auto diag_dev = diag->getLocalViewDevice(Tpetra::Access::OverwriteAll);
723 auto local_mat_dev = A.getLocalMatrixDevice();
724 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(diag_dev.extent(0)));
726 Kokkos::parallel_for(
727 "GetMatrixMaxMinusOffDiagonal", my_policy,
729 auto mymax = KAT_S::zero();
730 auto row = local_mat_dev.rowConst(rowIdx);
731 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
732 if (rowIdx != row.colidx(entryIdx)) {
733 if (KAT_S::real(mymax) < -KAT_S::real(row.value(entryIdx)))
734 mymax = -KAT_S::real(row.value(entryIdx));
737 diag_dev(rowIdx, 0) = mymax;
743template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
744Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
746 GetMatrixMaxMinusOffDiagonal(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber) {
747 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()), std::runtime_error,
"GetMatrixMaxMinusOffDiagonal: BlockNumber must match's A's column map.");
750 RCP<const Map> rowMap = A.getRowMap();
751 auto diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(rowMap,
false);
754 using local_vector_type =
typename Vector::dual_view_type::t_dev_um;
755 using local_matrix_type =
typename Matrix::local_matrix_device_type;
756 using execution_space =
typename local_vector_type::execution_space;
757 using values_type =
typename local_matrix_type::values_type;
758 using scalar_type =
typename values_type::non_const_value_type;
759 using KAT_S =
typename KokkosKernels::ArithTraits<scalar_type>;
761 auto diag_dev = diag->getLocalViewDevice(Tpetra::Access::OverwriteAll);
762 auto local_mat_dev = A.getLocalMatrixDevice();
763 auto local_block_dev = BlockNumber.getLocalViewDevice(Tpetra::Access::ReadOnly);
764 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(diag_dev.extent(0)));
766 Kokkos::parallel_for(
767 "GetMatrixMaxMinusOffDiagonal", my_policy,
769 auto mymax = KAT_S::zero();
770 auto row = local_mat_dev.row(rowIdx);
771 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
772 if ((rowIdx != row.colidx(entryIdx)) && (local_block_dev(rowIdx, 0) == local_block_dev(row.colidx(entryIdx), 0))) {
773 if (KAT_S::real(mymax) < -KAT_S::real(row.value(entryIdx)))
774 mymax = -KAT_S::real(row.value(entryIdx));
777 diag_dev(rowIdx, 0) = mymax;
783template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
784Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
786 GetInverse(Teuchos::RCP<
const Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> v,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tol,
Scalar valReplacement) {
787 RCP<Vector> ret = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(v->getMap(),
true);
790 RCP<const BlockedVector> bv = Teuchos::rcp_dynamic_cast<const BlockedVector>(v);
791 if (bv.is_null() ==
false) {
792 RCP<BlockedVector> bret = Teuchos::rcp_dynamic_cast<BlockedVector>(ret);
793 TEUCHOS_TEST_FOR_EXCEPTION(bret.is_null() ==
true,
MueLu::Exceptions::RuntimeError,
"MueLu::UtilitiesBase::GetInverse: return vector should be of type BlockedVector");
794 RCP<const BlockedMap> bmap = bv->getBlockedMap();
795 for (
size_t r = 0; r < bmap->getNumMaps(); ++r) {
796 RCP<const MultiVector> submvec = bv->getMultiVector(r, bmap->getThyraMode());
797 RCP<const Vector> subvec = submvec->getVector(0);
799 bret->setMultiVector(r, subvecinf, bmap->getThyraMode());
805 ArrayRCP<Scalar> retVals = ret->getDataNonConst(0);
806 ArrayRCP<const Scalar> inputVals = v->getData(0);
807 for (
size_t i = 0; i < v->getMap()->getLocalNumElements(); ++i) {
808 if (Teuchos::ScalarTraits<Scalar>::magnitude(inputVals[i]) > tol)
809 retVals[i] = Teuchos::ScalarTraits<Scalar>::one() / inputVals[i];
811 retVals[i] = valReplacement;
854template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
855RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
858 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
859 RCP<Vector> localDiag = GetMatrixDiagonal(A);
860 RCP<const Import> importer = A.getCrsGraph()->getImporter();
861 if (importer.is_null() && !rowMap->isSameAs(*colMap)) {
862 importer = ImportFactory::Build(rowMap, colMap);
864 if (!importer.is_null()) {
865 RCP<Vector> diagonal = VectorFactory::Build(colMap,
false);
866 diagonal->doImport(*localDiag, *(importer), Xpetra::INSERT);
872template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
873RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
876 using STS =
typename Teuchos::ScalarTraits<SC>;
879 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
880 RCP<const BlockedMap> browMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
881 if (!browMap.is_null()) rowMap = browMap->getMap();
883 RCP<Vector> local = Xpetra::VectorFactory<SC, LO, GO, Node>::Build(rowMap);
884 RCP<Vector> ghosted = Xpetra::VectorFactory<SC, LO, GO, Node>::Build(colMap,
true);
885 ArrayRCP<SC> localVals = local->getDataNonConst(0);
887 for (LO row = 0; row < static_cast<LO>(A.getRowMap()->getLocalNumElements()); ++row) {
888 size_t nnz = A.getNumEntriesInLocalRow(row);
889 ArrayView<const LO> indices;
890 ArrayView<const SC> vals;
891 A.getLocalRowView(row, indices, vals);
895 for (LO colID = 0; colID < static_cast<LO>(nnz); colID++) {
896 if (indices[colID] != row) {
903 RCP<const Xpetra::Import<LO, GO, Node>> importer;
904 importer = A.getCrsGraph()->getImporter();
905 if (importer == Teuchos::null) {
906 importer = Xpetra::ImportFactory<LO, GO, Node>::Build(rowMap, colMap);
908 ghosted->doImport(*local, *(importer), Xpetra::INSERT);
912template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
916 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
917 using STS =
typename Teuchos::ScalarTraits<Scalar>;
918 using MTS =
typename Teuchos::ScalarTraits<Magnitude>;
920 using RealValuedVector = Xpetra::Vector<MT, LO, GO, Node>;
923 RCP<const BlockedMap> browMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
924 if (!browMap.is_null()) rowMap = browMap->getMap();
926 RCP<RealValuedVector> local = Xpetra::VectorFactory<MT, LO, GO, Node>::Build(rowMap);
927 RCP<RealValuedVector> ghosted = Xpetra::VectorFactory<MT, LO, GO, Node>::Build(colMap,
true);
928 ArrayRCP<MT> localVals = local->getDataNonConst(0);
930 for (LO rowIdx = 0; rowIdx < static_cast<LO>(A.getRowMap()->getLocalNumElements()); ++rowIdx) {
931 size_t nnz = A.getNumEntriesInLocalRow(rowIdx);
932 ArrayView<const LO> indices;
933 ArrayView<const SC> vals;
934 A.getLocalRowView(rowIdx, indices, vals);
938 for (LO colID = 0; colID < static_cast<LO>(nnz); ++colID) {
939 if (indices[colID] != rowIdx) {
940 si += STS::magnitude(vals[colID]);
943 localVals[rowIdx] = si;
946 RCP<const Xpetra::Import<LO, GO, Node>> importer;
947 importer = A.getCrsGraph()->getImporter();
948 if (importer == Teuchos::null) {
949 importer = Xpetra::ImportFactory<LO, GO, Node>::Build(rowMap, colMap);
951 ghosted->doImport(*local, *(importer), Xpetra::INSERT);
955template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
959 using local_matrix_type =
typename Matrix::local_matrix_device_type;
960 using execution_space =
typename local_matrix_type::execution_space;
961 using KAT_S =
typename KokkosKernels::ArithTraits<typename local_matrix_type::value_type>;
963 auto local_mat_dev = A.getLocalMatrixDevice();
964 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(local_mat_dev.numRows()));
967 Kokkos::parallel_reduce(
968 "CountNegativeDiagonalEntries", my_policy,
970 auto row = local_mat_dev.row(rowIdx);
971 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
972 if (rowIdx == row.colidx(entryIdx) && KAT_S::real(row.value(entryIdx)) < 0)
978 MueLu_sumAll(A.getRowMap()->getComm(), count_l, count_g);
982template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
983Teuchos::Array<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>
985 ResidualNorm(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS) {
986 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
987 const size_t numVecs = X.getNumVectors();
988 RCP<MultiVector> RES = Residual(Op, X, RHS);
989 Teuchos::Array<Magnitude> norms(numVecs);
994template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
995Teuchos::Array<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>
997 ResidualNorm(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS, MultiVector& Resid) {
998 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
999 const size_t numVecs = X.getNumVectors();
1000 Residual(Op, X, RHS, Resid);
1001 Teuchos::Array<Magnitude> norms(numVecs);
1006template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1007RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
1009 Residual(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS) {
1010 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
1011 const size_t numVecs = X.getNumVectors();
1013 RCP<MultiVector> RES = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(RHS.getMap(), numVecs,
false);
1014 Op.residual(X, RHS, *RES);
1018template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1020 Residual(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS, MultiVector& Resid) {
1021 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides");
1022 TEUCHOS_TEST_FOR_EXCEPTION(Resid.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of residual vectors != number of right-hand sides");
1023 Op.residual(X, RHS, Resid);
1026template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1030 LocalOrdinal niters,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType diagonalReplacementTolerance,
bool verbose,
unsigned int seed) {
1032 "Utils::PowerMethod: operator must have domain and range maps that are equivalent.");
1035 RCP<Vector> diagInvVec;
1037 diagInvVec = GetMatrixDiagonalInverse(A, diagonalReplacementTolerance);
1040 Scalar lambda = PowerMethod(A, diagInvVec, niters, tolerance, verbose, seed);
1044template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1046UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1047 PowerMethod(
const Matrix& A,
const RCP<Vector>& diagInvVec,
1048 LocalOrdinal niters,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance,
bool verbose,
unsigned int seed) {
1049 TEUCHOS_TEST_FOR_EXCEPTION(!(A.getRangeMap()->isSameAs(*(A.getDomainMap()))), Exceptions::Incompatible,
1050 "Utils::PowerMethod: operator must have domain and range maps that are equivalent.");
1053 RCP<Vector> q = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getDomainMap(),
true);
1054 RCP<Vector> r = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRangeMap(),
true);
1055 RCP<Vector> z = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRangeMap(),
false);
1060 Teuchos::Array<Magnitude> norms(1);
1062 typedef Teuchos::ScalarTraits<Scalar> STS;
1064 const Scalar zero = STS::zero(), one = STS::one();
1067 Magnitude residual = STS::magnitude(zero);
1070 for (
int iter = 0; iter < niters; ++iter) {
1072 q->update(one / norms[0], *z, zero);
1074 if (diagInvVec != Teuchos::null)
1075 z->elementWiseMultiply(one, *diagInvVec, *z, zero);
1076 lambda = q->dot(*z);
1078 if (iter % 100 == 0 || iter + 1 == niters) {
1079 r->update(1.0, *z, -lambda, *q, zero);
1081 residual = STS::magnitude(norms[0] / lambda);
1083 std::cout <<
"Iter = " << iter
1084 <<
" Lambda = " << lambda
1085 <<
" Residual of A*q - lambda*q = " << residual
1089 if (residual < tolerance)
1095template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1096RCP<Teuchos::FancyOStream>
1099 RCP<Teuchos::FancyOStream> fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(os));
1103template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1104typename Teuchos::ScalarTraits<Scalar>::magnitudeType
1107 const size_t numVectors = v.size();
1109 Scalar d = Teuchos::ScalarTraits<Scalar>::zero();
1110 for (
size_t j = 0; j < numVectors; j++) {
1111 d += (v[j][i0] - v[j][i1]) * (v[j][i0] - v[j][i1]);
1113 return Teuchos::ScalarTraits<Scalar>::magnitude(d);
1116template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1117typename Teuchos::ScalarTraits<Scalar>::magnitudeType
1120 const size_t numVectors = v.size();
1121 using MT =
typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
1123 Scalar d = Teuchos::ScalarTraits<Scalar>::zero();
1124 for (
size_t j = 0; j < numVectors; j++) {
1125 d += Teuchos::as<MT>(weight[j]) * (v[j][i0] - v[j][i1]) * (v[j][i0] - v[j][i1]);
1127 return Teuchos::ScalarTraits<Scalar>::magnitude(d);
1130template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1131Teuchos::ArrayRCP<const bool>
1133 DetectDirichletRows(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType& tol,
bool count_twos_as_dirichlet) {
1135 typedef Teuchos::ScalarTraits<Scalar> STS;
1136 ArrayRCP<bool> boundaryNodes(numRows,
true);
1137 if (count_twos_as_dirichlet) {
1139 ArrayView<const LocalOrdinal> indices;
1140 ArrayView<const Scalar> vals;
1141 A.getLocalRowView(row, indices, vals);
1142 size_t nnz = A.getNumEntriesInLocalRow(row);
1145 for (col = 0; col < nnz; col++)
1146 if ((indices[col] != row) && STS::magnitude(vals[col]) > tol) {
1147 if (!boundaryNodes[row])
1149 boundaryNodes[row] =
false;
1152 boundaryNodes[row] =
true;
1157 ArrayView<const LocalOrdinal> indices;
1158 ArrayView<const Scalar> vals;
1159 A.getLocalRowView(row, indices, vals);
1160 size_t nnz = A.getNumEntriesInLocalRow(row);
1162 for (
size_t col = 0; col < nnz; col++)
1163 if ((indices[col] != row) && STS::magnitude(vals[col]) > tol) {
1164 boundaryNodes[row] =
false;
1169 return boundaryNodes;
1172template <
class CrsMatrix>
1173KOKKOS_FORCEINLINE_FUNCTION
bool isDirichletRow(
typename CrsMatrix::ordinal_type rowId,
1174 KokkosSparse::SparseRowViewConst<CrsMatrix>& row,
1175 const typename KokkosKernels::ArithTraits<typename CrsMatrix::value_type>::magnitudeType& tol,
1176 const bool count_twos_as_dirichlet) {
1177 using ATS = KokkosKernels::ArithTraits<typename CrsMatrix::value_type>;
1179 auto length = row.length;
1180 bool boundaryNode =
true;
1182 if (count_twos_as_dirichlet) {
1184 decltype(length) colID = 0;
1185 for (; colID < length; colID++)
1186 if ((row.colidx(colID) != rowId) &&
1187 (ATS::magnitude(row.value(colID)) > tol)) {
1190 boundaryNode =
false;
1192 if (colID == length)
1193 boundaryNode =
true;
1196 for (
decltype(length) colID = 0; colID < length; colID++)
1197 if ((row.colidx(colID) != rowId) &&
1198 (ATS::magnitude(row.value(colID)) > tol)) {
1199 boundaryNode =
false;
1203 return boundaryNode;
1206template <
class SC,
class LO,
class GO,
class NO,
class memory_space>
1207Kokkos::View<bool*, memory_space>
1209 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1210 const bool count_twos_as_dirichlet) {
1211 using impl_scalar_type =
typename KokkosKernels::ArithTraits<SC>::val_type;
1212 using ATS = KokkosKernels::ArithTraits<impl_scalar_type>;
1213 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
1214 using helpers = Xpetra::Helpers<SC, LO, GO, NO>;
1216 Kokkos::View<bool*, typename NO::device_type::memory_space> boundaryNodes;
1218 if (helpers::isTpetraBlockCrs(A)) {
1219 const Tpetra::BlockCrsMatrix<SC, LO, GO, NO>& Am = toTpetraBlock(A);
1220 auto b_graph = Am.getCrsGraph().getLocalGraphDevice();
1221 auto b_rowptr = Am.getCrsGraph().getLocalRowPtrsDevice();
1222 auto values = Am.getValuesDevice();
1223 LO numBlockRows = Am.getLocalNumRows();
1224 const LO stride = Am.getBlockSize() * Am.getBlockSize();
1226 boundaryNodes = Kokkos::View<bool*, typename NO::device_type::memory_space>(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), numBlockRows);
1228 if (count_twos_as_dirichlet)
1231 Kokkos::parallel_for(
1232 "MueLu:Utils::DetectDirichletRowsBlockCrs", range_type(0, numBlockRows),
1233 KOKKOS_LAMBDA(
const LO row) {
1234 auto rowView = b_graph.rowConst(row);
1235 auto length = rowView.length;
1236 LO valstart = b_rowptr[row] * stride;
1238 boundaryNodes(row) =
true;
1239 decltype(length) colID = 0;
1240 for (; colID < length; colID++) {
1241 if (rowView.colidx(colID) != row) {
1242 LO current = valstart + colID * stride;
1243 for (LO k = 0; k < stride; k++) {
1244 if (ATS::magnitude(values[current + k]) > tol) {
1245 boundaryNodes(row) =
false;
1250 if (boundaryNodes(row) ==
false)
1255 auto localMatrix = A.getLocalMatrixDevice();
1256 LO numRows = A.getLocalNumRows();
1257 boundaryNodes = Kokkos::View<bool*, typename NO::device_type::memory_space>(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), numRows);
1259 Kokkos::parallel_for(
1260 "MueLu:Utils::DetectDirichletRows", range_type(0, numRows),
1261 KOKKOS_LAMBDA(
const LO row) {
1262 auto rowView = localMatrix.rowConst(row);
1263 boundaryNodes(row) =
isDirichletRow(row, rowView, tol, count_twos_as_dirichlet);
1266 if constexpr (std::is_same<memory_space, typename NO::device_type::memory_space>::value)
1267 return boundaryNodes;
1269 Kokkos::View<bool*, memory_space> boundaryNodes2(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), boundaryNodes.extent(0));
1270 Kokkos::deep_copy(boundaryNodes2, boundaryNodes);
1271 return boundaryNodes2;
1274 Kokkos::View<bool*, memory_space> dummy(
"dummy", 0);
1278template <
class SC,
class LO,
class GO,
class NO>
1279Kokkos::View<bool*, typename NO::device_type::memory_space>
1282 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1283 const bool count_twos_as_dirichlet) {
1284 return MueLu::DetectDirichletRows_kokkos<SC, LO, GO, NO, typename NO::device_type::memory_space>(A, tol, count_twos_as_dirichlet);
1287template <
class SC,
class LO,
class GO,
class NO>
1288Kokkos::View<bool*, typename Kokkos::HostSpace>
1291 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1292 const bool count_twos_as_dirichlet) {
1293 return MueLu::DetectDirichletRows_kokkos<SC, LO, GO, NO, typename Kokkos::HostSpace>(A, tol, count_twos_as_dirichlet);
1296template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1297Teuchos::ArrayRCP<const bool>
1299 DetectDirichletRowsExt(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
bool& bHasZeroDiagonal,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType& tol) {
1301 bHasZeroDiagonal =
false;
1303 Teuchos::RCP<Vector> diagVec = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRowMap());
1304 A.getLocalDiagCopy(*diagVec);
1305 Teuchos::ArrayRCP<const Scalar> diagVecData = diagVec->getData(0);
1308 typedef Teuchos::ScalarTraits<Scalar> STS;
1309 ArrayRCP<bool> boundaryNodes(numRows,
false);
1311 ArrayView<const LocalOrdinal> indices;
1312 ArrayView<const Scalar> vals;
1313 A.getLocalRowView(row, indices, vals);
1315 bool bHasDiag =
false;
1316 for (
decltype(indices.size()) col = 0; col < indices.size(); col++) {
1317 if (indices[col] != row) {
1318 if (STS::magnitude(vals[col] / STS::magnitude(sqrt(STS::magnitude(diagVecData[row]) * STS::magnitude(diagVecData[col])))) > tol) {
1324 if (bHasDiag ==
false)
1325 bHasZeroDiagonal =
true;
1327 boundaryNodes[row] =
true;
1329 return boundaryNodes;
1332template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1335 const Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>& RHS,
1336 Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>& InitialGuess,
1337 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1338 const bool count_twos_as_dirichlet) {
1339 using range_type = Kokkos::RangePolicy<LO, typename Node::execution_space>;
1343 TEUCHOS_ASSERT_EQUALITY(numVectors, Teuchos::as<LocalOrdinal>(InitialGuess.getNumVectors()));
1344 if (Behavior::debug())
1345 TEUCHOS_ASSERT(RHS.getMap()->isCompatible(*InitialGuess.getMap()));
1347 auto lclRHS = RHS.getLocalViewDevice(Tpetra::Access::ReadOnly);
1348 auto lclInitialGuess = InitialGuess.getLocalViewDevice(Tpetra::Access::ReadWrite);
1349 auto lclA = A.getLocalMatrixDevice();
1351 Kokkos::parallel_for(
1352 "MueLu:Utils::EnforceInitialCondition", range_type(0, numRows),
1353 KOKKOS_LAMBDA(
const LO i) {
1354 auto row = lclA.rowConst(i);
1357 lclInitialGuess(i, j) = lclRHS(i, j);
1362template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1364 FindNonZeros(
const Teuchos::ArrayRCP<const Scalar> vals,
1365 Teuchos::ArrayRCP<bool> nonzeros) {
1366 TEUCHOS_ASSERT(vals.size() == nonzeros.size());
1367 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType magnitudeType;
1368 const magnitudeType eps = 2.0 * Teuchos::ScalarTraits<magnitudeType>::eps();
1369 for (
size_t i = 0; i < static_cast<size_t>(vals.size()); i++) {
1370 nonzeros[i] = (Teuchos::ScalarTraits<Scalar>::magnitude(vals[i]) > eps);
1375template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1377 FindNonZeros(
const typename Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dual_view_type::t_dev_const_um vals,
1378 Kokkos::View<bool*, typename Node::device_type> nonzeros) {
1379 using ATS = KokkosKernels::ArithTraits<Scalar>;
1380 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1381 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1382 TEUCHOS_ASSERT(vals.extent(0) == nonzeros.extent(0));
1383 const typename ATS::magnitudeType eps = 2.0 * impl_ATS::eps();
1385 Kokkos::parallel_for(
1386 "MueLu:Maxwell1::FindNonZeros", range_type(0, vals.extent(0)),
1387 KOKKOS_LAMBDA(
const size_t i) {
1388 nonzeros(i) = (impl_ATS::magnitude(vals(i, 0)) > eps);
1392template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1395 const Teuchos::ArrayRCP<bool>& dirichletRows,
1396 Teuchos::ArrayRCP<bool> dirichletCols,
1397 Teuchos::ArrayRCP<bool> dirichletDomain) {
1398 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1399 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1400 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowMap = A.getRowMap();
1401 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1402 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == rowMap->getLocalNumElements());
1403 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletCols.size()) == colMap->getLocalNumElements());
1404 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletDomain.size()) == domMap->getLocalNumElements());
1405 RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, 1,
true);
1407 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1408 if (dirichletRows[i]) {
1409 ArrayView<const LocalOrdinal> indices;
1410 ArrayView<const Scalar> values;
1411 A.getLocalRowView(i, indices, values);
1412 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
1413 myColsToZero->replaceLocalValue(indices[j], 0, one);
1417 RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero;
1418 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A.getCrsGraph()->getImporter();
1419 if (!importer.is_null()) {
1420 globalColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap, 1,
true);
1422 globalColsToZero->doExport(*myColsToZero, *importer, Xpetra::ADD);
1424 myColsToZero->doImport(*globalColsToZero, *importer, Xpetra::INSERT);
1426 globalColsToZero = myColsToZero;
1428 FindNonZeros(globalColsToZero->getData(0), dirichletDomain);
1429 FindNonZeros(myColsToZero->getData(0), dirichletCols);
1432template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1435 const Kokkos::View<bool*, typename Node::device_type>& dirichletRows,
1436 Kokkos::View<bool*, typename Node::device_type> dirichletCols,
1437 Kokkos::View<bool*, typename Node::device_type> dirichletDomain) {
1438 using ATS = KokkosKernels::ArithTraits<Scalar>;
1439 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1440 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1441 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1442 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowMap = A.getRowMap();
1443 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1444 TEUCHOS_ASSERT(dirichletRows.extent(0) == rowMap->getLocalNumElements());
1445 TEUCHOS_ASSERT(dirichletCols.extent(0) == colMap->getLocalNumElements());
1446 TEUCHOS_ASSERT(dirichletDomain.extent(0) == domMap->getLocalNumElements());
1447 RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap,
true);
1449 auto myColsToZeroView = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadWrite);
1450 auto localMatrix = A.getLocalMatrixDevice();
1451 Kokkos::parallel_for(
1452 "MueLu:Maxwell1::DetectDirichletCols", range_type(0, rowMap->getLocalNumElements()),
1454 if (dirichletRows(row)) {
1455 auto rowView = localMatrix.row(row);
1456 auto length = rowView.length;
1458 for (
decltype(length) colID = 0; colID < length; colID++)
1459 myColsToZeroView(rowView.colidx(colID), 0) = impl_ATS::one();
1463 RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero;
1464 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A.getCrsGraph()->getImporter();
1465 if (!importer.is_null()) {
1466 globalColsToZero = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap,
true);
1468 globalColsToZero->doExport(*myColsToZero, *importer, Xpetra::ADD);
1470 myColsToZero->doImport(*globalColsToZero, *importer, Xpetra::INSERT);
1472 globalColsToZero = myColsToZero;
1477template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1479 ApplyRowSumCriterion(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol, Teuchos::ArrayRCP<bool>& dirichletRows) {
1480 typedef Teuchos::ScalarTraits<Scalar> STS;
1481 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1482 typedef Teuchos::ScalarTraits<MT> MTS;
1483 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1484 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1485 size_t nnz = A.getNumEntriesInLocalRow(row);
1486 ArrayView<const LocalOrdinal> indices;
1487 ArrayView<const Scalar> vals;
1488 A.getLocalRowView(row, indices, vals);
1490 Scalar rowsum = STS::zero();
1491 Scalar diagval = STS::zero();
1493 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1496 diagval = vals[colID];
1497 rowsum += vals[colID];
1500 if (rowSumTol < MTS::one() && STS::magnitude(rowsum) > STS::magnitude(diagval) * rowSumTol) {
1502 dirichletRows[row] =
true;
1507template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1508void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1509 ApplyRowSumCriterion(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol, Teuchos::ArrayRCP<bool>& dirichletRows) {
1510 typedef Teuchos::ScalarTraits<Scalar> STS;
1511 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1512 typedef Teuchos::ScalarTraits<MT> MTS;
1513 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1515 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()), std::runtime_error,
"ApplyRowSumCriterion: BlockNumber must match's A's column map.");
1517 Teuchos::ArrayRCP<const LocalOrdinal> block_id = BlockNumber.getData(0);
1518 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1519 size_t nnz = A.getNumEntriesInLocalRow(row);
1520 ArrayView<const LocalOrdinal> indices;
1521 ArrayView<const Scalar> vals;
1522 A.getLocalRowView(row, indices, vals);
1524 Scalar rowsum = STS::zero();
1525 Scalar diagval = STS::zero();
1526 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1529 diagval = vals[colID];
1530 if (block_id[row] == block_id[col])
1531 rowsum += vals[colID];
1535 if (rowSumTol < MTS::one() && STS::magnitude(rowsum) > STS::magnitude(diagval) * rowSumTol) {
1537 dirichletRows[row] =
true;
1543template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node,
class memory_space>
1545 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1546 Kokkos::View<bool*, memory_space>& dirichletRows) {
1547 typedef Teuchos::ScalarTraits<Scalar> STS;
1548 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1550 auto dirichletRowsHost = Kokkos::create_mirror_view(dirichletRows);
1551 Kokkos::deep_copy(dirichletRowsHost, dirichletRows);
1553 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1554 size_t nnz = A.getNumEntriesInLocalRow(row);
1555 ArrayView<const LocalOrdinal> indices;
1556 ArrayView<const Scalar> vals;
1557 A.getLocalRowView(row, indices, vals);
1559 Scalar rowsum = STS::zero();
1560 Scalar diagval = STS::zero();
1561 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1564 diagval = vals[colID];
1565 rowsum += vals[colID];
1567 if (STS::real(rowsum) > STS::magnitude(diagval) * rowSumTol)
1568 dirichletRowsHost(row) =
true;
1571 Kokkos::deep_copy(dirichletRows, dirichletRowsHost);
1574template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1575void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1576 ApplyRowSumCriterion(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1577 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1578 Kokkos::View<bool*, typename Node::device_type::memory_space>& dirichletRows) {
1579 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, typename Node::device_type::memory_space>(A, rowSumTol, dirichletRows);
1582template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1583void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1584 ApplyRowSumCriterionHost(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1585 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1586 Kokkos::View<bool*, Kokkos::HostSpace>& dirichletRows) {
1587 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, Kokkos::HostSpace>(A, rowSumTol, dirichletRows);
1591template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node,
class memory_space>
1593 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1594 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1595 Kokkos::View<bool*, memory_space>& dirichletRows) {
1596 typedef Teuchos::ScalarTraits<Scalar> STS;
1597 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1599 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()), std::runtime_error,
"ApplyRowSumCriterion: BlockNumber must match's A's column map.");
1601 auto dirichletRowsHost = Kokkos::create_mirror_view(dirichletRows);
1602 Kokkos::deep_copy(dirichletRowsHost, dirichletRows);
1604 Teuchos::ArrayRCP<const LocalOrdinal> block_id = BlockNumber.getData(0);
1605 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1606 size_t nnz = A.getNumEntriesInLocalRow(row);
1607 ArrayView<const LocalOrdinal> indices;
1608 ArrayView<const Scalar> vals;
1609 A.getLocalRowView(row, indices, vals);
1611 Scalar rowsum = STS::zero();
1612 Scalar diagval = STS::zero();
1613 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1616 diagval = vals[colID];
1617 if (block_id[row] == block_id[col])
1618 rowsum += vals[colID];
1620 if (STS::real(rowsum) > STS::magnitude(diagval) * rowSumTol)
1621 dirichletRowsHost(row) =
true;
1624 Kokkos::deep_copy(dirichletRows, dirichletRowsHost);
1627template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1628void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1629 ApplyRowSumCriterion(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1630 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1631 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1632 Kokkos::View<bool*, typename Node::device_type::memory_space>& dirichletRows) {
1633 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, typename Node::device_type::memory_space>(A, BlockNumber, rowSumTol, dirichletRows);
1636template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1637void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1638 ApplyRowSumCriterionHost(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1639 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1640 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1641 Kokkos::View<bool*, Kokkos::HostSpace>& dirichletRows) {
1642 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, Kokkos::HostSpace>(A, BlockNumber, rowSumTol, dirichletRows);
1645template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1646Teuchos::ArrayRCP<const bool>
1649 const Teuchos::ArrayRCP<const bool>& dirichletRows) {
1650 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1651 Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1652 Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1653 Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1654 Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, 1);
1655 myColsToZero->putScalar(zero);
1657 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1658 if (dirichletRows[i]) {
1659 Teuchos::ArrayView<const LocalOrdinal> indices;
1660 Teuchos::ArrayView<const Scalar> values;
1661 A.getLocalRowView(i, indices, values);
1662 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
1663 myColsToZero->replaceLocalValue(indices[j], 0, one);
1667 Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap, 1);
1668 globalColsToZero->putScalar(zero);
1669 Teuchos::RCP<Xpetra::Export<LocalOrdinal, GlobalOrdinal, Node>> exporter = Xpetra::ExportFactory<LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, domMap);
1671 globalColsToZero->doExport(*myColsToZero, *exporter, Xpetra::ADD);
1673 myColsToZero->doImport(*globalColsToZero, *exporter, Xpetra::INSERT);
1674 Teuchos::ArrayRCP<const Scalar> myCols = myColsToZero->getData(0);
1675 Teuchos::ArrayRCP<bool> dirichletCols(colMap->getLocalNumElements(),
true);
1676 Magnitude eps = Teuchos::ScalarTraits<Magnitude>::eps();
1677 for (
size_t i = 0; i < colMap->getLocalNumElements(); i++) {
1678 dirichletCols[i] = Teuchos::ScalarTraits<Scalar>::magnitude(myCols[i]) > 2.0 * eps;
1680 return dirichletCols;
1683template <
class SC,
class LO,
class GO,
class NO>
1684Kokkos::View<bool*, typename NO::device_type>
1687 const Kokkos::View<const bool*, typename NO::device_type>& dirichletRows) {
1688 using ATS = KokkosKernels::ArithTraits<SC>;
1689 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1690 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
1691 using scalar_type =
typename KokkosKernels::ArithTraits<SC>::val_type;
1692 using mag_type =
typename KokkosKernels::ArithTraits<scalar_type>::mag_type;
1693 using KAT_M =
typename KokkosKernels::ArithTraits<mag_type>;
1694 using KAT_S =
typename KokkosKernels::ArithTraits<scalar_type>;
1696 SC zero = ATS::zero();
1698 auto localMatrix = A.getLocalMatrixDevice();
1699 LO numRows = A.getLocalNumRows();
1701 Teuchos::RCP<const Xpetra::Map<LO, GO, NO>> domMap = A.getDomainMap();
1702 Teuchos::RCP<const Xpetra::Map<LO, GO, NO>> colMap = A.getColMap();
1703 Teuchos::RCP<Xpetra::MultiVector<SC, LO, GO, NO>> myColsToZero = Xpetra::MultiVectorFactory<SC, LO, GO, NO>::Build(colMap, 1);
1704 myColsToZero->putScalar(zero);
1705 auto myColsToZeroView = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadWrite);
1707 Kokkos::parallel_for(
1708 "MueLu:Utils::DetectDirichletCols1", range_type(0, numRows),
1709 KOKKOS_LAMBDA(
const LO row) {
1710 if (dirichletRows(row)) {
1711 auto rowView = localMatrix.row(row);
1712 auto length = rowView.length;
1714 for (
decltype(length) colID = 0; colID < length; colID++) {
1715 if (KAT_S::abs(rowView.value(colID)) > KAT_M::zero())
1716 myColsToZeroView(rowView.colidx(colID), 0) = impl_ATS::one();
1721 Teuchos::RCP<Xpetra::MultiVector<SC, LO, GO, NO>> globalColsToZero = Xpetra::MultiVectorFactory<SC, LO, GO, NO>::Build(domMap, 1);
1722 globalColsToZero->putScalar(zero);
1723 Teuchos::RCP<Xpetra::Export<LO, GO, NO>> exporter = Xpetra::ExportFactory<LO, GO, NO>::Build(colMap, domMap);
1725 globalColsToZero->doExport(*myColsToZero, *exporter, Xpetra::ADD);
1727 myColsToZero->doImport(*globalColsToZero, *exporter, Xpetra::INSERT);
1729 auto myCols = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadOnly);
1730 size_t numColEntries = colMap->getLocalNumElements();
1731 Kokkos::View<bool*, typename NO::device_type> dirichletCols(Kokkos::ViewAllocateWithoutInitializing(
"dirichletCols"), numColEntries);
1732 const typename ATS::magnitudeType eps = 2.0 * ATS::eps();
1734 Kokkos::parallel_for(
1735 "MueLu:Utils::DetectDirichletCols2", range_type(0, numColEntries),
1736 KOKKOS_LAMBDA(
const size_t i) {
1737 dirichletCols(i) = impl_ATS::magnitude(myCols(i, 0)) > eps;
1739 return dirichletCols;
1742template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1745 Frobenius(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& B) {
1750 TEUCHOS_TEST_FOR_EXCEPTION(!A.getRowMap()->isSameAs(*B.getRowMap()),
Exceptions::Incompatible,
"MueLu::CGSolver::Frobenius: row maps are incompatible");
1751 TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete() || !B.isFillComplete(),
Exceptions::RuntimeError,
"Matrices must be fill completed");
1753 const Map& AColMap = *A.getColMap();
1754 const Map& BColMap = *B.getColMap();
1756 Teuchos::ArrayView<const LocalOrdinal> indA, indB;
1757 Teuchos::ArrayView<const Scalar> valA, valB;
1758 size_t nnzA = 0, nnzB = 0;
1770 Teuchos::Array<Scalar> valBAll(BColMap.getLocalNumElements());
1772 LocalOrdinal invalid = Teuchos::OrdinalTraits<LocalOrdinal>::invalid();
1773 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero(), f = zero, gf;
1774 size_t numRows = A.getLocalNumRows();
1775 for (
size_t i = 0; i < numRows; i++) {
1776 A.getLocalRowView(i, indA, valA);
1777 B.getLocalRowView(i, indB, valB);
1782 for (
size_t j = 0; j < nnzB; j++)
1783 valBAll[indB[j]] = valB[j];
1785 for (
size_t j = 0; j < nnzA; j++) {
1788 LocalOrdinal ind = BColMap.getLocalElement(AColMap.getGlobalElement(indA[j]));
1790 f += valBAll[ind] * valA[j];
1794 for (
size_t j = 0; j < nnzB; j++)
1795 valBAll[indB[j]] = zero;
1803template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1811 int maxint = INT_MAX;
1812 int mySeed = Teuchos::as<int>((maxint - 1) * (one - (comm.getRank() + 1) / (comm.getSize() + one)));
1813 if (mySeed < 1 || mySeed == maxint) {
1814 std::ostringstream errStr;
1815 errStr <<
"Error detected with random seed = " << mySeed <<
". It should be in the interval [1,2^31-2].";
1820 Teuchos::ScalarTraits<Scalar>::seedrandom(mySeed);
1823template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1825 FindDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1826 std::vector<LocalOrdinal>& dirichletRows,
bool count_twos_as_dirichlet) {
1827 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1828 dirichletRows.resize(0);
1829 for (
size_t i = 0; i < A->getLocalNumRows(); i++) {
1830 Teuchos::ArrayView<const LocalOrdinal> indices;
1831 Teuchos::ArrayView<const Scalar> values;
1832 A->getLocalRowView(i, indices, values);
1834 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1835 if (Teuchos::ScalarTraits<Scalar>::magnitude(values[j]) > Teuchos::ScalarTraits<MT>::eps()) {
1839 if (nnz == 1 || (count_twos_as_dirichlet && nnz == 2)) {
1840 dirichletRows.push_back(i);
1845template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1847 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1848 const std::vector<LocalOrdinal>& dirichletRows) {
1849 RCP<const Map> Rmap = A->getRowMap();
1850 RCP<const Map> Cmap = A->getColMap();
1851 Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1852 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1854 for (
size_t i = 0; i < dirichletRows.size(); i++) {
1855 GlobalOrdinal row_gid = Rmap->getGlobalElement(dirichletRows[i]);
1857 Teuchos::ArrayView<const LocalOrdinal> indices;
1858 Teuchos::ArrayView<const Scalar> values;
1859 A->getLocalRowView(dirichletRows[i], indices, values);
1861 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1862 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1863 if (Cmap->getGlobalElement(indices[j]) == row_gid)
1871template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1873 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1874 const Teuchos::ArrayRCP<const bool>& dirichletRows) {
1875 TEUCHOS_ASSERT(A->isFillComplete());
1876 RCP<const Map> domMap = A->getDomainMap();
1877 RCP<const Map> ranMap = A->getRangeMap();
1878 RCP<const Map> Rmap = A->getRowMap();
1879 RCP<const Map> Cmap = A->getColMap();
1880 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == Rmap->getLocalNumElements());
1881 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1882 const Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1884 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1885 if (dirichletRows[i]) {
1888 Teuchos::ArrayView<const LocalOrdinal> indices;
1889 Teuchos::ArrayView<const Scalar> values;
1890 A->getLocalRowView(i, indices, values);
1892 Teuchos::ArrayRCP<Scalar> valuesNC(values.size());
1893 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1894 if (Cmap->getGlobalElement(indices[j]) == row_gid)
1899 A->replaceLocalValues(i, indices, valuesNC());
1902 A->fillComplete(domMap, ranMap);
1905template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1907 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1908 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows) {
1909 TEUCHOS_ASSERT(A->isFillComplete());
1910 using ATS = KokkosKernels::ArithTraits<Scalar>;
1911 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1912 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1914 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A->getDomainMap();
1915 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> ranMap = A->getRangeMap();
1916 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> Rmap = A->getRowMap();
1917 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> Cmap = A->getColMap();
1919 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == Rmap->getLocalNumElements());
1921 auto localMatrix = A->getLocalMatrixDevice();
1922 auto localRmap = Rmap->getLocalMap();
1923 auto localCmap = Cmap->getLocalMap();
1925 Kokkos::parallel_for(
1926 "MueLu::Utils::ApplyOAZ", range_type(0, dirichletRows.extent(0)),
1928 if (dirichletRows(row)) {
1929 auto rowView = localMatrix.row(row);
1930 auto length = rowView.length;
1931 auto row_gid = localRmap.getGlobalElement(row);
1932 auto row_lid = localCmap.getLocalElement(row_gid);
1934 for (
decltype(length) colID = 0; colID < length; colID++)
1935 if (rowView.colidx(colID) == row_lid)
1936 rowView.value(colID) = impl_ATS::one();
1938 rowView.value(colID) = impl_ATS::zero();
1943template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1945 ZeroDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1946 const std::vector<LocalOrdinal>& dirichletRows,
1948 for (
size_t i = 0; i < dirichletRows.size(); i++) {
1949 Teuchos::ArrayView<const LocalOrdinal> indices;
1950 Teuchos::ArrayView<const Scalar> values;
1951 A->getLocalRowView(dirichletRows[i], indices, values);
1953 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1954 for (
size_t j = 0; j < (size_t)indices.size(); j++)
1955 valuesNC[j] = replaceWith;
1959template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1961 ZeroDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1962 const Teuchos::ArrayRCP<const bool>& dirichletRows,
1964 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == A->getRowMap()->getLocalNumElements());
1965 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1966 if (dirichletRows[i]) {
1967 Teuchos::ArrayView<const LocalOrdinal> indices;
1968 Teuchos::ArrayView<const Scalar> values;
1969 A->getLocalRowView(i, indices, values);
1971 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1972 for (
size_t j = 0; j < (size_t)indices.size(); j++)
1973 valuesNC[j] = replaceWith;
1978template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1980 ZeroDirichletRows(Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& X,
1981 const Teuchos::ArrayRCP<const bool>& dirichletRows,
1983 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == X->getMap()->getLocalNumElements());
1984 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1985 if (dirichletRows[i]) {
1986 for (
size_t j = 0; j < X->getNumVectors(); j++)
1987 X->replaceLocalValue(i, j, replaceWith);
1992template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1994 ZeroDirichletRows(RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1995 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows,
1997 using ATS = KokkosKernels::ArithTraits<Scalar>;
1998 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
2000 typename ATS::val_type impl_replaceWith = replaceWith;
2002 auto localMatrix = A->getLocalMatrixDevice();
2005 Kokkos::parallel_for(
2006 "MueLu:Utils::ZeroDirichletRows", range_type(0, numRows),
2008 if (dirichletRows(row)) {
2009 auto rowView = localMatrix.row(row);
2010 auto length = rowView.length;
2011 for (
decltype(length) colID = 0; colID < length; colID++)
2012 rowView.value(colID) = impl_replaceWith;
2017template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2018void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
2019 ZeroDirichletRows(RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& X,
2020 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows,
2022 using ATS = KokkosKernels::ArithTraits<Scalar>;
2023 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
2025 typename ATS::val_type impl_replaceWith = replaceWith;
2027 auto myCols = X->getLocalViewDevice(Tpetra::Access::ReadWrite);
2028 size_t numVecs = X->getNumVectors();
2029 Kokkos::parallel_for(
2030 "MueLu:Utils::ZeroDirichletRows_MV", range_type(0, dirichletRows.size()),
2031 KOKKOS_LAMBDA(
const size_t i) {
2032 if (dirichletRows(i)) {
2033 for (
size_t j = 0; j < numVecs; j++)
2034 myCols(i, j) = impl_replaceWith;
2039template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2042 const Teuchos::ArrayRCP<const bool>& dirichletCols,
2044 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletCols.size()) == A->getColMap()->getLocalNumElements());
2045 for (
size_t i = 0; i < A->getLocalNumRows(); i++) {
2046 Teuchos::ArrayView<const LocalOrdinal> indices;
2047 Teuchos::ArrayView<const Scalar> values;
2048 A->getLocalRowView(i, indices, values);
2050 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
2051 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
2052 if (dirichletCols[indices[j]])
2053 valuesNC[j] = replaceWith;
2057template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2059 ZeroDirichletCols(RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
2060 const Kokkos::View<const bool*, typename Node::device_type>& dirichletCols,
2061 Scalar replaceWith,
const bool DontZeroDiagEntries) {
2062 using ATS = KokkosKernels::ArithTraits<Scalar>;
2063 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
2065 typename ATS::val_type impl_replaceWith = replaceWith;
2067 auto localMatrix = A->getLocalMatrixDevice();
2069 auto lclRowmap = A->getRowMap()->getLocalMap();
2070 auto lclCowmap = A->getColMap()->getLocalMap();
2072 Kokkos::parallel_for(
2073 "MueLu:Utils::ZeroDirichletCols", range_type(0, numRows),
2075 auto rowView = localMatrix.row(row);
2076 auto length = rowView.length;
2078 if (DontZeroDiagEntries) {
2079 auto rgid = lclRowmap.getGlobalElement(row);
2080 for (
decltype(length) colID = 0; colID < length; colID++) {
2081 if (dirichletCols(rowView.colidx(colID))) {
2082 auto cgid = lclCowmap.getGlobalElement(rowView.colidx(colID));
2083 if (rgid != cgid) rowView.value(colID) = impl_replaceWith;
2087 for (
decltype(length) colID = 0; colID < length; colID++)
2088 if (dirichletCols(rowView.colidx(colID))) {
2089 rowView.value(colID) = impl_replaceWith;
2095template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2098 Teuchos::RCP<Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node>>& isDirichletRow,
2099 Teuchos::RCP<Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node>>& isDirichletCol) {
2101 if (!A->getRowMap()->isSameAs(*A->getDomainMap())) {
2102 throw std::runtime_error(
"UtilitiesBase::FindDirichletRowsAndPropagateToCols row and domain maps must match.");
2104 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A->getCrsGraph()->getImporter();
2105 bool has_import = !importer.is_null();
2108 std::vector<LocalOrdinal> dirichletRows;
2109 FindDirichletRows(A, dirichletRows);
2112 printf(
"[%d] DirichletRow Ids = ",A->getRowMap()->getComm()->getRank());
2113 for(
size_t i=0; i<(size_t) dirichletRows.size(); i++)
2114 printf(
"%d ",dirichletRows[i]);
2119 isDirichletRow = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(A->getRowMap(),
true);
2120 isDirichletCol = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(A->getColMap(),
true);
2123 Teuchos::ArrayRCP<int> dr_rcp =
isDirichletRow->getDataNonConst(0);
2124 Teuchos::ArrayView<int> dr = dr_rcp();
2125 Teuchos::ArrayRCP<int> dc_rcp = isDirichletCol->getDataNonConst(0);
2126 Teuchos::ArrayView<int> dc = dc_rcp();
2127 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
2128 dr[dirichletRows[i]] = 1;
2129 if (!has_import) dc[dirichletRows[i]] = 1;
2134 isDirichletCol->doImport(*
isDirichletRow, *importer, Xpetra::CombineMode::ADD);
2137template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2138RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
2141 using ISC =
typename KokkosKernels::ArithTraits<Scalar>::val_type;
2142 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
2143 using local_matrix_type =
typename CrsMatrix::local_matrix_device_type;
2144 using values_type =
typename local_matrix_type::values_type;
2146 const ISC ONE = KokkosKernels::ArithTraits<ISC>::one();
2147 const ISC ZERO = KokkosKernels::ArithTraits<ISC>::zero();
2150 auto localMatrix = original->getLocalMatrixDevice();
2151 TEUCHOS_TEST_FOR_EXCEPTION(!original->hasCrsGraph(),
Exceptions::RuntimeError,
"ReplaceNonZerosWithOnes: Cannot get CrsGraph");
2152 values_type new_values(
"values", localMatrix.nnz());
2154 Kokkos::parallel_for(
2155 "ReplaceNonZerosWithOnes", range_type(0, localMatrix.nnz()), KOKKOS_LAMBDA(
const size_t i) {
2156 if (localMatrix.values(i) != ZERO)
2157 new_values(i) = ONE;
2159 new_values(i) = ZERO;
2163 RCP<Matrix> NewMatrix = Xpetra::MatrixFactory<SC, LO, GO, NO>::Build(original->getCrsGraph(), new_values);
2164 TEUCHOS_TEST_FOR_EXCEPTION(NewMatrix.is_null(),
Exceptions::RuntimeError,
"ReplaceNonZerosWithOnes: MatrixFactory::Build() did not return matrix");
2165 NewMatrix->fillComplete(original->getDomainMap(), original->getRangeMap());
2169template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2170RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
2178#ifdef HAVE_MUELU_TIMER_SYNCHRONIZATION
2179 miniLevel.
SetComm(M->getRowMap()->getComm());
2181 miniLevel.
Set(
"A", M);
2185 if (MinvScheme ==
"fsai")
2186 invapproxFact->SetParameter(
"inverse: approximation type", Teuchos::ParameterEntry(std::string(
"factoredsparseapproxinverse")));
2188 invapproxFact->SetParameter(
"inverse: approximation type", Teuchos::ParameterEntry(std::string(
"sparseapproxinverse")));
2190 miniLevel.
Request(
"Ainv", invapproxFact.get());
2191 invapproxFact->Build(miniLevel);
2192 RCP<Matrix> NewMatrix = miniLevel.
Get<RCP<Matrix>>(
"Ainv", invapproxFact.get());
2193 TEUCHOS_TEST_FOR_EXCEPTION(NewMatrix.is_null(),
Exceptions::RuntimeError,
"SPAI: MatrixFactory::Build() did not return matrix");
2197template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2198RCP<const Xpetra::BlockedMap<LocalOrdinal, GlobalOrdinal, Node>>
2201 const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>& Importer) {
2202 typedef Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node> IntVector;
2203 Xpetra::UnderlyingLib lib = sourceBlockedMap.lib();
2206 RCP<const Map> fullMap = sourceBlockedMap.getMap();
2207 RCP<const Map> stridedMap = Teuchos::rcp_dynamic_cast<const Xpetra::StridedMap<LocalOrdinal, GlobalOrdinal, Node>>(fullMap);
2208 if (!stridedMap.is_null()) fullMap = stridedMap->getMap();
2211 const size_t numSubMaps = sourceBlockedMap.getNumMaps();
2212 if (!Importer.getSourceMap()->isCompatible(*fullMap))
2213 throw std::runtime_error(
"GenerateBlockedTargetMap(): Map compatibility error");
2216 RCP<IntVector> block_ids = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(fullMap);
2218 for (
size_t i = 0; i < numSubMaps; i++) {
2219 RCP<const Map> map = sourceBlockedMap.getMap(i);
2221 for (
size_t j = 0; j < map->getLocalNumElements(); j++) {
2222 LocalOrdinal jj = fullMap->getLocalElement(map->getGlobalElement(j));
2223 block_ids->replaceLocalValue(jj, (
int)i);
2228 RCP<const Map> targetMap = Importer.getTargetMap();
2229 RCP<IntVector> new_block_ids = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(targetMap);
2230 new_block_ids->doImport(*block_ids, Importer, Xpetra::CombineMode::ADD);
2231 Teuchos::ArrayRCP<const int> dataRCP = new_block_ids->getData(0);
2232 Teuchos::ArrayView<const int> data = dataRCP();
2235 Teuchos::Array<Teuchos::Array<GlobalOrdinal>> elementsInSubMap(numSubMaps);
2236 for (
size_t i = 0; i < targetMap->getLocalNumElements(); i++) {
2237 elementsInSubMap[data[i]].push_back(targetMap->getGlobalElement(i));
2241 std::vector<RCP<const Map>> subMaps(numSubMaps);
2242 for (
size_t i = 0; i < numSubMaps; i++) {
2243 subMaps[i] = Xpetra::MapFactory<LocalOrdinal, GlobalOrdinal, Node>::Build(lib, Teuchos::OrdinalTraits<GlobalOrdinal>::invalid(), elementsInSubMap[i](), targetMap->getIndexBase(), targetMap->getComm());
2247 return rcp(
new BlockedMap(targetMap, subMaps));
2250template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2252 MapsAreNested(
const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& rowMap,
const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& colMap) {
2253 if ((rowMap.lib() == Xpetra::UseTpetra) && (colMap.lib() == Xpetra::UseTpetra)) {
2254 auto tpRowMap = toTpetra(rowMap);
2255 auto tpColMap = toTpetra(colMap);
2256 return tpColMap.isLocallyFitted(tpRowMap);
2259 ArrayView<const GlobalOrdinal> rowElements = rowMap.getLocalElementList();
2260 ArrayView<const GlobalOrdinal> colElements = colMap.getLocalElementList();
2262 const size_t numElements = rowElements.size();
2264 if (
size_t(colElements.size()) < numElements)
2267 bool goodMap =
true;
2268 for (
size_t i = 0; i < numElements; i++)
2269 if (rowElements[i] != colElements[i]) {
2277template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2278Teuchos::RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>>
2280 ReverseCuthillMcKee(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op) {
2281 using local_matrix_type =
typename Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::local_matrix_device_type;
2282 using local_graph_type =
typename local_matrix_type::staticcrsgraph_type;
2283 using lno_nnz_view_t =
typename local_graph_type::entries_type::non_const_type;
2284 using device =
typename local_graph_type::device_type;
2285 using execution_space =
typename local_matrix_type::execution_space;
2286 using ordinal_type =
typename local_matrix_type::ordinal_type;
2288 local_graph_type localGraph = Op.getLocalMatrixDevice().graph;
2290 lno_nnz_view_t rcmOrder = KokkosGraph::Experimental::graph_rcm<device, typename local_graph_type::row_map_type, typename local_graph_type::entries_type, lno_nnz_view_t>(localGraph.row_map, localGraph.entries);
2292 RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>> retval =
2293 Xpetra::VectorFactory<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(Op.getRowMap());
2296 auto view1D = Kokkos::subview(retval->getLocalViewDevice(Tpetra::Access::ReadWrite), Kokkos::ALL(), 0);
2297 Kokkos::parallel_for(
2298 "Utilities::ReverseCuthillMcKee",
2299 Kokkos::RangePolicy<ordinal_type, execution_space>(0, localGraph.numRows()),
2300 KOKKOS_LAMBDA(
const ordinal_type rowIdx) {
2301 view1D(rcmOrder(rowIdx)) = rowIdx;
2306template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2307Teuchos::RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>>
2309 CuthillMcKee(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op) {
2310 using local_matrix_type =
typename Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::local_matrix_device_type;
2311 using local_graph_type =
typename local_matrix_type::staticcrsgraph_type;
2312 using lno_nnz_view_t =
typename local_graph_type::entries_type::non_const_type;
2313 using device =
typename local_graph_type::device_type;
2314 using execution_space =
typename local_matrix_type::execution_space;
2315 using ordinal_type =
typename local_matrix_type::ordinal_type;
2317 local_graph_type localGraph = Op.getLocalMatrixDevice().graph;
2320 lno_nnz_view_t rcmOrder = KokkosGraph::Experimental::graph_rcm<device, typename local_graph_type::row_map_type, typename local_graph_type::entries_type, lno_nnz_view_t>(localGraph.row_map, localGraph.entries);
2322 RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>> retval =
2323 Xpetra::VectorFactory<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(Op.getRowMap());
2326 auto view1D = Kokkos::subview(retval->getLocalViewDevice(Tpetra::Access::ReadWrite), Kokkos::ALL(), 0);
2328 Kokkos::parallel_for(
2329 "Utilities::ReverseCuthillMcKee",
2330 Kokkos::RangePolicy<ordinal_type, execution_space>(0, numRows),
2331 KOKKOS_LAMBDA(
const ordinal_type rowIdx) {
2332 view1D(rcmOrder(numRows - 1 - rowIdx)) = rowIdx;
2337template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2339 TripleMatrixProduct(
const Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& R,
2340 const Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
2341 const Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& P,
2342 Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& Ac,
2343 const Teuchos::ParameterList& pL,
2345 Teuchos::RCP<Teuchos::ParameterList>& APparams,
2346 Teuchos::RCP<Teuchos::ParameterList>& RAPparams,
2347 Level* coarseLevel) {
2348 using Matrix = Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
2349 using MatrixMatrix = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
2350 using MatrixFactory = Xpetra::MatrixFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
2353 const bool doTranspose =
true;
2354 const bool doFillComplete =
true;
2355 const bool doOptimizeStorage =
true;
2357 const bool useImplicit = pL.get<
bool>(
"transpose: use implicit");
2359 const std::string matrixName = (pL.isType<std::string>(
"Matrix name")) ? pL.get<std::string>(
"Matrix name") :
"A";
2360 const std::string prolongatorName = (pL.isType<std::string>(
"Prolongator name")) ? pL.get<std::string>(
"Prolongator name") :
"P";
2361 const std::string restrictorName = (pL.isType<std::string>(
"Restrictor name")) ? pL.get<std::string>(
"Restrictor name") :
"R";
2362 std::string coarseMatrixName;
2363 if (pL.isType<std::string>(
"coarseMatrixName"))
2364 coarseMatrixName = pL.get<std::string>(
"coarseMatrixName");
2366 if (matrixName.size() == 1)
2367 coarseMatrixName = matrixName +
"c";
2369 coarseMatrixName = matrixName +
"_coarse";
2372 std::string levelstr, labelstr;
2373 if (coarseLevel !=
nullptr) {
2374 std::ostringstream levelss;
2376 levelstr = levelss.str();
2377 labelstr = FormattingHelper::getColonLabel(coarseLevel->getObjectLabel());
2380 bool isGPU = Node::is_gpu;
2383 if (RAPparams.is_null())
2384 RAPparams = rcp(
new ParameterList);
2385 if (pL.isSublist(
"matrixmatrix: kernel params"))
2386 RAPparams->setParameters(pL.sublist(
"matrixmatrix: kernel params"));
2388 if (RAPparams->isParameter(
"graph")) {
2389 Ac = RAPparams->get<RCP<Matrix>>(
"graph");
2393 Ac->SetMaxEigenvalueEstimate(-Teuchos::ScalarTraits<Scalar>::one());
2397 RAPparams->set(
"compute global constants: temporaries", RAPparams->get(
"compute global constants: temporaries",
false));
2398 RAPparams->set(
"compute global constants", RAPparams->get(
"compute global constants",
true));
2400 if (pL.get<
bool>(
"rap: triple product") ==
false || isGPU) {
2401 if (pL.get<
bool>(
"rap: triple product") && isGPU)
2402 verbObj.
GetOStream(
Warnings1) <<
"Switching from triple product to R x (A x P) since triple product has not been implemented for "
2403 << Node::execution_space::name() << std::endl;
2408 if (APparams.is_null())
2409 APparams = rcp(
new ParameterList);
2410 if (pL.isSublist(
"matrixmatrix: kernel params"))
2411 APparams = rcp(
new ParameterList(pL.sublist(
"matrixmatrix: kernel params")));
2414 APparams->set(
"compute global constants: temporaries", APparams->get(
"compute global constants: temporaries",
false));
2415 APparams->set(
"compute global constants", APparams->get(
"compute global constants",
false));
2417 if (APparams->isParameter(
"graph"))
2418 AP = APparams->get<RCP<Matrix>>(
"graph");
2420 std::string monitorstrAP =
"MxM: " + matrixName +
" x " + prolongatorName;
2421 std::string timerstrAP =
"MueLu::" + matrixName +
"*" + prolongatorName;
2422 if (!labelstr.empty())
2423 timerstrAP = labelstr + timerstrAP;
2424 if (!levelstr.empty())
2425 timerstrAP = timerstrAP +
"-" + levelstr;
2430 AP = MatrixMatrix::Multiply(*A, !doTranspose, *P, !doTranspose, AP, verbObj.
GetOStream(
Statistics2),
2431 doFillComplete, doOptimizeStorage, timerstrAP, APparams);
2438 std::string timerstrRAP, monitorstrRAP;
2440 monitorstrRAP =
"MxM: " + prolongatorName +
"' x (" + matrixName + prolongatorName +
") (implicit)";
2441 timerstrRAP =
"MueLu::" + restrictorName +
"*(" + matrixName +
"*" + prolongatorName +
")-implicit";
2443 monitorstrRAP =
"MxM: " + restrictorName +
" x (" + matrixName + prolongatorName +
") (explicit)";
2444 timerstrRAP =
"MueLu::" + restrictorName +
"*(" + matrixName +
"*" + prolongatorName +
")-explicit";
2446 if (!labelstr.empty())
2447 timerstrRAP = labelstr + timerstrRAP;
2448 if (!levelstr.empty())
2449 timerstrRAP = timerstrRAP +
"-" + levelstr;
2454 Ac = MatrixMatrix::Multiply(*P, doTranspose, *AP, !doTranspose, Ac, verbObj.
GetOStream(
Statistics2),
2455 doFillComplete, doOptimizeStorage, timerstrRAP, RAPparams);
2460 Ac = MatrixMatrix::Multiply(*R, !doTranspose, *AP, !doTranspose, Ac, verbObj.
GetOStream(
Statistics2),
2461 doFillComplete, doOptimizeStorage, timerstrRAP, RAPparams);
2465 APparams->set(
"graph", AP);
2469 std::string monitorstrRAP;
2470 std::string timerstrRAP;
2472 monitorstrRAP =
"MxMxM: " + restrictorName +
" x " + matrixName +
" x " + prolongatorName +
" (implicit)";
2473 timerstrRAP =
"MueLu::" + restrictorName +
"*" + matrixName +
"*" + prolongatorName +
"-implicit";
2475 monitorstrRAP =
"MxMxM: " + restrictorName +
" x " + matrixName +
" x " + prolongatorName +
" (explicit)";
2476 timerstrRAP =
"MueLu::" + restrictorName +
"*" + matrixName +
"*" + prolongatorName +
"-explicit";
2478 if (!labelstr.empty())
2479 timerstrRAP = labelstr + timerstrRAP;
2480 if (!levelstr.empty())
2481 timerstrRAP = timerstrRAP +
"-" + levelstr;
2484 Ac = MatrixFactory::Build(P->getDomainMap(), Teuchos::as<LocalOrdinal>(0));
2488 Xpetra::TripleMatrixMultiply<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
2489 MultiplyRAP(*P, doTranspose, *A, !doTranspose, *P, !doTranspose, *Ac, doFillComplete,
2490 doOptimizeStorage, timerstrRAP,
2493 Ac = MatrixFactory::Build(R->getRowMap(), Teuchos::as<LocalOrdinal>(0));
2497 Xpetra::TripleMatrixMultiply<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
2498 MultiplyRAP(*R, !doTranspose, *A, !doTranspose, *P, !doTranspose, *Ac, doFillComplete,
2499 doOptimizeStorage, timerstrRAP,
2504 Teuchos::ArrayView<const double> relativeFloor = pL.get<Teuchos::Array<double>>(
"rap: relative diagonal floor")();
2505 if (relativeFloor.size() > 0) {
2506 Xpetra::MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::RelativeDiagonalBoost(Ac, relativeFloor, verbObj.
GetOStream(
Statistics2));
2509 bool repairZeroDiagonals = pL.get<
bool>(
"RepairMainDiagonal") || pL.get<
bool>(
"rap: fix zero diagonals");
2510 bool checkAc = pL.get<
bool>(
"CheckMainDiagonal") || pL.get<
bool>(
"rap: fix zero diagonals");
2512 if (checkAc || repairZeroDiagonals) {
2513 using magnitudeType =
typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
2514 magnitudeType threshold;
2515 if (pL.isType<magnitudeType>(
"rap: fix zero diagonals threshold"))
2516 threshold = pL.get<magnitudeType>(
"rap: fix zero diagonals threshold");
2518 threshold = Teuchos::as<magnitudeType>(pL.get<
double>(
"rap: fix zero diagonals threshold"));
2519 Scalar replacement = Teuchos::as<Scalar>(pL.get<
double>(
"rap: fix zero diagonals replacement"));
2520 Xpetra::MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::CheckRepairMainDiagonal(Ac, repairZeroDiagonals, verbObj.
GetOStream(
Warnings1), threshold, replacement);
2524 RCP<ParameterList> params = rcp(
new ParameterList());
2525 params->set(
"printLoadBalancingInfo",
true);
2526 params->set(
"printCommInfo",
true);
2531 RAPparams->set(
"graph", Ac);
2534 if (Behavior::debug())
2535 MatrixUtils::checkLocalRowMapMatchesColMap(*Ac);