480 Kokkos::View<scalar_type*, execution_space> regSum(
"regSum", diag_dev.extent(0));
481 Kokkos::View<mag_type, execution_space> avgAbsDiagVal_dev(
"avgAbsDiagVal");
482 Kokkos::View<int, execution_space> numDiagsEqualToOne_dev(
"numDiagsEqualToOne");
485 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"GetLumpedMatrixDiagonal: parallel_for (doReciprocal)");
486 Kokkos::parallel_for(
487 "GetLumpedMatrixDiagonal", my_policy,
488 KOKKOS_LAMBDA(
const int rowIdx) {
489 diag_dev(rowIdx, 0) = KAT_S::zero();
490 for (size_type entryIdx = local_mat_dev.graph.row_map(rowIdx);
491 entryIdx < local_mat_dev.graph.row_map(rowIdx + 1);
493 regSum(rowIdx) += local_mat_dev.values(entryIdx);
494 if (KAT_M::zero() < KAT_S::abs(local_mat_dev.values(entryIdx))) {
497 diag_dev(rowIdx, 0) += KAT_S::abs(local_mat_dev.values(entryIdx));
498 if (rowIdx == local_mat_dev.graph.entries(entryIdx)) {
499 Kokkos::atomic_add(&avgAbsDiagVal_dev(), KAT_S::abs(local_mat_dev.values(entryIdx)));
503 if (nnzPerRow(rowIdx) == 1 && KAT_S::magnitude(diag_dev(rowIdx, 0)) == KAT_M::one()) {
504 Kokkos::atomic_add(&numDiagsEqualToOne_dev(), 1);
508 if (useAverageAbsDiagVal) {
509 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"GetLumpedMatrixDiagonal: useAverageAbsDiagVal");
510 typename Kokkos::View<mag_type, execution_space>::host_mirror_type avgAbsDiagVal = Kokkos::create_mirror_view(avgAbsDiagVal_dev);
511 Kokkos::deep_copy(avgAbsDiagVal, avgAbsDiagVal_dev);
512 int numDiagsEqualToOne;
513 Kokkos::deep_copy(numDiagsEqualToOne, numDiagsEqualToOne_dev);
515 tol = TST::magnitude(100 * Teuchos::ScalarTraits<Scalar>::eps()) * (avgAbsDiagVal() - numDiagsEqualToOne) / (rowMap->getLocalNumElements() - numDiagsEqualToOne);
519 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"ComputeLumpedDiagonalInverse: parallel_for (doReciprocal)");
520 Kokkos::parallel_for(
521 "ComputeLumpedDiagonalInverse", my_policy,
522 KOKKOS_LAMBDA(
const int rowIdx) {
523 if (replaceSingleEntryRowWithZero && nnzPerRow(rowIdx) <= 1) {
524 diag_dev(rowIdx, 0) = KAT_S::zero();
525 }
else if ((diag_dev(rowIdx, 0) != KAT_S::zero()) && (KAT_S::magnitude(diag_dev(rowIdx, 0)) < KAT_S::magnitude(2 * regSum(rowIdx)))) {
526 diag_dev(rowIdx, 0) = KAT_S::one() / KAT_S::magnitude(2 * regSum(rowIdx));
528 if (KAT_S::magnitude(diag_dev(rowIdx, 0)) > tol) {
529 diag_dev(rowIdx, 0) = KAT_S::one() / diag_dev(rowIdx, 0);
531 diag_dev(rowIdx, 0) = valReplacement_dev;
538 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"GetLumpedMatrixDiagonal: parallel_for");
539 Kokkos::parallel_for(
540 "GetLumpedMatrixDiagonal", my_policy,
541 KOKKOS_LAMBDA(
const int rowIdx) {
542 diag_dev(rowIdx, 0) = KAT_S::zero();
543 for (size_type entryIdx = local_mat_dev.graph.row_map(rowIdx);
544 entryIdx < local_mat_dev.graph.row_map(rowIdx + 1);
546 diag_dev(rowIdx, 0) += KAT_S::magnitude(local_mat_dev.values(entryIdx));
552 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"UtilitiesBase: GetLumpedMatrixDiagonal: (Teuchos implementation)");
553 ArrayRCP<Scalar> diagVals = diag->getDataNonConst(0);
554 Teuchos::Array<Scalar> regSum(diag->getLocalLength());
555 Teuchos::ArrayView<const LocalOrdinal> cols;
556 Teuchos::ArrayView<const Scalar> vals;
558 std::vector<int> nnzPerRow(rowMap->getLocalNumElements());
563 const Magnitude zeroMagn = TST::magnitude(zero);
564 Magnitude avgAbsDiagVal = TST::magnitude(zero);
565 int numDiagsEqualToOne = 0;
566 for (
size_t i = 0; i < rowMap->getLocalNumElements(); ++i) {
568 rcpA->getLocalRowView(i, cols, vals);
571 regSum[i] += vals[j];
572 const Magnitude rowEntryMagn = TST::magnitude(vals[j]);
573 if (rowEntryMagn > zeroMagn)
575 diagVals[i] += rowEntryMagn;
576 if (
static_cast<size_t>(cols[j]) == i)
577 avgAbsDiagVal += rowEntryMagn;
579 if (nnzPerRow[i] == 1 && TST::magnitude(diagVals[i]) == 1.)
580 numDiagsEqualToOne++;
582 if (useAverageAbsDiagVal)
583 tol = TST::magnitude(100 * Teuchos::ScalarTraits<Scalar>::eps()) * (avgAbsDiagVal - numDiagsEqualToOne) / (rowMap->getLocalNumElements() - numDiagsEqualToOne);
585 for (
size_t i = 0; i < rowMap->getLocalNumElements(); ++i) {
586 if (replaceSingleEntryRowWithZero && nnzPerRow[i] <=
static_cast<int>(1))
588 else if ((diagVals[i] != zero) && (TST::magnitude(diagVals[i]) < TST::magnitude(two * regSum[i])))
589 diagVals[i] = one / TST::magnitude((two * regSum[i]));
591 if (TST::magnitude(diagVals[i]) > tol)
592 diagVals[i] = one / diagVals[i];
594 diagVals[i] = valReplacement;
601 TEUCHOS_TEST_FOR_EXCEPTION(doReciprocal, Xpetra::Exceptions::RuntimeError,
602 "UtilitiesBase::GetLumpedMatrixDiagonal(): extracting reciprocal of diagonal of a blocked matrix is not supported");
603 diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(bA->getRangeMapExtractor()->getFullMap(),
true);
605 for (
size_t row = 0; row < bA->Rows(); ++row) {
606 for (
size_t col = 0; col < bA->Cols(); ++col) {
607 if (!bA->getMatrix(row, col).is_null()) {
609 bool bThyraMode = bA->getRangeMapExtractor()->getThyraMode() && (Teuchos::rcp_dynamic_cast<Xpetra::BlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>(bA->getMatrix(row, col)) == Teuchos::null);
610 RCP<Vector> ddtemp = bA->getRangeMapExtractor()->ExtractVector(diag, row, bThyraMode);
611 RCP<const Vector> dd = GetLumpedMatrixDiagonal(*(bA->getMatrix(row, col)));
612 ddtemp->update(Teuchos::as<Scalar>(1.0), *dd, Teuchos::as<Scalar>(1.0));
613 bA->getRangeMapExtractor()->InsertVector(ddtemp, row, diag, bThyraMode);
622template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
623Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
627 RCP<const Map> rowMap = A.getRowMap();
628 auto diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(rowMap,
false);
631 using local_vector_type =
typename Vector::dual_view_type::t_dev_um;
632 using local_matrix_type =
typename Matrix::local_matrix_device_type;
633 using execution_space =
typename local_vector_type::execution_space;
634 using values_type =
typename local_matrix_type::values_type;
635 using scalar_type =
typename values_type::non_const_value_type;
636 using KAT_S =
typename KokkosKernels::ArithTraits<scalar_type>;
638 auto diag_dev = diag->getLocalViewDevice(Tpetra::Access::OverwriteAll);
639 auto local_mat_dev = A.getLocalMatrixDevice();
640 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(diag_dev.extent(0)));
642 Kokkos::parallel_for(
643 "GetMatrixMaxMinusOffDiagonal", my_policy,
645 auto mymax = KAT_S::zero();
646 auto row = local_mat_dev.rowConst(rowIdx);
647 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
648 if (rowIdx != row.colidx(entryIdx)) {
649 if (KAT_S::real(mymax) < -KAT_S::real(row.value(entryIdx)))
650 mymax = -KAT_S::real(row.value(entryIdx));
653 diag_dev(rowIdx, 0) = mymax;
659template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
660Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
662 GetMatrixMaxMinusOffDiagonal(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber) {
663 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()), std::runtime_error,
"GetMatrixMaxMinusOffDiagonal: BlockNumber must match's A's column map.");
666 RCP<const Map> rowMap = A.getRowMap();
667 auto diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(rowMap,
false);
670 using local_vector_type =
typename Vector::dual_view_type::t_dev_um;
671 using local_matrix_type =
typename Matrix::local_matrix_device_type;
672 using execution_space =
typename local_vector_type::execution_space;
673 using values_type =
typename local_matrix_type::values_type;
674 using scalar_type =
typename values_type::non_const_value_type;
675 using KAT_S =
typename KokkosKernels::ArithTraits<scalar_type>;
677 auto diag_dev = diag->getLocalViewDevice(Tpetra::Access::OverwriteAll);
678 auto local_mat_dev = A.getLocalMatrixDevice();
679 auto local_block_dev = BlockNumber.getLocalViewDevice(Tpetra::Access::ReadOnly);
680 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(diag_dev.extent(0)));
682 Kokkos::parallel_for(
683 "GetMatrixMaxMinusOffDiagonal", my_policy,
685 auto mymax = KAT_S::zero();
686 auto row = local_mat_dev.row(rowIdx);
687 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
688 if ((rowIdx != row.colidx(entryIdx)) && (local_block_dev(rowIdx, 0) == local_block_dev(row.colidx(entryIdx), 0))) {
689 if (KAT_S::real(mymax) < -KAT_S::real(row.value(entryIdx)))
690 mymax = -KAT_S::real(row.value(entryIdx));
693 diag_dev(rowIdx, 0) = mymax;
699template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
700Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
702 GetInverse(Teuchos::RCP<
const Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> v,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tol,
Scalar valReplacement) {
703 RCP<Vector> ret = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(v->getMap(),
true);
706 RCP<const BlockedVector> bv = Teuchos::rcp_dynamic_cast<const BlockedVector>(v);
707 if (bv.is_null() ==
false) {
708 RCP<BlockedVector> bret = Teuchos::rcp_dynamic_cast<BlockedVector>(ret);
709 TEUCHOS_TEST_FOR_EXCEPTION(bret.is_null() ==
true,
MueLu::Exceptions::RuntimeError,
"MueLu::UtilitiesBase::GetInverse: return vector should be of type BlockedVector");
710 RCP<const BlockedMap> bmap = bv->getBlockedMap();
711 for (
size_t r = 0; r < bmap->getNumMaps(); ++r) {
712 RCP<const MultiVector> submvec = bv->getMultiVector(r, bmap->getThyraMode());
713 RCP<const Vector> subvec = submvec->getVector(0);
715 bret->setMultiVector(r, subvecinf, bmap->getThyraMode());
721 ArrayRCP<Scalar> retVals = ret->getDataNonConst(0);
722 ArrayRCP<const Scalar> inputVals = v->getData(0);
723 for (
size_t i = 0; i < v->getMap()->getLocalNumElements(); ++i) {
724 if (Teuchos::ScalarTraits<Scalar>::magnitude(inputVals[i]) > tol)
725 retVals[i] = Teuchos::ScalarTraits<Scalar>::one() / inputVals[i];
727 retVals[i] = valReplacement;
770template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
771RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
774 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
775 RCP<Vector> localDiag = GetMatrixDiagonal(A);
776 RCP<const Import> importer = A.getCrsGraph()->getImporter();
777 if (importer.is_null() && !rowMap->isSameAs(*colMap)) {
778 importer = ImportFactory::Build(rowMap, colMap);
780 if (!importer.is_null()) {
781 RCP<Vector> diagonal = VectorFactory::Build(colMap,
false);
782 diagonal->doImport(*localDiag, *(importer), Xpetra::INSERT);
788template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
789RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
792 using STS =
typename Teuchos::ScalarTraits<SC>;
795 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
796 RCP<const BlockedMap> browMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
797 if (!browMap.is_null()) rowMap = browMap->getMap();
799 RCP<Vector> local = Xpetra::VectorFactory<SC, LO, GO, Node>::Build(rowMap);
800 RCP<Vector> ghosted = Xpetra::VectorFactory<SC, LO, GO, Node>::Build(colMap,
true);
801 ArrayRCP<SC> localVals = local->getDataNonConst(0);
803 for (LO row = 0; row < static_cast<LO>(A.getRowMap()->getLocalNumElements()); ++row) {
804 size_t nnz = A.getNumEntriesInLocalRow(row);
805 ArrayView<const LO> indices;
806 ArrayView<const SC> vals;
807 A.getLocalRowView(row, indices, vals);
811 for (LO colID = 0; colID < static_cast<LO>(nnz); colID++) {
812 if (indices[colID] != row) {
819 RCP<const Xpetra::Import<LO, GO, Node>> importer;
820 importer = A.getCrsGraph()->getImporter();
821 if (importer == Teuchos::null) {
822 importer = Xpetra::ImportFactory<LO, GO, Node>::Build(rowMap, colMap);
824 ghosted->doImport(*local, *(importer), Xpetra::INSERT);
828template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
832 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
833 using STS =
typename Teuchos::ScalarTraits<Scalar>;
834 using MTS =
typename Teuchos::ScalarTraits<Magnitude>;
836 using RealValuedVector = Xpetra::Vector<MT, LO, GO, Node>;
839 RCP<const BlockedMap> browMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
840 if (!browMap.is_null()) rowMap = browMap->getMap();
842 RCP<RealValuedVector> local = Xpetra::VectorFactory<MT, LO, GO, Node>::Build(rowMap);
843 RCP<RealValuedVector> ghosted = Xpetra::VectorFactory<MT, LO, GO, Node>::Build(colMap,
true);
844 ArrayRCP<MT> localVals = local->getDataNonConst(0);
846 for (LO rowIdx = 0; rowIdx < static_cast<LO>(A.getRowMap()->getLocalNumElements()); ++rowIdx) {
847 size_t nnz = A.getNumEntriesInLocalRow(rowIdx);
848 ArrayView<const LO> indices;
849 ArrayView<const SC> vals;
850 A.getLocalRowView(rowIdx, indices, vals);
854 for (LO colID = 0; colID < static_cast<LO>(nnz); ++colID) {
855 if (indices[colID] != rowIdx) {
856 si += STS::magnitude(vals[colID]);
859 localVals[rowIdx] = si;
862 RCP<const Xpetra::Import<LO, GO, Node>> importer;
863 importer = A.getCrsGraph()->getImporter();
864 if (importer == Teuchos::null) {
865 importer = Xpetra::ImportFactory<LO, GO, Node>::Build(rowMap, colMap);
867 ghosted->doImport(*local, *(importer), Xpetra::INSERT);
871template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
875 using local_matrix_type =
typename Matrix::local_matrix_device_type;
876 using execution_space =
typename local_matrix_type::execution_space;
877 using KAT_S =
typename KokkosKernels::ArithTraits<typename local_matrix_type::value_type>;
879 auto local_mat_dev = A.getLocalMatrixDevice();
880 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(local_mat_dev.numRows()));
883 Kokkos::parallel_reduce(
884 "CountNegativeDiagonalEntries", my_policy,
886 auto row = local_mat_dev.row(rowIdx);
887 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
888 if (rowIdx == row.colidx(entryIdx) && KAT_S::real(row.value(entryIdx)) < 0)
894 MueLu_sumAll(A.getRowMap()->getComm(), count_l, count_g);
898template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
899Teuchos::Array<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>
901 ResidualNorm(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS) {
902 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
903 const size_t numVecs = X.getNumVectors();
904 RCP<MultiVector> RES = Residual(Op, X, RHS);
905 Teuchos::Array<Magnitude> norms(numVecs);
910template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
911Teuchos::Array<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>
913 ResidualNorm(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS, MultiVector& Resid) {
914 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
915 const size_t numVecs = X.getNumVectors();
916 Residual(Op, X, RHS, Resid);
917 Teuchos::Array<Magnitude> norms(numVecs);
922template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
923RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
925 Residual(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS) {
926 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
927 const size_t numVecs = X.getNumVectors();
929 RCP<MultiVector> RES = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(RHS.getMap(), numVecs,
false);
930 Op.residual(X, RHS, *RES);
934template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
936 Residual(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS, MultiVector& Resid) {
937 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides");
938 TEUCHOS_TEST_FOR_EXCEPTION(Resid.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of residual vectors != number of right-hand sides");
939 Op.residual(X, RHS, Resid);
942template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
946 LocalOrdinal niters,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType diagonalReplacementTolerance,
bool verbose,
unsigned int seed) {
948 "Utils::PowerMethod: operator must have domain and range maps that are equivalent.");
951 RCP<Vector> diagInvVec;
953 diagInvVec = GetMatrixDiagonalInverse(A, diagonalReplacementTolerance);
956 Scalar lambda = PowerMethod(A, diagInvVec, niters, tolerance, verbose, seed);
960template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
962UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
963 PowerMethod(
const Matrix& A,
const RCP<Vector>& diagInvVec,
964 LocalOrdinal niters,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance,
bool verbose,
unsigned int seed) {
965 TEUCHOS_TEST_FOR_EXCEPTION(!(A.getRangeMap()->isSameAs(*(A.getDomainMap()))), Exceptions::Incompatible,
966 "Utils::PowerMethod: operator must have domain and range maps that are equivalent.");
969 RCP<Vector> q = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getDomainMap(),
true);
970 RCP<Vector> r = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRangeMap(),
true);
971 RCP<Vector> z = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRangeMap(),
false);
976 Teuchos::Array<Magnitude> norms(1);
978 typedef Teuchos::ScalarTraits<Scalar> STS;
980 const Scalar zero = STS::zero(), one = STS::one();
983 Magnitude residual = STS::magnitude(zero);
986 for (
int iter = 0; iter < niters; ++iter) {
988 q->update(one / norms[0], *z, zero);
990 if (diagInvVec != Teuchos::null)
991 z->elementWiseMultiply(one, *diagInvVec, *z, zero);
994 if (iter % 100 == 0 || iter + 1 == niters) {
995 r->update(1.0, *z, -lambda, *q, zero);
997 residual = STS::magnitude(norms[0] / lambda);
999 std::cout <<
"Iter = " << iter
1000 <<
" Lambda = " << lambda
1001 <<
" Residual of A*q - lambda*q = " << residual
1005 if (residual < tolerance)
1011template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1012RCP<Teuchos::FancyOStream>
1015 RCP<Teuchos::FancyOStream> fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(os));
1019template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1020typename Teuchos::ScalarTraits<Scalar>::magnitudeType
1023 const size_t numVectors = v.size();
1025 Scalar d = Teuchos::ScalarTraits<Scalar>::zero();
1026 for (
size_t j = 0; j < numVectors; j++) {
1027 d += (v[j][i0] - v[j][i1]) * (v[j][i0] - v[j][i1]);
1029 return Teuchos::ScalarTraits<Scalar>::magnitude(d);
1032template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1033typename Teuchos::ScalarTraits<Scalar>::magnitudeType
1036 const size_t numVectors = v.size();
1037 using MT =
typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
1039 Scalar d = Teuchos::ScalarTraits<Scalar>::zero();
1040 for (
size_t j = 0; j < numVectors; j++) {
1041 d += Teuchos::as<MT>(weight[j]) * (v[j][i0] - v[j][i1]) * (v[j][i0] - v[j][i1]);
1043 return Teuchos::ScalarTraits<Scalar>::magnitude(d);
1046template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1047Teuchos::ArrayRCP<const bool>
1049 DetectDirichletRows(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType& tol,
bool count_twos_as_dirichlet) {
1051 typedef Teuchos::ScalarTraits<Scalar> STS;
1052 ArrayRCP<bool> boundaryNodes(numRows,
true);
1053 if (count_twos_as_dirichlet) {
1055 ArrayView<const LocalOrdinal> indices;
1056 ArrayView<const Scalar> vals;
1057 A.getLocalRowView(row, indices, vals);
1058 size_t nnz = A.getNumEntriesInLocalRow(row);
1061 for (col = 0; col < nnz; col++)
1062 if ((indices[col] != row) && STS::magnitude(vals[col]) > tol) {
1063 if (!boundaryNodes[row])
1065 boundaryNodes[row] =
false;
1068 boundaryNodes[row] =
true;
1073 ArrayView<const LocalOrdinal> indices;
1074 ArrayView<const Scalar> vals;
1075 A.getLocalRowView(row, indices, vals);
1076 size_t nnz = A.getNumEntriesInLocalRow(row);
1078 for (
size_t col = 0; col < nnz; col++)
1079 if ((indices[col] != row) && STS::magnitude(vals[col]) > tol) {
1080 boundaryNodes[row] =
false;
1085 return boundaryNodes;
1088template <
class CrsMatrix>
1089KOKKOS_FORCEINLINE_FUNCTION
bool isDirichletRow(
typename CrsMatrix::ordinal_type rowId,
1090 KokkosSparse::SparseRowViewConst<CrsMatrix>& row,
1091 const typename KokkosKernels::ArithTraits<typename CrsMatrix::value_type>::magnitudeType& tol,
1092 const bool count_twos_as_dirichlet) {
1093 using ATS = KokkosKernels::ArithTraits<typename CrsMatrix::value_type>;
1095 auto length = row.length;
1096 bool boundaryNode =
true;
1098 if (count_twos_as_dirichlet) {
1100 decltype(length) colID = 0;
1101 for (; colID < length; colID++)
1102 if ((row.colidx(colID) != rowId) &&
1103 (ATS::magnitude(row.value(colID)) > tol)) {
1106 boundaryNode =
false;
1108 if (colID == length)
1109 boundaryNode =
true;
1112 for (
decltype(length) colID = 0; colID < length; colID++)
1113 if ((row.colidx(colID) != rowId) &&
1114 (ATS::magnitude(row.value(colID)) > tol)) {
1115 boundaryNode =
false;
1119 return boundaryNode;
1122template <
class SC,
class LO,
class GO,
class NO,
class memory_space>
1123Kokkos::View<bool*, memory_space>
1125 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1126 const bool count_twos_as_dirichlet) {
1127 using impl_scalar_type =
typename KokkosKernels::ArithTraits<SC>::val_type;
1128 using ATS = KokkosKernels::ArithTraits<impl_scalar_type>;
1129 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
1130 using helpers = Xpetra::Helpers<SC, LO, GO, NO>;
1132 Kokkos::View<bool*, typename NO::device_type::memory_space> boundaryNodes;
1134 if (helpers::isTpetraBlockCrs(A)) {
1135 const Tpetra::BlockCrsMatrix<SC, LO, GO, NO>& Am = toTpetraBlock(A);
1136 auto b_graph = Am.getCrsGraph().getLocalGraphDevice();
1137 auto b_rowptr = Am.getCrsGraph().getLocalRowPtrsDevice();
1138 auto values = Am.getValuesDevice();
1139 LO numBlockRows = Am.getLocalNumRows();
1140 const LO stride = Am.getBlockSize() * Am.getBlockSize();
1142 boundaryNodes = Kokkos::View<bool*, typename NO::device_type::memory_space>(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), numBlockRows);
1144 if (count_twos_as_dirichlet)
1147 Kokkos::parallel_for(
1148 "MueLu:Utils::DetectDirichletRowsBlockCrs", range_type(0, numBlockRows),
1149 KOKKOS_LAMBDA(
const LO row) {
1150 auto rowView = b_graph.rowConst(row);
1151 auto length = rowView.length;
1152 LO valstart = b_rowptr[row] * stride;
1154 boundaryNodes(row) =
true;
1155 decltype(length) colID = 0;
1156 for (; colID < length; colID++) {
1157 if (rowView.colidx(colID) != row) {
1158 LO current = valstart + colID * stride;
1159 for (LO k = 0; k < stride; k++) {
1160 if (ATS::magnitude(values[current + k]) > tol) {
1161 boundaryNodes(row) =
false;
1166 if (boundaryNodes(row) ==
false)
1171 auto localMatrix = A.getLocalMatrixDevice();
1172 LO numRows = A.getLocalNumRows();
1173 boundaryNodes = Kokkos::View<bool*, typename NO::device_type::memory_space>(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), numRows);
1175 Kokkos::parallel_for(
1176 "MueLu:Utils::DetectDirichletRows", range_type(0, numRows),
1177 KOKKOS_LAMBDA(
const LO row) {
1178 auto rowView = localMatrix.rowConst(row);
1179 boundaryNodes(row) =
isDirichletRow(row, rowView, tol, count_twos_as_dirichlet);
1182 if constexpr (std::is_same<memory_space, typename NO::device_type::memory_space>::value)
1183 return boundaryNodes;
1185 Kokkos::View<bool*, memory_space> boundaryNodes2(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), boundaryNodes.extent(0));
1186 Kokkos::deep_copy(boundaryNodes2, boundaryNodes);
1187 return boundaryNodes2;
1190 Kokkos::View<bool*, memory_space> dummy(
"dummy", 0);
1194template <
class SC,
class LO,
class GO,
class NO>
1195Kokkos::View<bool*, typename NO::device_type::memory_space>
1198 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1199 const bool count_twos_as_dirichlet) {
1200 return MueLu::DetectDirichletRows_kokkos<SC, LO, GO, NO, typename NO::device_type::memory_space>(A, tol, count_twos_as_dirichlet);
1203template <
class SC,
class LO,
class GO,
class NO>
1204Kokkos::View<bool*, typename Kokkos::HostSpace>
1207 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1208 const bool count_twos_as_dirichlet) {
1209 return MueLu::DetectDirichletRows_kokkos<SC, LO, GO, NO, typename Kokkos::HostSpace>(A, tol, count_twos_as_dirichlet);
1212template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1213Teuchos::ArrayRCP<const bool>
1215 DetectDirichletRowsExt(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
bool& bHasZeroDiagonal,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType& tol) {
1217 bHasZeroDiagonal =
false;
1219 Teuchos::RCP<Vector> diagVec = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRowMap());
1220 A.getLocalDiagCopy(*diagVec);
1221 Teuchos::ArrayRCP<const Scalar> diagVecData = diagVec->getData(0);
1224 typedef Teuchos::ScalarTraits<Scalar> STS;
1225 ArrayRCP<bool> boundaryNodes(numRows,
false);
1227 ArrayView<const LocalOrdinal> indices;
1228 ArrayView<const Scalar> vals;
1229 A.getLocalRowView(row, indices, vals);
1231 bool bHasDiag =
false;
1232 for (
decltype(indices.size()) col = 0; col < indices.size(); col++) {
1233 if (indices[col] != row) {
1234 if (STS::magnitude(vals[col] / STS::magnitude(sqrt(STS::magnitude(diagVecData[row]) * STS::magnitude(diagVecData[col])))) > tol) {
1240 if (bHasDiag ==
false)
1241 bHasZeroDiagonal =
true;
1243 boundaryNodes[row] =
true;
1245 return boundaryNodes;
1248template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1251 const Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>& RHS,
1252 Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>& InitialGuess,
1253 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1254 const bool count_twos_as_dirichlet) {
1255 using range_type = Kokkos::RangePolicy<LO, typename Node::execution_space>;
1259 TEUCHOS_ASSERT_EQUALITY(numVectors, Teuchos::as<LocalOrdinal>(InitialGuess.getNumVectors()));
1260 if (Behavior::debug())
1261 TEUCHOS_ASSERT(RHS.getMap()->isCompatible(*InitialGuess.getMap()));
1263 auto lclRHS = RHS.getLocalViewDevice(Tpetra::Access::ReadOnly);
1264 auto lclInitialGuess = InitialGuess.getLocalViewDevice(Tpetra::Access::ReadWrite);
1265 auto lclA = A.getLocalMatrixDevice();
1267 Kokkos::parallel_for(
1268 "MueLu:Utils::EnforceInitialCondition", range_type(0, numRows),
1269 KOKKOS_LAMBDA(
const LO i) {
1270 auto row = lclA.rowConst(i);
1273 lclInitialGuess(i, j) = lclRHS(i, j);
1278template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1280 FindNonZeros(
const Teuchos::ArrayRCP<const Scalar> vals,
1281 Teuchos::ArrayRCP<bool> nonzeros) {
1282 TEUCHOS_ASSERT(vals.size() == nonzeros.size());
1283 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType magnitudeType;
1284 const magnitudeType eps = 2.0 * Teuchos::ScalarTraits<magnitudeType>::eps();
1285 for (
size_t i = 0; i < static_cast<size_t>(vals.size()); i++) {
1286 nonzeros[i] = (Teuchos::ScalarTraits<Scalar>::magnitude(vals[i]) > eps);
1291template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1293 FindNonZeros(
const typename Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dual_view_type::t_dev_const_um vals,
1294 Kokkos::View<bool*, typename Node::device_type> nonzeros) {
1295 using ATS = KokkosKernels::ArithTraits<Scalar>;
1296 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1297 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1298 TEUCHOS_ASSERT(vals.extent(0) == nonzeros.extent(0));
1299 const typename ATS::magnitudeType eps = 2.0 * impl_ATS::eps();
1301 Kokkos::parallel_for(
1302 "MueLu:Maxwell1::FindNonZeros", range_type(0, vals.extent(0)),
1303 KOKKOS_LAMBDA(
const size_t i) {
1304 nonzeros(i) = (impl_ATS::magnitude(vals(i, 0)) > eps);
1308template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1311 const Teuchos::ArrayRCP<bool>& dirichletRows,
1312 Teuchos::ArrayRCP<bool> dirichletCols,
1313 Teuchos::ArrayRCP<bool> dirichletDomain) {
1314 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1315 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1316 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowMap = A.getRowMap();
1317 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1318 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == rowMap->getLocalNumElements());
1319 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletCols.size()) == colMap->getLocalNumElements());
1320 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletDomain.size()) == domMap->getLocalNumElements());
1321 RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, 1,
true);
1323 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1324 if (dirichletRows[i]) {
1325 ArrayView<const LocalOrdinal> indices;
1326 ArrayView<const Scalar> values;
1327 A.getLocalRowView(i, indices, values);
1328 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
1329 myColsToZero->replaceLocalValue(indices[j], 0, one);
1333 RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero;
1334 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A.getCrsGraph()->getImporter();
1335 if (!importer.is_null()) {
1336 globalColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap, 1,
true);
1338 globalColsToZero->doExport(*myColsToZero, *importer, Xpetra::ADD);
1340 myColsToZero->doImport(*globalColsToZero, *importer, Xpetra::INSERT);
1342 globalColsToZero = myColsToZero;
1344 FindNonZeros(globalColsToZero->getData(0), dirichletDomain);
1345 FindNonZeros(myColsToZero->getData(0), dirichletCols);
1348template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1351 const Kokkos::View<bool*, typename Node::device_type>& dirichletRows,
1352 Kokkos::View<bool*, typename Node::device_type> dirichletCols,
1353 Kokkos::View<bool*, typename Node::device_type> dirichletDomain) {
1354 using ATS = KokkosKernels::ArithTraits<Scalar>;
1355 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1356 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1357 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1358 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowMap = A.getRowMap();
1359 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1360 TEUCHOS_ASSERT(dirichletRows.extent(0) == rowMap->getLocalNumElements());
1361 TEUCHOS_ASSERT(dirichletCols.extent(0) == colMap->getLocalNumElements());
1362 TEUCHOS_ASSERT(dirichletDomain.extent(0) == domMap->getLocalNumElements());
1363 RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap,
true);
1365 auto myColsToZeroView = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadWrite);
1366 auto localMatrix = A.getLocalMatrixDevice();
1367 Kokkos::parallel_for(
1368 "MueLu:Maxwell1::DetectDirichletCols", range_type(0, rowMap->getLocalNumElements()),
1370 if (dirichletRows(row)) {
1371 auto rowView = localMatrix.row(row);
1372 auto length = rowView.length;
1374 for (
decltype(length) colID = 0; colID < length; colID++)
1375 myColsToZeroView(rowView.colidx(colID), 0) = impl_ATS::one();
1379 RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero;
1380 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A.getCrsGraph()->getImporter();
1381 if (!importer.is_null()) {
1382 globalColsToZero = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap,
true);
1384 globalColsToZero->doExport(*myColsToZero, *importer, Xpetra::ADD);
1386 myColsToZero->doImport(*globalColsToZero, *importer, Xpetra::INSERT);
1388 globalColsToZero = myColsToZero;
1393template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1395 ApplyRowSumCriterion(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol, Teuchos::ArrayRCP<bool>& dirichletRows) {
1396 typedef Teuchos::ScalarTraits<Scalar> STS;
1397 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1398 typedef Teuchos::ScalarTraits<MT> MTS;
1399 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1400 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1401 size_t nnz = A.getNumEntriesInLocalRow(row);
1402 ArrayView<const LocalOrdinal> indices;
1403 ArrayView<const Scalar> vals;
1404 A.getLocalRowView(row, indices, vals);
1406 Scalar rowsum = STS::zero();
1407 Scalar diagval = STS::zero();
1409 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1412 diagval = vals[colID];
1413 rowsum += vals[colID];
1416 if (rowSumTol < MTS::one() && STS::magnitude(rowsum) > STS::magnitude(diagval) * rowSumTol) {
1418 dirichletRows[row] =
true;
1423template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1424void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1425 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) {
1426 typedef Teuchos::ScalarTraits<Scalar> STS;
1427 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1428 typedef Teuchos::ScalarTraits<MT> MTS;
1429 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1431 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()), std::runtime_error,
"ApplyRowSumCriterion: BlockNumber must match's A's column map.");
1433 Teuchos::ArrayRCP<const LocalOrdinal> block_id = BlockNumber.getData(0);
1434 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1435 size_t nnz = A.getNumEntriesInLocalRow(row);
1436 ArrayView<const LocalOrdinal> indices;
1437 ArrayView<const Scalar> vals;
1438 A.getLocalRowView(row, indices, vals);
1440 Scalar rowsum = STS::zero();
1441 Scalar diagval = STS::zero();
1442 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1445 diagval = vals[colID];
1446 if (block_id[row] == block_id[col])
1447 rowsum += vals[colID];
1451 if (rowSumTol < MTS::one() && STS::magnitude(rowsum) > STS::magnitude(diagval) * rowSumTol) {
1453 dirichletRows[row] =
true;
1459template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node,
class memory_space>
1461 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1462 Kokkos::View<bool*, memory_space>& dirichletRows) {
1463 typedef Teuchos::ScalarTraits<Scalar> STS;
1464 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1466 auto dirichletRowsHost = Kokkos::create_mirror_view(dirichletRows);
1467 Kokkos::deep_copy(dirichletRowsHost, dirichletRows);
1469 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1470 size_t nnz = A.getNumEntriesInLocalRow(row);
1471 ArrayView<const LocalOrdinal> indices;
1472 ArrayView<const Scalar> vals;
1473 A.getLocalRowView(row, indices, vals);
1475 Scalar rowsum = STS::zero();
1476 Scalar diagval = STS::zero();
1477 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1480 diagval = vals[colID];
1481 rowsum += vals[colID];
1483 if (STS::real(rowsum) > STS::magnitude(diagval) * rowSumTol)
1484 dirichletRowsHost(row) =
true;
1487 Kokkos::deep_copy(dirichletRows, dirichletRowsHost);
1490template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1491void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1492 ApplyRowSumCriterion(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1493 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1494 Kokkos::View<bool*, typename Node::device_type::memory_space>& dirichletRows) {
1495 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, typename Node::device_type::memory_space>(A, rowSumTol, dirichletRows);
1498template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1499void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1500 ApplyRowSumCriterionHost(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1501 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1502 Kokkos::View<bool*, Kokkos::HostSpace>& dirichletRows) {
1503 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, Kokkos::HostSpace>(A, rowSumTol, dirichletRows);
1507template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node,
class memory_space>
1509 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1510 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1511 Kokkos::View<bool*, memory_space>& dirichletRows) {
1512 typedef Teuchos::ScalarTraits<Scalar> STS;
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 auto dirichletRowsHost = Kokkos::create_mirror_view(dirichletRows);
1518 Kokkos::deep_copy(dirichletRowsHost, dirichletRows);
1520 Teuchos::ArrayRCP<const LocalOrdinal> block_id = BlockNumber.getData(0);
1521 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1522 size_t nnz = A.getNumEntriesInLocalRow(row);
1523 ArrayView<const LocalOrdinal> indices;
1524 ArrayView<const Scalar> vals;
1525 A.getLocalRowView(row, indices, vals);
1527 Scalar rowsum = STS::zero();
1528 Scalar diagval = STS::zero();
1529 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1532 diagval = vals[colID];
1533 if (block_id[row] == block_id[col])
1534 rowsum += vals[colID];
1536 if (STS::real(rowsum) > STS::magnitude(diagval) * rowSumTol)
1537 dirichletRowsHost(row) =
true;
1540 Kokkos::deep_copy(dirichletRows, dirichletRowsHost);
1543template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1544void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1545 ApplyRowSumCriterion(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1546 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1547 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1548 Kokkos::View<bool*, typename Node::device_type::memory_space>& dirichletRows) {
1549 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, typename Node::device_type::memory_space>(A, BlockNumber, rowSumTol, dirichletRows);
1552template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1553void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1554 ApplyRowSumCriterionHost(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1555 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1556 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1557 Kokkos::View<bool*, Kokkos::HostSpace>& dirichletRows) {
1558 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, Kokkos::HostSpace>(A, BlockNumber, rowSumTol, dirichletRows);
1561template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1562Teuchos::ArrayRCP<const bool>
1565 const Teuchos::ArrayRCP<const bool>& dirichletRows) {
1566 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1567 Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1568 Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1569 Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1570 Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, 1);
1571 myColsToZero->putScalar(zero);
1573 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1574 if (dirichletRows[i]) {
1575 Teuchos::ArrayView<const LocalOrdinal> indices;
1576 Teuchos::ArrayView<const Scalar> values;
1577 A.getLocalRowView(i, indices, values);
1578 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
1579 myColsToZero->replaceLocalValue(indices[j], 0, one);
1583 Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap, 1);
1584 globalColsToZero->putScalar(zero);
1585 Teuchos::RCP<Xpetra::Export<LocalOrdinal, GlobalOrdinal, Node>> exporter = Xpetra::ExportFactory<LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, domMap);
1587 globalColsToZero->doExport(*myColsToZero, *exporter, Xpetra::ADD);
1589 myColsToZero->doImport(*globalColsToZero, *exporter, Xpetra::INSERT);
1590 Teuchos::ArrayRCP<const Scalar> myCols = myColsToZero->getData(0);
1591 Teuchos::ArrayRCP<bool> dirichletCols(colMap->getLocalNumElements(),
true);
1592 Magnitude eps = Teuchos::ScalarTraits<Magnitude>::eps();
1593 for (
size_t i = 0; i < colMap->getLocalNumElements(); i++) {
1594 dirichletCols[i] = Teuchos::ScalarTraits<Scalar>::magnitude(myCols[i]) > 2.0 * eps;
1596 return dirichletCols;
1599template <
class SC,
class LO,
class GO,
class NO>
1600Kokkos::View<bool*, typename NO::device_type>
1603 const Kokkos::View<const bool*, typename NO::device_type>& dirichletRows) {
1604 using ATS = KokkosKernels::ArithTraits<SC>;
1605 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1606 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
1608 SC zero = ATS::zero();
1610 auto localMatrix = A.getLocalMatrixDevice();
1611 LO numRows = A.getLocalNumRows();
1613 Teuchos::RCP<const Xpetra::Map<LO, GO, NO>> domMap = A.getDomainMap();
1614 Teuchos::RCP<const Xpetra::Map<LO, GO, NO>> colMap = A.getColMap();
1615 Teuchos::RCP<Xpetra::MultiVector<SC, LO, GO, NO>> myColsToZero = Xpetra::MultiVectorFactory<SC, LO, GO, NO>::Build(colMap, 1);
1616 myColsToZero->putScalar(zero);
1617 auto myColsToZeroView = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadWrite);
1619 Kokkos::parallel_for(
1620 "MueLu:Utils::DetectDirichletCols1", range_type(0, numRows),
1621 KOKKOS_LAMBDA(
const LO row) {
1622 if (dirichletRows(row)) {
1623 auto rowView = localMatrix.row(row);
1624 auto length = rowView.length;
1626 for (
decltype(length) colID = 0; colID < length; colID++)
1627 myColsToZeroView(rowView.colidx(colID), 0) = impl_ATS::one();
1631 Teuchos::RCP<Xpetra::MultiVector<SC, LO, GO, NO>> globalColsToZero = Xpetra::MultiVectorFactory<SC, LO, GO, NO>::Build(domMap, 1);
1632 globalColsToZero->putScalar(zero);
1633 Teuchos::RCP<Xpetra::Export<LO, GO, NO>> exporter = Xpetra::ExportFactory<LO, GO, NO>::Build(colMap, domMap);
1635 globalColsToZero->doExport(*myColsToZero, *exporter, Xpetra::ADD);
1637 myColsToZero->doImport(*globalColsToZero, *exporter, Xpetra::INSERT);
1639 auto myCols = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadOnly);
1640 size_t numColEntries = colMap->getLocalNumElements();
1641 Kokkos::View<bool*, typename NO::device_type> dirichletCols(Kokkos::ViewAllocateWithoutInitializing(
"dirichletCols"), numColEntries);
1642 const typename ATS::magnitudeType eps = 2.0 * ATS::eps();
1644 Kokkos::parallel_for(
1645 "MueLu:Utils::DetectDirichletCols2", range_type(0, numColEntries),
1646 KOKKOS_LAMBDA(
const size_t i) {
1647 dirichletCols(i) = impl_ATS::magnitude(myCols(i, 0)) > eps;
1649 return dirichletCols;
1652template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1655 Frobenius(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& B) {
1660 TEUCHOS_TEST_FOR_EXCEPTION(!A.getRowMap()->isSameAs(*B.getRowMap()),
Exceptions::Incompatible,
"MueLu::CGSolver::Frobenius: row maps are incompatible");
1661 TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete() || !B.isFillComplete(),
Exceptions::RuntimeError,
"Matrices must be fill completed");
1663 const Map& AColMap = *A.getColMap();
1664 const Map& BColMap = *B.getColMap();
1666 Teuchos::ArrayView<const LocalOrdinal> indA, indB;
1667 Teuchos::ArrayView<const Scalar> valA, valB;
1668 size_t nnzA = 0, nnzB = 0;
1680 Teuchos::Array<Scalar> valBAll(BColMap.getLocalNumElements());
1682 LocalOrdinal invalid = Teuchos::OrdinalTraits<LocalOrdinal>::invalid();
1683 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero(), f = zero, gf;
1684 size_t numRows = A.getLocalNumRows();
1685 for (
size_t i = 0; i < numRows; i++) {
1686 A.getLocalRowView(i, indA, valA);
1687 B.getLocalRowView(i, indB, valB);
1692 for (
size_t j = 0; j < nnzB; j++)
1693 valBAll[indB[j]] = valB[j];
1695 for (
size_t j = 0; j < nnzA; j++) {
1698 LocalOrdinal ind = BColMap.getLocalElement(AColMap.getGlobalElement(indA[j]));
1700 f += valBAll[ind] * valA[j];
1704 for (
size_t j = 0; j < nnzB; j++)
1705 valBAll[indB[j]] = zero;
1713template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1721 int maxint = INT_MAX;
1722 int mySeed = Teuchos::as<int>((maxint - 1) * (one - (comm.getRank() + 1) / (comm.getSize() + one)));
1723 if (mySeed < 1 || mySeed == maxint) {
1724 std::ostringstream errStr;
1725 errStr <<
"Error detected with random seed = " << mySeed <<
". It should be in the interval [1,2^31-2].";
1730 Teuchos::ScalarTraits<Scalar>::seedrandom(mySeed);
1733template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1735 FindDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1736 std::vector<LocalOrdinal>& dirichletRows,
bool count_twos_as_dirichlet) {
1737 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1738 dirichletRows.resize(0);
1739 for (
size_t i = 0; i < A->getLocalNumRows(); i++) {
1740 Teuchos::ArrayView<const LocalOrdinal> indices;
1741 Teuchos::ArrayView<const Scalar> values;
1742 A->getLocalRowView(i, indices, values);
1744 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1745 if (Teuchos::ScalarTraits<Scalar>::magnitude(values[j]) > Teuchos::ScalarTraits<MT>::eps()) {
1749 if (nnz == 1 || (count_twos_as_dirichlet && nnz == 2)) {
1750 dirichletRows.push_back(i);
1755template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1757 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1758 const std::vector<LocalOrdinal>& dirichletRows) {
1759 RCP<const Map> Rmap = A->getRowMap();
1760 RCP<const Map> Cmap = A->getColMap();
1761 Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1762 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1764 for (
size_t i = 0; i < dirichletRows.size(); i++) {
1765 GlobalOrdinal row_gid = Rmap->getGlobalElement(dirichletRows[i]);
1767 Teuchos::ArrayView<const LocalOrdinal> indices;
1768 Teuchos::ArrayView<const Scalar> values;
1769 A->getLocalRowView(dirichletRows[i], indices, values);
1771 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1772 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1773 if (Cmap->getGlobalElement(indices[j]) == row_gid)
1781template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1783 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1784 const Teuchos::ArrayRCP<const bool>& dirichletRows) {
1785 TEUCHOS_ASSERT(A->isFillComplete());
1786 RCP<const Map> domMap = A->getDomainMap();
1787 RCP<const Map> ranMap = A->getRangeMap();
1788 RCP<const Map> Rmap = A->getRowMap();
1789 RCP<const Map> Cmap = A->getColMap();
1790 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == Rmap->getLocalNumElements());
1791 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1792 const Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1794 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1795 if (dirichletRows[i]) {
1798 Teuchos::ArrayView<const LocalOrdinal> indices;
1799 Teuchos::ArrayView<const Scalar> values;
1800 A->getLocalRowView(i, indices, values);
1802 Teuchos::ArrayRCP<Scalar> valuesNC(values.size());
1803 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1804 if (Cmap->getGlobalElement(indices[j]) == row_gid)
1809 A->replaceLocalValues(i, indices, valuesNC());
1812 A->fillComplete(domMap, ranMap);
1815template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1817 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1818 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows) {
1819 TEUCHOS_ASSERT(A->isFillComplete());
1820 using ATS = KokkosKernels::ArithTraits<Scalar>;
1821 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1822 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1824 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A->getDomainMap();
1825 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> ranMap = A->getRangeMap();
1826 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> Rmap = A->getRowMap();
1827 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> Cmap = A->getColMap();
1829 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == Rmap->getLocalNumElements());
1831 auto localMatrix = A->getLocalMatrixDevice();
1832 auto localRmap = Rmap->getLocalMap();
1833 auto localCmap = Cmap->getLocalMap();
1835 Kokkos::parallel_for(
1836 "MueLu::Utils::ApplyOAZ", range_type(0, dirichletRows.extent(0)),
1838 if (dirichletRows(row)) {
1839 auto rowView = localMatrix.row(row);
1840 auto length = rowView.length;
1841 auto row_gid = localRmap.getGlobalElement(row);
1842 auto row_lid = localCmap.getLocalElement(row_gid);
1844 for (
decltype(length) colID = 0; colID < length; colID++)
1845 if (rowView.colidx(colID) == row_lid)
1846 rowView.value(colID) = impl_ATS::one();
1848 rowView.value(colID) = impl_ATS::zero();
1853template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1855 ZeroDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1856 const std::vector<LocalOrdinal>& dirichletRows,
1858 for (
size_t i = 0; i < dirichletRows.size(); i++) {
1859 Teuchos::ArrayView<const LocalOrdinal> indices;
1860 Teuchos::ArrayView<const Scalar> values;
1861 A->getLocalRowView(dirichletRows[i], indices, values);
1863 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1864 for (
size_t j = 0; j < (size_t)indices.size(); j++)
1865 valuesNC[j] = replaceWith;
1869template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1871 ZeroDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1872 const Teuchos::ArrayRCP<const bool>& dirichletRows,
1874 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == A->getRowMap()->getLocalNumElements());
1875 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1876 if (dirichletRows[i]) {
1877 Teuchos::ArrayView<const LocalOrdinal> indices;
1878 Teuchos::ArrayView<const Scalar> values;
1879 A->getLocalRowView(i, indices, values);
1881 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1882 for (
size_t j = 0; j < (size_t)indices.size(); j++)
1883 valuesNC[j] = replaceWith;
1888template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1890 ZeroDirichletRows(Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& X,
1891 const Teuchos::ArrayRCP<const bool>& dirichletRows,
1893 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == X->getMap()->getLocalNumElements());
1894 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1895 if (dirichletRows[i]) {
1896 for (
size_t j = 0; j < X->getNumVectors(); j++)
1897 X->replaceLocalValue(i, j, replaceWith);
1902template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1904 ZeroDirichletRows(RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1905 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows,
1907 using ATS = KokkosKernels::ArithTraits<Scalar>;
1908 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1910 typename ATS::val_type impl_replaceWith = replaceWith;
1912 auto localMatrix = A->getLocalMatrixDevice();
1915 Kokkos::parallel_for(
1916 "MueLu:Utils::ZeroDirichletRows", range_type(0, numRows),
1918 if (dirichletRows(row)) {
1919 auto rowView = localMatrix.row(row);
1920 auto length = rowView.length;
1921 for (
decltype(length) colID = 0; colID < length; colID++)
1922 rowView.value(colID) = impl_replaceWith;
1927template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1928void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1929 ZeroDirichletRows(RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& X,
1930 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows,
1932 using ATS = KokkosKernels::ArithTraits<Scalar>;
1933 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1935 typename ATS::val_type impl_replaceWith = replaceWith;
1937 auto myCols = X->getLocalViewDevice(Tpetra::Access::ReadWrite);
1938 size_t numVecs = X->getNumVectors();
1939 Kokkos::parallel_for(
1940 "MueLu:Utils::ZeroDirichletRows_MV", range_type(0, dirichletRows.size()),
1941 KOKKOS_LAMBDA(
const size_t i) {
1942 if (dirichletRows(i)) {
1943 for (
size_t j = 0; j < numVecs; j++)
1944 myCols(i, j) = impl_replaceWith;
1949template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1952 const Teuchos::ArrayRCP<const bool>& dirichletCols,
1954 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletCols.size()) == A->getColMap()->getLocalNumElements());
1955 for (
size_t i = 0; i < A->getLocalNumRows(); i++) {
1956 Teuchos::ArrayView<const LocalOrdinal> indices;
1957 Teuchos::ArrayView<const Scalar> values;
1958 A->getLocalRowView(i, indices, values);
1960 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1961 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
1962 if (dirichletCols[indices[j]])
1963 valuesNC[j] = replaceWith;
1967template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1969 ZeroDirichletCols(RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1970 const Kokkos::View<const bool*, typename Node::device_type>& dirichletCols,
1972 using ATS = KokkosKernels::ArithTraits<Scalar>;
1973 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1975 typename ATS::val_type impl_replaceWith = replaceWith;
1977 auto localMatrix = A->getLocalMatrixDevice();
1980 Kokkos::parallel_for(
1981 "MueLu:Utils::ZeroDirichletCols", range_type(0, numRows),
1983 auto rowView = localMatrix.row(row);
1984 auto length = rowView.length;
1985 for (
decltype(length) colID = 0; colID < length; colID++)
1986 if (dirichletCols(rowView.colidx(colID))) {
1987 rowView.value(colID) = impl_replaceWith;
1992template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1995 Teuchos::RCP<Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node>>& isDirichletRow,
1996 Teuchos::RCP<Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node>>& isDirichletCol) {
1998 if (!A->getRowMap()->isSameAs(*A->getDomainMap())) {
1999 throw std::runtime_error(
"UtilitiesBase::FindDirichletRowsAndPropagateToCols row and domain maps must match.");
2001 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A->getCrsGraph()->getImporter();
2002 bool has_import = !importer.is_null();
2005 std::vector<LocalOrdinal> dirichletRows;
2006 FindDirichletRows(A, dirichletRows);
2009 printf(
"[%d] DirichletRow Ids = ",A->getRowMap()->getComm()->getRank());
2010 for(
size_t i=0; i<(size_t) dirichletRows.size(); i++)
2011 printf(
"%d ",dirichletRows[i]);
2016 isDirichletRow = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(A->getRowMap(),
true);
2017 isDirichletCol = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(A->getColMap(),
true);
2020 Teuchos::ArrayRCP<int> dr_rcp =
isDirichletRow->getDataNonConst(0);
2021 Teuchos::ArrayView<int> dr = dr_rcp();
2022 Teuchos::ArrayRCP<int> dc_rcp = isDirichletCol->getDataNonConst(0);
2023 Teuchos::ArrayView<int> dc = dc_rcp();
2024 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
2025 dr[dirichletRows[i]] = 1;
2026 if (!has_import) dc[dirichletRows[i]] = 1;
2031 isDirichletCol->doImport(*
isDirichletRow, *importer, Xpetra::CombineMode::ADD);
2034template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2035RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
2038 using ISC =
typename KokkosKernels::ArithTraits<Scalar>::val_type;
2039 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
2040 using local_matrix_type =
typename CrsMatrix::local_matrix_device_type;
2041 using values_type =
typename local_matrix_type::values_type;
2043 const ISC ONE = KokkosKernels::ArithTraits<ISC>::one();
2044 const ISC ZERO = KokkosKernels::ArithTraits<ISC>::zero();
2047 auto localMatrix = original->getLocalMatrixDevice();
2048 TEUCHOS_TEST_FOR_EXCEPTION(!original->hasCrsGraph(),
Exceptions::RuntimeError,
"ReplaceNonZerosWithOnes: Cannot get CrsGraph");
2049 values_type new_values(
"values", localMatrix.nnz());
2051 Kokkos::parallel_for(
2052 "ReplaceNonZerosWithOnes", range_type(0, localMatrix.nnz()), KOKKOS_LAMBDA(
const size_t i) {
2053 if (localMatrix.values(i) != ZERO)
2054 new_values(i) = ONE;
2056 new_values(i) = ZERO;
2060 RCP<Matrix> NewMatrix = Xpetra::MatrixFactory<SC, LO, GO, NO>::Build(original->getCrsGraph(), new_values);
2061 TEUCHOS_TEST_FOR_EXCEPTION(NewMatrix.is_null(),
Exceptions::RuntimeError,
"ReplaceNonZerosWithOnes: MatrixFactory::Build() did not return matrix");
2062 NewMatrix->fillComplete(original->getDomainMap(), original->getRangeMap());
2066template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2067RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
2075#ifdef HAVE_MUELU_TIMER_SYNCHRONIZATION
2076 miniLevel.
SetComm(M->getRowMap()->getComm());
2078 miniLevel.
Set(
"A", M);
2082 invapproxFact->SetParameter(
"inverse: approximation type", Teuchos::ParameterEntry(std::string(
"sparseapproxinverse")));
2083 miniLevel.
Request(
"Ainv", invapproxFact.get());
2084 invapproxFact->Build(miniLevel);
2085 RCP<Matrix> NewMatrix = miniLevel.
Get<RCP<Matrix>>(
"Ainv", invapproxFact.get());
2086 TEUCHOS_TEST_FOR_EXCEPTION(NewMatrix.is_null(),
Exceptions::RuntimeError,
"SPAI: MatrixFactory::Build() did not return matrix");
2090template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2091RCP<const Xpetra::BlockedMap<LocalOrdinal, GlobalOrdinal, Node>>
2094 const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>& Importer) {
2095 typedef Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node> IntVector;
2096 Xpetra::UnderlyingLib lib = sourceBlockedMap.lib();
2099 RCP<const Map> fullMap = sourceBlockedMap.getMap();
2100 RCP<const Map> stridedMap = Teuchos::rcp_dynamic_cast<const Xpetra::StridedMap<LocalOrdinal, GlobalOrdinal, Node>>(fullMap);
2101 if (!stridedMap.is_null()) fullMap = stridedMap->getMap();
2104 const size_t numSubMaps = sourceBlockedMap.getNumMaps();
2105 if (!Importer.getSourceMap()->isCompatible(*fullMap))
2106 throw std::runtime_error(
"GenerateBlockedTargetMap(): Map compatibility error");
2109 RCP<IntVector> block_ids = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(fullMap);
2111 for (
size_t i = 0; i < numSubMaps; i++) {
2112 RCP<const Map> map = sourceBlockedMap.getMap(i);
2114 for (
size_t j = 0; j < map->getLocalNumElements(); j++) {
2115 LocalOrdinal jj = fullMap->getLocalElement(map->getGlobalElement(j));
2116 block_ids->replaceLocalValue(jj, (
int)i);
2121 RCP<const Map> targetMap = Importer.getTargetMap();
2122 RCP<IntVector> new_block_ids = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(targetMap);
2123 new_block_ids->doImport(*block_ids, Importer, Xpetra::CombineMode::ADD);
2124 Teuchos::ArrayRCP<const int> dataRCP = new_block_ids->getData(0);
2125 Teuchos::ArrayView<const int> data = dataRCP();
2128 Teuchos::Array<Teuchos::Array<GlobalOrdinal>> elementsInSubMap(numSubMaps);
2129 for (
size_t i = 0; i < targetMap->getLocalNumElements(); i++) {
2130 elementsInSubMap[data[i]].push_back(targetMap->getGlobalElement(i));
2134 std::vector<RCP<const Map>> subMaps(numSubMaps);
2135 for (
size_t i = 0; i < numSubMaps; i++) {
2136 subMaps[i] = Xpetra::MapFactory<LocalOrdinal, GlobalOrdinal, Node>::Build(lib, Teuchos::OrdinalTraits<GlobalOrdinal>::invalid(), elementsInSubMap[i](), targetMap->getIndexBase(), targetMap->getComm());
2140 return rcp(
new BlockedMap(targetMap, subMaps));
2143template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2145 MapsAreNested(
const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& rowMap,
const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& colMap) {
2146 if ((rowMap.lib() == Xpetra::UseTpetra) && (colMap.lib() == Xpetra::UseTpetra)) {
2147 auto tpRowMap = toTpetra(rowMap);
2148 auto tpColMap = toTpetra(colMap);
2149 return tpColMap.isLocallyFitted(tpRowMap);
2152 ArrayView<const GlobalOrdinal> rowElements = rowMap.getLocalElementList();
2153 ArrayView<const GlobalOrdinal> colElements = colMap.getLocalElementList();
2155 const size_t numElements = rowElements.size();
2157 if (
size_t(colElements.size()) < numElements)
2160 bool goodMap =
true;
2161 for (
size_t i = 0; i < numElements; i++)
2162 if (rowElements[i] != colElements[i]) {
2170template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2171Teuchos::RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>>
2173 ReverseCuthillMcKee(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op) {
2174 using local_matrix_type =
typename Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::local_matrix_device_type;
2175 using local_graph_type =
typename local_matrix_type::staticcrsgraph_type;
2176 using lno_nnz_view_t =
typename local_graph_type::entries_type::non_const_type;
2177 using device =
typename local_graph_type::device_type;
2178 using execution_space =
typename local_matrix_type::execution_space;
2179 using ordinal_type =
typename local_matrix_type::ordinal_type;
2181 local_graph_type localGraph = Op.getLocalMatrixDevice().graph;
2183 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);
2185 RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>> retval =
2186 Xpetra::VectorFactory<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(Op.getRowMap());
2189 auto view1D = Kokkos::subview(retval->getLocalViewDevice(Tpetra::Access::ReadWrite), Kokkos::ALL(), 0);
2190 Kokkos::parallel_for(
2191 "Utilities::ReverseCuthillMcKee",
2192 Kokkos::RangePolicy<ordinal_type, execution_space>(0, localGraph.numRows()),
2193 KOKKOS_LAMBDA(
const ordinal_type rowIdx) {
2194 view1D(rcmOrder(rowIdx)) = rowIdx;
2199template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2200Teuchos::RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>>
2202 CuthillMcKee(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op) {
2203 using local_matrix_type =
typename Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::local_matrix_device_type;
2204 using local_graph_type =
typename local_matrix_type::staticcrsgraph_type;
2205 using lno_nnz_view_t =
typename local_graph_type::entries_type::non_const_type;
2206 using device =
typename local_graph_type::device_type;
2207 using execution_space =
typename local_matrix_type::execution_space;
2208 using ordinal_type =
typename local_matrix_type::ordinal_type;
2210 local_graph_type localGraph = Op.getLocalMatrixDevice().graph;
2213 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);
2215 RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>> retval =
2216 Xpetra::VectorFactory<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(Op.getRowMap());
2219 auto view1D = Kokkos::subview(retval->getLocalViewDevice(Tpetra::Access::ReadWrite), Kokkos::ALL(), 0);
2221 Kokkos::parallel_for(
2222 "Utilities::ReverseCuthillMcKee",
2223 Kokkos::RangePolicy<ordinal_type, execution_space>(0, numRows),
2224 KOKKOS_LAMBDA(
const ordinal_type rowIdx) {
2225 view1D(rcmOrder(numRows - 1 - rowIdx)) = rowIdx;
2230template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2232 TripleMatrixProduct(
const Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& R,
2233 const Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
2234 const Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& P,
2235 Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& Ac,
2236 const Teuchos::ParameterList& pL,
2238 Teuchos::RCP<Teuchos::ParameterList>& APparams,
2239 Teuchos::RCP<Teuchos::ParameterList>& RAPparams,
2240 Level* coarseLevel) {
2241 using Matrix = Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
2242 using MatrixMatrix = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
2243 using MatrixFactory = Xpetra::MatrixFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
2246 const bool doTranspose =
true;
2247 const bool doFillComplete =
true;
2248 const bool doOptimizeStorage =
true;
2250 const bool useImplicit = pL.get<
bool>(
"transpose: use implicit");
2252 const std::string matrixName = (pL.isType<std::string>(
"Matrix name")) ? pL.get<std::string>(
"Matrix name") :
"A";
2253 const std::string prolongatorName = (pL.isType<std::string>(
"Prolongator name")) ? pL.get<std::string>(
"Prolongator name") :
"P";
2254 const std::string restrictorName = (pL.isType<std::string>(
"Restrictor name")) ? pL.get<std::string>(
"Restrictor name") :
"R";
2255 std::string coarseMatrixName;
2256 if (pL.isType<std::string>(
"coarseMatrixName"))
2257 coarseMatrixName = pL.get<std::string>(
"coarseMatrixName");
2259 if (matrixName.size() == 1)
2260 coarseMatrixName = matrixName +
"c";
2262 coarseMatrixName = matrixName +
"_coarse";
2265 std::string levelstr, labelstr;
2266 if (coarseLevel !=
nullptr) {
2267 std::ostringstream levelss;
2269 levelstr = levelss.str();
2270 labelstr = FormattingHelper::getColonLabel(coarseLevel->getObjectLabel());
2273 bool isGPU = Node::is_gpu;
2276 if (RAPparams.is_null())
2277 RAPparams = rcp(
new ParameterList);
2278 if (pL.isSublist(
"matrixmatrix: kernel params"))
2279 RAPparams->setParameters(pL.sublist(
"matrixmatrix: kernel params"));
2281 if (RAPparams->isParameter(
"graph")) {
2282 Ac = RAPparams->get<RCP<Matrix>>(
"graph");
2286 Ac->SetMaxEigenvalueEstimate(-Teuchos::ScalarTraits<Scalar>::one());
2290 RAPparams->set(
"compute global constants: temporaries", RAPparams->get(
"compute global constants: temporaries",
false));
2291 RAPparams->set(
"compute global constants",
true);
2293 if (pL.get<
bool>(
"rap: triple product") ==
false || isGPU) {
2294 if (pL.get<
bool>(
"rap: triple product") && isGPU)
2295 verbObj.
GetOStream(
Warnings1) <<
"Switching from triple product to R x (A x P) since triple product has not been implemented for "
2296 << Node::execution_space::name() << std::endl;
2301 if (APparams.is_null())
2302 APparams = rcp(
new ParameterList);
2303 if (pL.isSublist(
"matrixmatrix: kernel params"))
2304 APparams = rcp(
new ParameterList(pL.sublist(
"matrixmatrix: kernel params")));
2307 APparams->set(
"compute global constants: temporaries", APparams->get(
"compute global constants: temporaries",
false));
2308 APparams->set(
"compute global constants", APparams->get(
"compute global constants",
false));
2310 if (APparams->isParameter(
"graph"))
2311 AP = APparams->get<RCP<Matrix>>(
"graph");
2313 std::string monitorstrAP =
"MxM: " + matrixName +
" x " + prolongatorName;
2314 std::string timerstrAP =
"MueLu::" + matrixName +
"*" + prolongatorName;
2315 if (!labelstr.empty())
2316 timerstrAP = labelstr + timerstrAP;
2317 if (!levelstr.empty())
2318 timerstrAP = timerstrAP +
"-" + levelstr;
2323 AP = MatrixMatrix::Multiply(*A, !doTranspose, *P, !doTranspose, AP, verbObj.
GetOStream(
Statistics2),
2324 doFillComplete, doOptimizeStorage, timerstrAP, APparams);
2331 std::string timerstrRAP, monitorstrRAP;
2333 monitorstrRAP =
"MxM: " + prolongatorName +
"' x (" + matrixName + prolongatorName +
") (implicit)";
2334 timerstrRAP =
"MueLu::" + restrictorName +
"*(" + matrixName +
"*" + prolongatorName +
")-implicit";
2336 monitorstrRAP =
"MxM: " + restrictorName +
" x (" + matrixName + prolongatorName +
") (explicit)";
2337 timerstrRAP =
"MueLu::" + restrictorName +
"*(" + matrixName +
"*" + prolongatorName +
")-explicit";
2339 if (!labelstr.empty())
2340 timerstrRAP = labelstr + timerstrRAP;
2341 if (!levelstr.empty())
2342 timerstrRAP = timerstrRAP +
"-" + levelstr;
2347 Ac = MatrixMatrix::Multiply(*P, doTranspose, *AP, !doTranspose, Ac, verbObj.
GetOStream(
Statistics2),
2348 doFillComplete, doOptimizeStorage, timerstrRAP, RAPparams);
2353 Ac = MatrixMatrix::Multiply(*R, !doTranspose, *AP, !doTranspose, Ac, verbObj.
GetOStream(
Statistics2),
2354 doFillComplete, doOptimizeStorage, timerstrRAP, RAPparams);
2358 APparams->set(
"graph", AP);
2362 std::string monitorstrRAP;
2363 std::string timerstrRAP;
2365 monitorstrRAP =
"MxMxM: " + restrictorName +
" x " + matrixName +
" x " + prolongatorName +
" (implicit)";
2366 timerstrRAP =
"MueLu::" + restrictorName +
"*" + matrixName +
"*" + prolongatorName +
"-implicit";
2368 monitorstrRAP =
"MxMxM: " + restrictorName +
" x " + matrixName +
" x " + prolongatorName +
" (explicit)";
2369 timerstrRAP =
"MueLu::" + restrictorName +
"*" + matrixName +
"*" + prolongatorName +
"-explicit";
2371 if (!labelstr.empty())
2372 timerstrRAP = labelstr + timerstrRAP;
2373 if (!levelstr.empty())
2374 timerstrRAP = timerstrRAP +
"-" + levelstr;
2377 Ac = MatrixFactory::Build(P->getDomainMap(), Teuchos::as<LocalOrdinal>(0));
2381 Xpetra::TripleMatrixMultiply<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
2382 MultiplyRAP(*P, doTranspose, *A, !doTranspose, *P, !doTranspose, *Ac, doFillComplete,
2383 doOptimizeStorage, timerstrRAP,
2386 Ac = MatrixFactory::Build(R->getRowMap(), Teuchos::as<LocalOrdinal>(0));
2390 Xpetra::TripleMatrixMultiply<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
2391 MultiplyRAP(*R, !doTranspose, *A, !doTranspose, *P, !doTranspose, *Ac, doFillComplete,
2392 doOptimizeStorage, timerstrRAP,
2397 Teuchos::ArrayView<const double> relativeFloor = pL.get<Teuchos::Array<double>>(
"rap: relative diagonal floor")();
2398 if (relativeFloor.size() > 0) {
2399 Xpetra::MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::RelativeDiagonalBoost(Ac, relativeFloor, verbObj.
GetOStream(
Statistics2));
2402 bool repairZeroDiagonals = pL.get<
bool>(
"RepairMainDiagonal") || pL.get<
bool>(
"rap: fix zero diagonals");
2403 bool checkAc = pL.get<
bool>(
"CheckMainDiagonal") || pL.get<
bool>(
"rap: fix zero diagonals");
2405 if (checkAc || repairZeroDiagonals) {
2406 using magnitudeType =
typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
2407 magnitudeType threshold;
2408 if (pL.isType<magnitudeType>(
"rap: fix zero diagonals threshold"))
2409 threshold = pL.get<magnitudeType>(
"rap: fix zero diagonals threshold");
2411 threshold = Teuchos::as<magnitudeType>(pL.get<
double>(
"rap: fix zero diagonals threshold"));
2412 Scalar replacement = Teuchos::as<Scalar>(pL.get<
double>(
"rap: fix zero diagonals replacement"));
2413 Xpetra::MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::CheckRepairMainDiagonal(Ac, repairZeroDiagonals, verbObj.
GetOStream(
Warnings1), threshold, replacement);
2417 RCP<ParameterList> params = rcp(
new ParameterList());
2418 params->set(
"printLoadBalancingInfo",
true);
2419 params->set(
"printCommInfo",
true);
2424 RAPparams->set(
"graph", Ac);
2427 if (Behavior::debug())
2428 MatrixUtils::checkLocalRowMapMatchesColMap(*Ac);