476 Kokkos::View<int*, execution_space> nnzPerRow(
"nnz per rows", diag_dev.extent(0));
477 Kokkos::View<scalar_type*, execution_space> regSum(
"regSum", diag_dev.extent(0));
478 Kokkos::View<mag_type, execution_space> avgAbsDiagVal_dev(
"avgAbsDiagVal");
479 Kokkos::View<int, execution_space> numDiagsEqualToOne_dev(
"numDiagsEqualToOne");
482 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"GetLumpedMatrixDiagonal: parallel_for (doReciprocal)");
483 Kokkos::parallel_for(
484 "GetLumpedMatrixDiagonal", my_policy,
485 KOKKOS_LAMBDA(
const int rowIdx) {
486 diag_dev(rowIdx, 0) = KAT_S::zero();
487 for (size_type entryIdx = local_mat_dev.graph.row_map(rowIdx);
488 entryIdx < local_mat_dev.graph.row_map(rowIdx + 1);
490 regSum(rowIdx) += local_mat_dev.values(entryIdx);
491 if (KAT_M::zero() < KAT_S::abs(local_mat_dev.values(entryIdx))) {
494 diag_dev(rowIdx, 0) += KAT_S::abs(local_mat_dev.values(entryIdx));
495 if (rowIdx == local_mat_dev.graph.entries(entryIdx)) {
496 Kokkos::atomic_add(&avgAbsDiagVal_dev(), KAT_S::abs(local_mat_dev.values(entryIdx)));
500 if (nnzPerRow(rowIdx) == 1 && KAT_S::magnitude(diag_dev(rowIdx, 0)) == KAT_M::one()) {
501 Kokkos::atomic_add(&numDiagsEqualToOne_dev(), 1);
505 if (useAverageAbsDiagVal) {
506 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"GetLumpedMatrixDiagonal: useAverageAbsDiagVal");
507 typename Kokkos::View<mag_type, execution_space>::host_mirror_type avgAbsDiagVal = Kokkos::create_mirror_view(avgAbsDiagVal_dev);
508 Kokkos::deep_copy(avgAbsDiagVal, avgAbsDiagVal_dev);
509 int numDiagsEqualToOne;
510 Kokkos::deep_copy(numDiagsEqualToOne, numDiagsEqualToOne_dev);
512 tol = TST::magnitude(100 * Teuchos::ScalarTraits<Scalar>::eps()) * (avgAbsDiagVal() - numDiagsEqualToOne) / (rowMap->getLocalNumElements() - numDiagsEqualToOne);
516 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"ComputeLumpedDiagonalInverse: parallel_for (doReciprocal)");
517 Kokkos::parallel_for(
518 "ComputeLumpedDiagonalInverse", my_policy,
519 KOKKOS_LAMBDA(
const int rowIdx) {
520 if (replaceSingleEntryRowWithZero && nnzPerRow(rowIdx) <= 1) {
521 diag_dev(rowIdx, 0) = KAT_S::zero();
522 }
else if ((diag_dev(rowIdx, 0) != KAT_S::zero()) && (KAT_S::magnitude(diag_dev(rowIdx, 0)) < KAT_S::magnitude(2 * regSum(rowIdx)))) {
523 diag_dev(rowIdx, 0) = KAT_S::one() / KAT_S::magnitude(2 * regSum(rowIdx));
525 if (KAT_S::magnitude(diag_dev(rowIdx, 0)) > tol) {
526 diag_dev(rowIdx, 0) = KAT_S::one() / diag_dev(rowIdx, 0);
528 diag_dev(rowIdx, 0) = valReplacement_dev;
535 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"GetLumpedMatrixDiagonal: parallel_for");
536 Kokkos::parallel_for(
537 "GetLumpedMatrixDiagonal", my_policy,
538 KOKKOS_LAMBDA(
const int rowIdx) {
539 diag_dev(rowIdx, 0) = KAT_S::zero();
540 for (size_type entryIdx = local_mat_dev.graph.row_map(rowIdx);
541 entryIdx < local_mat_dev.graph.row_map(rowIdx + 1);
543 diag_dev(rowIdx, 0) += KAT_S::magnitude(local_mat_dev.values(entryIdx));
549 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"UtilitiesBase: GetLumpedMatrixDiagonal: (Teuchos implementation)");
550 ArrayRCP<Scalar> diagVals = diag->getDataNonConst(0);
551 Teuchos::Array<Scalar> regSum(diag->getLocalLength());
552 Teuchos::ArrayView<const LocalOrdinal> cols;
553 Teuchos::ArrayView<const Scalar> vals;
555 std::vector<int> nnzPerRow(rowMap->getLocalNumElements());
560 const Magnitude zeroMagn = TST::magnitude(zero);
561 Magnitude avgAbsDiagVal = TST::magnitude(zero);
562 int numDiagsEqualToOne = 0;
563 for (
size_t i = 0; i < rowMap->getLocalNumElements(); ++i) {
565 rcpA->getLocalRowView(i, cols, vals);
568 regSum[i] += vals[j];
569 const Magnitude rowEntryMagn = TST::magnitude(vals[j]);
570 if (rowEntryMagn > zeroMagn)
572 diagVals[i] += rowEntryMagn;
573 if (
static_cast<size_t>(cols[j]) == i)
574 avgAbsDiagVal += rowEntryMagn;
576 if (nnzPerRow[i] == 1 && TST::magnitude(diagVals[i]) == 1.)
577 numDiagsEqualToOne++;
579 if (useAverageAbsDiagVal)
580 tol = TST::magnitude(100 * Teuchos::ScalarTraits<Scalar>::eps()) * (avgAbsDiagVal - numDiagsEqualToOne) / (rowMap->getLocalNumElements() - numDiagsEqualToOne);
582 for (
size_t i = 0; i < rowMap->getLocalNumElements(); ++i) {
583 if (replaceSingleEntryRowWithZero && nnzPerRow[i] <=
static_cast<int>(1))
585 else if ((diagVals[i] != zero) && (TST::magnitude(diagVals[i]) < TST::magnitude(two * regSum[i])))
586 diagVals[i] = one / TST::magnitude((two * regSum[i]));
588 if (TST::magnitude(diagVals[i]) > tol)
589 diagVals[i] = one / diagVals[i];
591 diagVals[i] = valReplacement;
598 TEUCHOS_TEST_FOR_EXCEPTION(doReciprocal, Xpetra::Exceptions::RuntimeError,
599 "UtilitiesBase::GetLumpedMatrixDiagonal(): extracting reciprocal of diagonal of a blocked matrix is not supported");
600 diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(bA->getRangeMapExtractor()->getFullMap(),
true);
602 for (
size_t row = 0; row < bA->Rows(); ++row) {
603 for (
size_t col = 0; col < bA->Cols(); ++col) {
604 if (!bA->getMatrix(row, col).is_null()) {
606 bool bThyraMode = bA->getRangeMapExtractor()->getThyraMode() && (Teuchos::rcp_dynamic_cast<Xpetra::BlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>(bA->getMatrix(row, col)) == Teuchos::null);
607 RCP<Vector> ddtemp = bA->getRangeMapExtractor()->ExtractVector(diag, row, bThyraMode);
608 RCP<const Vector> dd = GetLumpedMatrixDiagonal(*(bA->getMatrix(row, col)));
609 ddtemp->update(Teuchos::as<Scalar>(1.0), *dd, Teuchos::as<Scalar>(1.0));
610 bA->getRangeMapExtractor()->InsertVector(ddtemp, row, diag, bThyraMode);
619template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
620Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
624 RCP<const Map> rowMap = A.getRowMap();
625 auto diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(rowMap,
false);
628 using local_vector_type =
typename Vector::dual_view_type::t_dev_um;
629 using local_matrix_type =
typename Matrix::local_matrix_device_type;
630 using execution_space =
typename local_vector_type::execution_space;
631 using values_type =
typename local_matrix_type::values_type;
632 using scalar_type =
typename values_type::non_const_value_type;
633 using KAT_S =
typename KokkosKernels::ArithTraits<scalar_type>;
635 auto diag_dev = diag->getLocalViewDevice(Tpetra::Access::OverwriteAll);
636 auto local_mat_dev = A.getLocalMatrixDevice();
637 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(diag_dev.extent(0)));
639 Kokkos::parallel_for(
640 "GetMatrixMaxMinusOffDiagonal", my_policy,
642 auto mymax = KAT_S::zero();
643 auto row = local_mat_dev.rowConst(rowIdx);
644 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
645 if (rowIdx != row.colidx(entryIdx)) {
646 if (KAT_S::real(mymax) < -KAT_S::real(row.value(entryIdx)))
647 mymax = -KAT_S::real(row.value(entryIdx));
650 diag_dev(rowIdx, 0) = mymax;
656template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
657Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
659 GetMatrixMaxMinusOffDiagonal(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber) {
660 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()), std::runtime_error,
"GetMatrixMaxMinusOffDiagonal: BlockNumber must match's A's column map.");
663 RCP<const Map> rowMap = A.getRowMap();
664 auto diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(rowMap,
false);
667 using local_vector_type =
typename Vector::dual_view_type::t_dev_um;
668 using local_matrix_type =
typename Matrix::local_matrix_device_type;
669 using execution_space =
typename local_vector_type::execution_space;
670 using values_type =
typename local_matrix_type::values_type;
671 using scalar_type =
typename values_type::non_const_value_type;
672 using KAT_S =
typename KokkosKernels::ArithTraits<scalar_type>;
674 auto diag_dev = diag->getLocalViewDevice(Tpetra::Access::OverwriteAll);
675 auto local_mat_dev = A.getLocalMatrixDevice();
676 auto local_block_dev = BlockNumber.getLocalViewDevice(Tpetra::Access::ReadOnly);
677 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(diag_dev.extent(0)));
679 Kokkos::parallel_for(
680 "GetMatrixMaxMinusOffDiagonal", my_policy,
682 auto mymax = KAT_S::zero();
683 auto row = local_mat_dev.row(rowIdx);
684 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
685 if ((rowIdx != row.colidx(entryIdx)) && (local_block_dev(rowIdx, 0) == local_block_dev(row.colidx(entryIdx), 0))) {
686 if (KAT_S::real(mymax) < -KAT_S::real(row.value(entryIdx)))
687 mymax = -KAT_S::real(row.value(entryIdx));
690 diag_dev(rowIdx, 0) = mymax;
696template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
697Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
699 GetInverse(Teuchos::RCP<
const Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> v,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tol,
Scalar valReplacement) {
700 RCP<Vector> ret = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(v->getMap(),
true);
703 RCP<const BlockedVector> bv = Teuchos::rcp_dynamic_cast<const BlockedVector>(v);
704 if (bv.is_null() ==
false) {
705 RCP<BlockedVector> bret = Teuchos::rcp_dynamic_cast<BlockedVector>(ret);
706 TEUCHOS_TEST_FOR_EXCEPTION(bret.is_null() ==
true,
MueLu::Exceptions::RuntimeError,
"MueLu::UtilitiesBase::GetInverse: return vector should be of type BlockedVector");
707 RCP<const BlockedMap> bmap = bv->getBlockedMap();
708 for (
size_t r = 0; r < bmap->getNumMaps(); ++r) {
709 RCP<const MultiVector> submvec = bv->getMultiVector(r, bmap->getThyraMode());
710 RCP<const Vector> subvec = submvec->getVector(0);
712 bret->setMultiVector(r, subvecinf, bmap->getThyraMode());
718 ArrayRCP<Scalar> retVals = ret->getDataNonConst(0);
719 ArrayRCP<const Scalar> inputVals = v->getData(0);
720 for (
size_t i = 0; i < v->getMap()->getLocalNumElements(); ++i) {
721 if (Teuchos::ScalarTraits<Scalar>::magnitude(inputVals[i]) > tol)
722 retVals[i] = Teuchos::ScalarTraits<Scalar>::one() / inputVals[i];
724 retVals[i] = valReplacement;
767template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
768RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
771 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
772 RCP<Vector> localDiag = GetMatrixDiagonal(A);
773 RCP<const Import> importer = A.getCrsGraph()->getImporter();
774 if (importer.is_null() && !rowMap->isSameAs(*colMap)) {
775 importer = ImportFactory::Build(rowMap, colMap);
777 if (!importer.is_null()) {
778 RCP<Vector> diagonal = VectorFactory::Build(colMap,
false);
779 diagonal->doImport(*localDiag, *(importer), Xpetra::INSERT);
785template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
786RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
789 using STS =
typename Teuchos::ScalarTraits<SC>;
792 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
793 RCP<const BlockedMap> browMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
794 if (!browMap.is_null()) rowMap = browMap->getMap();
796 RCP<Vector> local = Xpetra::VectorFactory<SC, LO, GO, Node>::Build(rowMap);
797 RCP<Vector> ghosted = Xpetra::VectorFactory<SC, LO, GO, Node>::Build(colMap,
true);
798 ArrayRCP<SC> localVals = local->getDataNonConst(0);
800 for (LO row = 0; row < static_cast<LO>(A.getRowMap()->getLocalNumElements()); ++row) {
801 size_t nnz = A.getNumEntriesInLocalRow(row);
802 ArrayView<const LO> indices;
803 ArrayView<const SC> vals;
804 A.getLocalRowView(row, indices, vals);
808 for (LO colID = 0; colID < static_cast<LO>(nnz); colID++) {
809 if (indices[colID] != row) {
816 RCP<const Xpetra::Import<LO, GO, Node>> importer;
817 importer = A.getCrsGraph()->getImporter();
818 if (importer == Teuchos::null) {
819 importer = Xpetra::ImportFactory<LO, GO, Node>::Build(rowMap, colMap);
821 ghosted->doImport(*local, *(importer), Xpetra::INSERT);
825template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
829 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
830 using STS =
typename Teuchos::ScalarTraits<Scalar>;
831 using MTS =
typename Teuchos::ScalarTraits<Magnitude>;
833 using RealValuedVector = Xpetra::Vector<MT, LO, GO, Node>;
836 RCP<const BlockedMap> browMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
837 if (!browMap.is_null()) rowMap = browMap->getMap();
839 RCP<RealValuedVector> local = Xpetra::VectorFactory<MT, LO, GO, Node>::Build(rowMap);
840 RCP<RealValuedVector> ghosted = Xpetra::VectorFactory<MT, LO, GO, Node>::Build(colMap,
true);
841 ArrayRCP<MT> localVals = local->getDataNonConst(0);
843 for (LO rowIdx = 0; rowIdx < static_cast<LO>(A.getRowMap()->getLocalNumElements()); ++rowIdx) {
844 size_t nnz = A.getNumEntriesInLocalRow(rowIdx);
845 ArrayView<const LO> indices;
846 ArrayView<const SC> vals;
847 A.getLocalRowView(rowIdx, indices, vals);
851 for (LO colID = 0; colID < static_cast<LO>(nnz); ++colID) {
852 if (indices[colID] != rowIdx) {
853 si += STS::magnitude(vals[colID]);
856 localVals[rowIdx] = si;
859 RCP<const Xpetra::Import<LO, GO, Node>> importer;
860 importer = A.getCrsGraph()->getImporter();
861 if (importer == Teuchos::null) {
862 importer = Xpetra::ImportFactory<LO, GO, Node>::Build(rowMap, colMap);
864 ghosted->doImport(*local, *(importer), Xpetra::INSERT);
868template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
872 using local_matrix_type =
typename Matrix::local_matrix_device_type;
873 using execution_space =
typename local_matrix_type::execution_space;
874 using KAT_S =
typename KokkosKernels::ArithTraits<typename local_matrix_type::value_type>;
876 auto local_mat_dev = A.getLocalMatrixDevice();
877 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(local_mat_dev.numRows()));
880 Kokkos::parallel_reduce(
881 "CountNegativeDiagonalEntries", my_policy,
883 auto row = local_mat_dev.row(rowIdx);
884 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
885 if (rowIdx == row.colidx(entryIdx) && KAT_S::real(row.value(entryIdx)) < 0)
891 MueLu_sumAll(A.getRowMap()->getComm(), count_l, count_g);
895template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
896Teuchos::Array<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>
898 ResidualNorm(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS) {
899 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
900 const size_t numVecs = X.getNumVectors();
901 RCP<MultiVector> RES = Residual(Op, X, RHS);
902 Teuchos::Array<Magnitude> norms(numVecs);
907template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
908Teuchos::Array<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>
910 ResidualNorm(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS, MultiVector& Resid) {
911 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
912 const size_t numVecs = X.getNumVectors();
913 Residual(Op, X, RHS, Resid);
914 Teuchos::Array<Magnitude> norms(numVecs);
919template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
920RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
922 Residual(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS) {
923 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
924 const size_t numVecs = X.getNumVectors();
926 RCP<MultiVector> RES = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(RHS.getMap(), numVecs,
false);
927 Op.residual(X, RHS, *RES);
931template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
933 Residual(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS, MultiVector& Resid) {
934 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides");
935 TEUCHOS_TEST_FOR_EXCEPTION(Resid.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of residual vectors != number of right-hand sides");
936 Op.residual(X, RHS, Resid);
939template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
943 LocalOrdinal niters,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType diagonalReplacementTolerance,
bool verbose,
unsigned int seed) {
945 "Utils::PowerMethod: operator must have domain and range maps that are equivalent.");
948 RCP<Vector> diagInvVec;
950 diagInvVec = GetMatrixDiagonalInverse(A, diagonalReplacementTolerance);
953 Scalar lambda = PowerMethod(A, diagInvVec, niters, tolerance, verbose, seed);
957template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
959UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
960 PowerMethod(
const Matrix& A,
const RCP<Vector>& diagInvVec,
961 LocalOrdinal niters,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance,
bool verbose,
unsigned int seed) {
962 TEUCHOS_TEST_FOR_EXCEPTION(!(A.getRangeMap()->isSameAs(*(A.getDomainMap()))), Exceptions::Incompatible,
963 "Utils::PowerMethod: operator must have domain and range maps that are equivalent.");
966 RCP<Vector> q = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getDomainMap(),
true);
967 RCP<Vector> r = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRangeMap(),
true);
968 RCP<Vector> z = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRangeMap(),
false);
973 Teuchos::Array<Magnitude> norms(1);
975 typedef Teuchos::ScalarTraits<Scalar> STS;
977 const Scalar zero = STS::zero(), one = STS::one();
980 Magnitude residual = STS::magnitude(zero);
983 for (
int iter = 0; iter < niters; ++iter) {
985 q->update(one / norms[0], *z, zero);
987 if (diagInvVec != Teuchos::null)
988 z->elementWiseMultiply(one, *diagInvVec, *z, zero);
991 if (iter % 100 == 0 || iter + 1 == niters) {
992 r->update(1.0, *z, -lambda, *q, zero);
994 residual = STS::magnitude(norms[0] / lambda);
996 std::cout <<
"Iter = " << iter
997 <<
" Lambda = " << lambda
998 <<
" Residual of A*q - lambda*q = " << residual
1002 if (residual < tolerance)
1008template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1009RCP<Teuchos::FancyOStream>
1012 RCP<Teuchos::FancyOStream> fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(os));
1016template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1017typename Teuchos::ScalarTraits<Scalar>::magnitudeType
1020 const size_t numVectors = v.size();
1022 Scalar d = Teuchos::ScalarTraits<Scalar>::zero();
1023 for (
size_t j = 0; j < numVectors; j++) {
1024 d += (v[j][i0] - v[j][i1]) * (v[j][i0] - v[j][i1]);
1026 return Teuchos::ScalarTraits<Scalar>::magnitude(d);
1029template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1030typename Teuchos::ScalarTraits<Scalar>::magnitudeType
1033 const size_t numVectors = v.size();
1034 using MT =
typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
1036 Scalar d = Teuchos::ScalarTraits<Scalar>::zero();
1037 for (
size_t j = 0; j < numVectors; j++) {
1038 d += Teuchos::as<MT>(weight[j]) * (v[j][i0] - v[j][i1]) * (v[j][i0] - v[j][i1]);
1040 return Teuchos::ScalarTraits<Scalar>::magnitude(d);
1043template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1044Teuchos::ArrayRCP<const bool>
1046 DetectDirichletRows(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType& tol,
bool count_twos_as_dirichlet) {
1048 typedef Teuchos::ScalarTraits<Scalar> STS;
1049 ArrayRCP<bool> boundaryNodes(numRows,
true);
1050 if (count_twos_as_dirichlet) {
1052 ArrayView<const LocalOrdinal> indices;
1053 ArrayView<const Scalar> vals;
1054 A.getLocalRowView(row, indices, vals);
1055 size_t nnz = A.getNumEntriesInLocalRow(row);
1058 for (col = 0; col < nnz; col++)
1059 if ((indices[col] != row) && STS::magnitude(vals[col]) > tol) {
1060 if (!boundaryNodes[row])
1062 boundaryNodes[row] =
false;
1065 boundaryNodes[row] =
true;
1070 ArrayView<const LocalOrdinal> indices;
1071 ArrayView<const Scalar> vals;
1072 A.getLocalRowView(row, indices, vals);
1073 size_t nnz = A.getNumEntriesInLocalRow(row);
1075 for (
size_t col = 0; col < nnz; col++)
1076 if ((indices[col] != row) && STS::magnitude(vals[col]) > tol) {
1077 boundaryNodes[row] =
false;
1082 return boundaryNodes;
1085template <
class CrsMatrix>
1086KOKKOS_FORCEINLINE_FUNCTION
bool isDirichletRow(
typename CrsMatrix::ordinal_type rowId,
1087 KokkosSparse::SparseRowViewConst<CrsMatrix>& row,
1088 const typename KokkosKernels::ArithTraits<typename CrsMatrix::value_type>::magnitudeType& tol,
1089 const bool count_twos_as_dirichlet) {
1090 using ATS = KokkosKernels::ArithTraits<typename CrsMatrix::value_type>;
1092 auto length = row.length;
1093 bool boundaryNode =
true;
1095 if (count_twos_as_dirichlet) {
1097 decltype(length) colID = 0;
1098 for (; colID < length; colID++)
1099 if ((row.colidx(colID) != rowId) &&
1100 (ATS::magnitude(row.value(colID)) > tol)) {
1103 boundaryNode =
false;
1105 if (colID == length)
1106 boundaryNode =
true;
1109 for (
decltype(length) colID = 0; colID < length; colID++)
1110 if ((row.colidx(colID) != rowId) &&
1111 (ATS::magnitude(row.value(colID)) > tol)) {
1112 boundaryNode =
false;
1116 return boundaryNode;
1119template <
class SC,
class LO,
class GO,
class NO,
class memory_space>
1120Kokkos::View<bool*, memory_space>
1122 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1123 const bool count_twos_as_dirichlet) {
1124 using impl_scalar_type =
typename KokkosKernels::ArithTraits<SC>::val_type;
1125 using ATS = KokkosKernels::ArithTraits<impl_scalar_type>;
1126 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
1127 using helpers = Xpetra::Helpers<SC, LO, GO, NO>;
1129 Kokkos::View<bool*, typename NO::device_type::memory_space> boundaryNodes;
1131 if (helpers::isTpetraBlockCrs(A)) {
1132 const Tpetra::BlockCrsMatrix<SC, LO, GO, NO>& Am = toTpetraBlock(A);
1133 auto b_graph = Am.getCrsGraph().getLocalGraphDevice();
1134 auto b_rowptr = Am.getCrsGraph().getLocalRowPtrsDevice();
1135 auto values = Am.getValuesDevice();
1136 LO numBlockRows = Am.getLocalNumRows();
1137 const LO stride = Am.getBlockSize() * Am.getBlockSize();
1139 boundaryNodes = Kokkos::View<bool*, typename NO::device_type::memory_space>(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), numBlockRows);
1141 if (count_twos_as_dirichlet)
1144 Kokkos::parallel_for(
1145 "MueLu:Utils::DetectDirichletRowsBlockCrs", range_type(0, numBlockRows),
1146 KOKKOS_LAMBDA(
const LO row) {
1147 auto rowView = b_graph.rowConst(row);
1148 auto length = rowView.length;
1149 LO valstart = b_rowptr[row] * stride;
1151 boundaryNodes(row) =
true;
1152 decltype(length) colID = 0;
1153 for (; colID < length; colID++) {
1154 if (rowView.colidx(colID) != row) {
1155 LO current = valstart + colID * stride;
1156 for (LO k = 0; k < stride; k++) {
1157 if (ATS::magnitude(values[current + k]) > tol) {
1158 boundaryNodes(row) =
false;
1163 if (boundaryNodes(row) ==
false)
1168 auto localMatrix = A.getLocalMatrixDevice();
1169 LO numRows = A.getLocalNumRows();
1170 boundaryNodes = Kokkos::View<bool*, typename NO::device_type::memory_space>(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), numRows);
1172 Kokkos::parallel_for(
1173 "MueLu:Utils::DetectDirichletRows", range_type(0, numRows),
1174 KOKKOS_LAMBDA(
const LO row) {
1175 auto rowView = localMatrix.rowConst(row);
1176 boundaryNodes(row) =
isDirichletRow(row, rowView, tol, count_twos_as_dirichlet);
1179 if constexpr (std::is_same<memory_space, typename NO::device_type::memory_space>::value)
1180 return boundaryNodes;
1182 Kokkos::View<bool*, memory_space> boundaryNodes2(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), boundaryNodes.extent(0));
1183 Kokkos::deep_copy(boundaryNodes2, boundaryNodes);
1184 return boundaryNodes2;
1187 Kokkos::View<bool*, memory_space> dummy(
"dummy", 0);
1191template <
class SC,
class LO,
class GO,
class NO>
1192Kokkos::View<bool*, typename NO::device_type::memory_space>
1195 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1196 const bool count_twos_as_dirichlet) {
1197 return MueLu::DetectDirichletRows_kokkos<SC, LO, GO, NO, typename NO::device_type::memory_space>(A, tol, count_twos_as_dirichlet);
1200template <
class SC,
class LO,
class GO,
class NO>
1201Kokkos::View<bool*, typename Kokkos::HostSpace>
1204 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1205 const bool count_twos_as_dirichlet) {
1206 return MueLu::DetectDirichletRows_kokkos<SC, LO, GO, NO, typename Kokkos::HostSpace>(A, tol, count_twos_as_dirichlet);
1209template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1210Teuchos::ArrayRCP<const bool>
1212 DetectDirichletRowsExt(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
bool& bHasZeroDiagonal,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType& tol) {
1214 bHasZeroDiagonal =
false;
1216 Teuchos::RCP<Vector> diagVec = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRowMap());
1217 A.getLocalDiagCopy(*diagVec);
1218 Teuchos::ArrayRCP<const Scalar> diagVecData = diagVec->getData(0);
1221 typedef Teuchos::ScalarTraits<Scalar> STS;
1222 ArrayRCP<bool> boundaryNodes(numRows,
false);
1224 ArrayView<const LocalOrdinal> indices;
1225 ArrayView<const Scalar> vals;
1226 A.getLocalRowView(row, indices, vals);
1228 bool bHasDiag =
false;
1229 for (
decltype(indices.size()) col = 0; col < indices.size(); col++) {
1230 if (indices[col] != row) {
1231 if (STS::magnitude(vals[col] / STS::magnitude(sqrt(STS::magnitude(diagVecData[row]) * STS::magnitude(diagVecData[col])))) > tol) {
1237 if (bHasDiag ==
false)
1238 bHasZeroDiagonal =
true;
1240 boundaryNodes[row] =
true;
1242 return boundaryNodes;
1245template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1248 const Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>& RHS,
1249 Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>& InitialGuess,
1250 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1251 const bool count_twos_as_dirichlet) {
1252 using range_type = Kokkos::RangePolicy<LO, typename Node::execution_space>;
1256 TEUCHOS_ASSERT_EQUALITY(numVectors, Teuchos::as<LocalOrdinal>(InitialGuess.getNumVectors()));
1257 if (Behavior::debug())
1258 TEUCHOS_ASSERT(RHS.getMap()->isCompatible(*InitialGuess.getMap()));
1260 auto lclRHS = RHS.getLocalViewDevice(Tpetra::Access::ReadOnly);
1261 auto lclInitialGuess = InitialGuess.getLocalViewDevice(Tpetra::Access::ReadWrite);
1262 auto lclA = A.getLocalMatrixDevice();
1264 Kokkos::parallel_for(
1265 "MueLu:Utils::EnforceInitialCondition", range_type(0, numRows),
1266 KOKKOS_LAMBDA(
const LO i) {
1267 auto row = lclA.rowConst(i);
1270 lclInitialGuess(i, j) = lclRHS(i, j);
1275template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1277 FindNonZeros(
const Teuchos::ArrayRCP<const Scalar> vals,
1278 Teuchos::ArrayRCP<bool> nonzeros) {
1279 TEUCHOS_ASSERT(vals.size() == nonzeros.size());
1280 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType magnitudeType;
1281 const magnitudeType eps = 2.0 * Teuchos::ScalarTraits<magnitudeType>::eps();
1282 for (
size_t i = 0; i < static_cast<size_t>(vals.size()); i++) {
1283 nonzeros[i] = (Teuchos::ScalarTraits<Scalar>::magnitude(vals[i]) > eps);
1288template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1290 FindNonZeros(
const typename Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dual_view_type::t_dev_const_um vals,
1291 Kokkos::View<bool*, typename Node::device_type> nonzeros) {
1292 using ATS = KokkosKernels::ArithTraits<Scalar>;
1293 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1294 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1295 TEUCHOS_ASSERT(vals.extent(0) == nonzeros.extent(0));
1296 const typename ATS::magnitudeType eps = 2.0 * impl_ATS::eps();
1298 Kokkos::parallel_for(
1299 "MueLu:Maxwell1::FindNonZeros", range_type(0, vals.extent(0)),
1300 KOKKOS_LAMBDA(
const size_t i) {
1301 nonzeros(i) = (impl_ATS::magnitude(vals(i, 0)) > eps);
1305template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1308 const Teuchos::ArrayRCP<bool>& dirichletRows,
1309 Teuchos::ArrayRCP<bool> dirichletCols,
1310 Teuchos::ArrayRCP<bool> dirichletDomain) {
1311 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1312 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1313 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowMap = A.getRowMap();
1314 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1315 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == rowMap->getLocalNumElements());
1316 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletCols.size()) == colMap->getLocalNumElements());
1317 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletDomain.size()) == domMap->getLocalNumElements());
1318 RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, 1,
true);
1320 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1321 if (dirichletRows[i]) {
1322 ArrayView<const LocalOrdinal> indices;
1323 ArrayView<const Scalar> values;
1324 A.getLocalRowView(i, indices, values);
1325 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
1326 myColsToZero->replaceLocalValue(indices[j], 0, one);
1330 RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero;
1331 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A.getCrsGraph()->getImporter();
1332 if (!importer.is_null()) {
1333 globalColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap, 1,
true);
1335 globalColsToZero->doExport(*myColsToZero, *importer, Xpetra::ADD);
1337 myColsToZero->doImport(*globalColsToZero, *importer, Xpetra::INSERT);
1339 globalColsToZero = myColsToZero;
1341 FindNonZeros(globalColsToZero->getData(0), dirichletDomain);
1342 FindNonZeros(myColsToZero->getData(0), dirichletCols);
1345template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1348 const Kokkos::View<bool*, typename Node::device_type>& dirichletRows,
1349 Kokkos::View<bool*, typename Node::device_type> dirichletCols,
1350 Kokkos::View<bool*, typename Node::device_type> dirichletDomain) {
1351 using ATS = KokkosKernels::ArithTraits<Scalar>;
1352 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1353 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1354 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1355 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowMap = A.getRowMap();
1356 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1357 TEUCHOS_ASSERT(dirichletRows.extent(0) == rowMap->getLocalNumElements());
1358 TEUCHOS_ASSERT(dirichletCols.extent(0) == colMap->getLocalNumElements());
1359 TEUCHOS_ASSERT(dirichletDomain.extent(0) == domMap->getLocalNumElements());
1360 RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap,
true);
1362 auto myColsToZeroView = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadWrite);
1363 auto localMatrix = A.getLocalMatrixDevice();
1364 Kokkos::parallel_for(
1365 "MueLu:Maxwell1::DetectDirichletCols", range_type(0, rowMap->getLocalNumElements()),
1367 if (dirichletRows(row)) {
1368 auto rowView = localMatrix.row(row);
1369 auto length = rowView.length;
1371 for (
decltype(length) colID = 0; colID < length; colID++)
1372 myColsToZeroView(rowView.colidx(colID), 0) = impl_ATS::one();
1376 RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero;
1377 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A.getCrsGraph()->getImporter();
1378 if (!importer.is_null()) {
1379 globalColsToZero = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap,
true);
1381 globalColsToZero->doExport(*myColsToZero, *importer, Xpetra::ADD);
1383 myColsToZero->doImport(*globalColsToZero, *importer, Xpetra::INSERT);
1385 globalColsToZero = myColsToZero;
1390template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1392 ApplyRowSumCriterion(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol, Teuchos::ArrayRCP<bool>& dirichletRows) {
1393 typedef Teuchos::ScalarTraits<Scalar> STS;
1394 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1395 typedef Teuchos::ScalarTraits<MT> MTS;
1396 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1397 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1398 size_t nnz = A.getNumEntriesInLocalRow(row);
1399 ArrayView<const LocalOrdinal> indices;
1400 ArrayView<const Scalar> vals;
1401 A.getLocalRowView(row, indices, vals);
1403 Scalar rowsum = STS::zero();
1404 Scalar diagval = STS::zero();
1406 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1409 diagval = vals[colID];
1410 rowsum += vals[colID];
1413 if (rowSumTol < MTS::one() && STS::magnitude(rowsum) > STS::magnitude(diagval) * rowSumTol) {
1415 dirichletRows[row] =
true;
1420template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1421void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1422 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) {
1423 typedef Teuchos::ScalarTraits<Scalar> STS;
1424 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1425 typedef Teuchos::ScalarTraits<MT> MTS;
1426 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1428 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()), std::runtime_error,
"ApplyRowSumCriterion: BlockNumber must match's A's column map.");
1430 Teuchos::ArrayRCP<const LocalOrdinal> block_id = BlockNumber.getData(0);
1431 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1432 size_t nnz = A.getNumEntriesInLocalRow(row);
1433 ArrayView<const LocalOrdinal> indices;
1434 ArrayView<const Scalar> vals;
1435 A.getLocalRowView(row, indices, vals);
1437 Scalar rowsum = STS::zero();
1438 Scalar diagval = STS::zero();
1439 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1442 diagval = vals[colID];
1443 if (block_id[row] == block_id[col])
1444 rowsum += vals[colID];
1448 if (rowSumTol < MTS::one() && STS::magnitude(rowsum) > STS::magnitude(diagval) * rowSumTol) {
1450 dirichletRows[row] =
true;
1456template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node,
class memory_space>
1458 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1459 Kokkos::View<bool*, memory_space>& dirichletRows) {
1460 typedef Teuchos::ScalarTraits<Scalar> STS;
1461 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1463 auto dirichletRowsHost = Kokkos::create_mirror_view(dirichletRows);
1464 Kokkos::deep_copy(dirichletRowsHost, dirichletRows);
1466 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1467 size_t nnz = A.getNumEntriesInLocalRow(row);
1468 ArrayView<const LocalOrdinal> indices;
1469 ArrayView<const Scalar> vals;
1470 A.getLocalRowView(row, indices, vals);
1472 Scalar rowsum = STS::zero();
1473 Scalar diagval = STS::zero();
1474 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1477 diagval = vals[colID];
1478 rowsum += vals[colID];
1480 if (STS::real(rowsum) > STS::magnitude(diagval) * rowSumTol)
1481 dirichletRowsHost(row) =
true;
1484 Kokkos::deep_copy(dirichletRows, dirichletRowsHost);
1487template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1488void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1489 ApplyRowSumCriterion(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1490 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1491 Kokkos::View<bool*, typename Node::device_type::memory_space>& dirichletRows) {
1492 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, typename Node::device_type::memory_space>(A, rowSumTol, dirichletRows);
1495template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1496void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1497 ApplyRowSumCriterionHost(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1498 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1499 Kokkos::View<bool*, Kokkos::HostSpace>& dirichletRows) {
1500 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, Kokkos::HostSpace>(A, rowSumTol, dirichletRows);
1504template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node,
class memory_space>
1506 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1507 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1508 Kokkos::View<bool*, memory_space>& dirichletRows) {
1509 typedef Teuchos::ScalarTraits<Scalar> STS;
1510 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1512 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()), std::runtime_error,
"ApplyRowSumCriterion: BlockNumber must match's A's column map.");
1514 auto dirichletRowsHost = Kokkos::create_mirror_view(dirichletRows);
1515 Kokkos::deep_copy(dirichletRowsHost, dirichletRows);
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];
1533 if (STS::real(rowsum) > STS::magnitude(diagval) * rowSumTol)
1534 dirichletRowsHost(row) =
true;
1537 Kokkos::deep_copy(dirichletRows, dirichletRowsHost);
1540template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1541void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1542 ApplyRowSumCriterion(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1543 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1544 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1545 Kokkos::View<bool*, typename Node::device_type::memory_space>& dirichletRows) {
1546 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, typename Node::device_type::memory_space>(A, BlockNumber, rowSumTol, dirichletRows);
1549template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1550void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1551 ApplyRowSumCriterionHost(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1552 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1553 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1554 Kokkos::View<bool*, Kokkos::HostSpace>& dirichletRows) {
1555 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, Kokkos::HostSpace>(A, BlockNumber, rowSumTol, dirichletRows);
1558template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1559Teuchos::ArrayRCP<const bool>
1562 const Teuchos::ArrayRCP<const bool>& dirichletRows) {
1563 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1564 Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1565 Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1566 Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1567 Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, 1);
1568 myColsToZero->putScalar(zero);
1570 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1571 if (dirichletRows[i]) {
1572 Teuchos::ArrayView<const LocalOrdinal> indices;
1573 Teuchos::ArrayView<const Scalar> values;
1574 A.getLocalRowView(i, indices, values);
1575 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
1576 myColsToZero->replaceLocalValue(indices[j], 0, one);
1580 Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap, 1);
1581 globalColsToZero->putScalar(zero);
1582 Teuchos::RCP<Xpetra::Export<LocalOrdinal, GlobalOrdinal, Node>> exporter = Xpetra::ExportFactory<LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, domMap);
1584 globalColsToZero->doExport(*myColsToZero, *exporter, Xpetra::ADD);
1586 myColsToZero->doImport(*globalColsToZero, *exporter, Xpetra::INSERT);
1587 Teuchos::ArrayRCP<const Scalar> myCols = myColsToZero->getData(0);
1588 Teuchos::ArrayRCP<bool> dirichletCols(colMap->getLocalNumElements(),
true);
1589 Magnitude eps = Teuchos::ScalarTraits<Magnitude>::eps();
1590 for (
size_t i = 0; i < colMap->getLocalNumElements(); i++) {
1591 dirichletCols[i] = Teuchos::ScalarTraits<Scalar>::magnitude(myCols[i]) > 2.0 * eps;
1593 return dirichletCols;
1596template <
class SC,
class LO,
class GO,
class NO>
1597Kokkos::View<bool*, typename NO::device_type>
1600 const Kokkos::View<const bool*, typename NO::device_type>& dirichletRows) {
1601 using ATS = KokkosKernels::ArithTraits<SC>;
1602 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1603 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
1605 SC zero = ATS::zero();
1607 auto localMatrix = A.getLocalMatrixDevice();
1608 LO numRows = A.getLocalNumRows();
1610 Teuchos::RCP<const Xpetra::Map<LO, GO, NO>> domMap = A.getDomainMap();
1611 Teuchos::RCP<const Xpetra::Map<LO, GO, NO>> colMap = A.getColMap();
1612 Teuchos::RCP<Xpetra::MultiVector<SC, LO, GO, NO>> myColsToZero = Xpetra::MultiVectorFactory<SC, LO, GO, NO>::Build(colMap, 1);
1613 myColsToZero->putScalar(zero);
1614 auto myColsToZeroView = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadWrite);
1616 Kokkos::parallel_for(
1617 "MueLu:Utils::DetectDirichletCols1", range_type(0, numRows),
1618 KOKKOS_LAMBDA(
const LO row) {
1619 if (dirichletRows(row)) {
1620 auto rowView = localMatrix.row(row);
1621 auto length = rowView.length;
1623 for (
decltype(length) colID = 0; colID < length; colID++)
1624 myColsToZeroView(rowView.colidx(colID), 0) = impl_ATS::one();
1628 Teuchos::RCP<Xpetra::MultiVector<SC, LO, GO, NO>> globalColsToZero = Xpetra::MultiVectorFactory<SC, LO, GO, NO>::Build(domMap, 1);
1629 globalColsToZero->putScalar(zero);
1630 Teuchos::RCP<Xpetra::Export<LO, GO, NO>> exporter = Xpetra::ExportFactory<LO, GO, NO>::Build(colMap, domMap);
1632 globalColsToZero->doExport(*myColsToZero, *exporter, Xpetra::ADD);
1634 myColsToZero->doImport(*globalColsToZero, *exporter, Xpetra::INSERT);
1636 auto myCols = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadOnly);
1637 size_t numColEntries = colMap->getLocalNumElements();
1638 Kokkos::View<bool*, typename NO::device_type> dirichletCols(Kokkos::ViewAllocateWithoutInitializing(
"dirichletCols"), numColEntries);
1639 const typename ATS::magnitudeType eps = 2.0 * ATS::eps();
1641 Kokkos::parallel_for(
1642 "MueLu:Utils::DetectDirichletCols2", range_type(0, numColEntries),
1643 KOKKOS_LAMBDA(
const size_t i) {
1644 dirichletCols(i) = impl_ATS::magnitude(myCols(i, 0)) > eps;
1646 return dirichletCols;
1649template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1652 Frobenius(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& B) {
1657 TEUCHOS_TEST_FOR_EXCEPTION(!A.getRowMap()->isSameAs(*B.getRowMap()),
Exceptions::Incompatible,
"MueLu::CGSolver::Frobenius: row maps are incompatible");
1658 TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete() || !B.isFillComplete(),
Exceptions::RuntimeError,
"Matrices must be fill completed");
1660 const Map& AColMap = *A.getColMap();
1661 const Map& BColMap = *B.getColMap();
1663 Teuchos::ArrayView<const LocalOrdinal> indA, indB;
1664 Teuchos::ArrayView<const Scalar> valA, valB;
1665 size_t nnzA = 0, nnzB = 0;
1677 Teuchos::Array<Scalar> valBAll(BColMap.getLocalNumElements());
1679 LocalOrdinal invalid = Teuchos::OrdinalTraits<LocalOrdinal>::invalid();
1680 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero(), f = zero, gf;
1681 size_t numRows = A.getLocalNumRows();
1682 for (
size_t i = 0; i < numRows; i++) {
1683 A.getLocalRowView(i, indA, valA);
1684 B.getLocalRowView(i, indB, valB);
1689 for (
size_t j = 0; j < nnzB; j++)
1690 valBAll[indB[j]] = valB[j];
1692 for (
size_t j = 0; j < nnzA; j++) {
1695 LocalOrdinal ind = BColMap.getLocalElement(AColMap.getGlobalElement(indA[j]));
1697 f += valBAll[ind] * valA[j];
1701 for (
size_t j = 0; j < nnzB; j++)
1702 valBAll[indB[j]] = zero;
1710template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1718 int maxint = INT_MAX;
1719 int mySeed = Teuchos::as<int>((maxint - 1) * (one - (comm.getRank() + 1) / (comm.getSize() + one)));
1720 if (mySeed < 1 || mySeed == maxint) {
1721 std::ostringstream errStr;
1722 errStr <<
"Error detected with random seed = " << mySeed <<
". It should be in the interval [1,2^31-2].";
1727 Teuchos::ScalarTraits<Scalar>::seedrandom(mySeed);
1730template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1732 FindDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1733 std::vector<LocalOrdinal>& dirichletRows,
bool count_twos_as_dirichlet) {
1734 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1735 dirichletRows.resize(0);
1736 for (
size_t i = 0; i < A->getLocalNumRows(); i++) {
1737 Teuchos::ArrayView<const LocalOrdinal> indices;
1738 Teuchos::ArrayView<const Scalar> values;
1739 A->getLocalRowView(i, indices, values);
1741 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1742 if (Teuchos::ScalarTraits<Scalar>::magnitude(values[j]) > Teuchos::ScalarTraits<MT>::eps()) {
1746 if (nnz == 1 || (count_twos_as_dirichlet && nnz == 2)) {
1747 dirichletRows.push_back(i);
1752template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1754 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1755 const std::vector<LocalOrdinal>& dirichletRows) {
1756 RCP<const Map> Rmap = A->getRowMap();
1757 RCP<const Map> Cmap = A->getColMap();
1758 Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1759 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1761 for (
size_t i = 0; i < dirichletRows.size(); i++) {
1762 GlobalOrdinal row_gid = Rmap->getGlobalElement(dirichletRows[i]);
1764 Teuchos::ArrayView<const LocalOrdinal> indices;
1765 Teuchos::ArrayView<const Scalar> values;
1766 A->getLocalRowView(dirichletRows[i], indices, values);
1768 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1769 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1770 if (Cmap->getGlobalElement(indices[j]) == row_gid)
1778template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1780 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1781 const Teuchos::ArrayRCP<const bool>& dirichletRows) {
1782 TEUCHOS_ASSERT(A->isFillComplete());
1783 RCP<const Map> domMap = A->getDomainMap();
1784 RCP<const Map> ranMap = A->getRangeMap();
1785 RCP<const Map> Rmap = A->getRowMap();
1786 RCP<const Map> Cmap = A->getColMap();
1787 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == Rmap->getLocalNumElements());
1788 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1789 const Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1791 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1792 if (dirichletRows[i]) {
1795 Teuchos::ArrayView<const LocalOrdinal> indices;
1796 Teuchos::ArrayView<const Scalar> values;
1797 A->getLocalRowView(i, indices, values);
1799 Teuchos::ArrayRCP<Scalar> valuesNC(values.size());
1800 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1801 if (Cmap->getGlobalElement(indices[j]) == row_gid)
1806 A->replaceLocalValues(i, indices, valuesNC());
1809 A->fillComplete(domMap, ranMap);
1812template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1814 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1815 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows) {
1816 TEUCHOS_ASSERT(A->isFillComplete());
1817 using ATS = KokkosKernels::ArithTraits<Scalar>;
1818 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1819 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1821 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A->getDomainMap();
1822 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> ranMap = A->getRangeMap();
1823 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> Rmap = A->getRowMap();
1824 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> Cmap = A->getColMap();
1826 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == Rmap->getLocalNumElements());
1828 auto localMatrix = A->getLocalMatrixDevice();
1829 auto localRmap = Rmap->getLocalMap();
1830 auto localCmap = Cmap->getLocalMap();
1832 Kokkos::parallel_for(
1833 "MueLu::Utils::ApplyOAZ", range_type(0, dirichletRows.extent(0)),
1835 if (dirichletRows(row)) {
1836 auto rowView = localMatrix.row(row);
1837 auto length = rowView.length;
1838 auto row_gid = localRmap.getGlobalElement(row);
1839 auto row_lid = localCmap.getLocalElement(row_gid);
1841 for (
decltype(length) colID = 0; colID < length; colID++)
1842 if (rowView.colidx(colID) == row_lid)
1843 rowView.value(colID) = impl_ATS::one();
1845 rowView.value(colID) = impl_ATS::zero();
1850template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1852 ZeroDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1853 const std::vector<LocalOrdinal>& dirichletRows,
1855 for (
size_t i = 0; i < dirichletRows.size(); i++) {
1856 Teuchos::ArrayView<const LocalOrdinal> indices;
1857 Teuchos::ArrayView<const Scalar> values;
1858 A->getLocalRowView(dirichletRows[i], indices, values);
1860 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1861 for (
size_t j = 0; j < (size_t)indices.size(); j++)
1862 valuesNC[j] = replaceWith;
1866template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1868 ZeroDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1869 const Teuchos::ArrayRCP<const bool>& dirichletRows,
1871 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == A->getRowMap()->getLocalNumElements());
1872 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1873 if (dirichletRows[i]) {
1874 Teuchos::ArrayView<const LocalOrdinal> indices;
1875 Teuchos::ArrayView<const Scalar> values;
1876 A->getLocalRowView(i, indices, values);
1878 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1879 for (
size_t j = 0; j < (size_t)indices.size(); j++)
1880 valuesNC[j] = replaceWith;
1885template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1887 ZeroDirichletRows(Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& X,
1888 const Teuchos::ArrayRCP<const bool>& dirichletRows,
1890 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == X->getMap()->getLocalNumElements());
1891 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1892 if (dirichletRows[i]) {
1893 for (
size_t j = 0; j < X->getNumVectors(); j++)
1894 X->replaceLocalValue(i, j, replaceWith);
1899template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1901 ZeroDirichletRows(RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1902 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows,
1904 using ATS = KokkosKernels::ArithTraits<Scalar>;
1905 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1907 typename ATS::val_type impl_replaceWith = replaceWith;
1909 auto localMatrix = A->getLocalMatrixDevice();
1912 Kokkos::parallel_for(
1913 "MueLu:Utils::ZeroDirichletRows", range_type(0, numRows),
1915 if (dirichletRows(row)) {
1916 auto rowView = localMatrix.row(row);
1917 auto length = rowView.length;
1918 for (
decltype(length) colID = 0; colID < length; colID++)
1919 rowView.value(colID) = impl_replaceWith;
1924template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1925void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1926 ZeroDirichletRows(RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& X,
1927 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows,
1929 using ATS = KokkosKernels::ArithTraits<Scalar>;
1930 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1932 typename ATS::val_type impl_replaceWith = replaceWith;
1934 auto myCols = X->getLocalViewDevice(Tpetra::Access::ReadWrite);
1935 size_t numVecs = X->getNumVectors();
1936 Kokkos::parallel_for(
1937 "MueLu:Utils::ZeroDirichletRows_MV", range_type(0, dirichletRows.size()),
1938 KOKKOS_LAMBDA(
const size_t i) {
1939 if (dirichletRows(i)) {
1940 for (
size_t j = 0; j < numVecs; j++)
1941 myCols(i, j) = impl_replaceWith;
1946template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1949 const Teuchos::ArrayRCP<const bool>& dirichletCols,
1951 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletCols.size()) == A->getColMap()->getLocalNumElements());
1952 for (
size_t i = 0; i < A->getLocalNumRows(); i++) {
1953 Teuchos::ArrayView<const LocalOrdinal> indices;
1954 Teuchos::ArrayView<const Scalar> values;
1955 A->getLocalRowView(i, indices, values);
1957 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1958 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
1959 if (dirichletCols[indices[j]])
1960 valuesNC[j] = replaceWith;
1964template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1966 ZeroDirichletCols(RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1967 const Kokkos::View<const bool*, typename Node::device_type>& dirichletCols,
1969 using ATS = KokkosKernels::ArithTraits<Scalar>;
1970 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1972 typename ATS::val_type impl_replaceWith = replaceWith;
1974 auto localMatrix = A->getLocalMatrixDevice();
1977 Kokkos::parallel_for(
1978 "MueLu:Utils::ZeroDirichletCols", range_type(0, numRows),
1980 auto rowView = localMatrix.row(row);
1981 auto length = rowView.length;
1982 for (
decltype(length) colID = 0; colID < length; colID++)
1983 if (dirichletCols(rowView.colidx(colID))) {
1984 rowView.value(colID) = impl_replaceWith;
1989template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1992 Teuchos::RCP<Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node>>& isDirichletRow,
1993 Teuchos::RCP<Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node>>& isDirichletCol) {
1995 if (!A->getRowMap()->isSameAs(*A->getDomainMap())) {
1996 throw std::runtime_error(
"UtilitiesBase::FindDirichletRowsAndPropagateToCols row and domain maps must match.");
1998 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A->getCrsGraph()->getImporter();
1999 bool has_import = !importer.is_null();
2002 std::vector<LocalOrdinal> dirichletRows;
2003 FindDirichletRows(A, dirichletRows);
2006 printf(
"[%d] DirichletRow Ids = ",A->getRowMap()->getComm()->getRank());
2007 for(
size_t i=0; i<(size_t) dirichletRows.size(); i++)
2008 printf(
"%d ",dirichletRows[i]);
2013 isDirichletRow = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(A->getRowMap(),
true);
2014 isDirichletCol = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(A->getColMap(),
true);
2017 Teuchos::ArrayRCP<int> dr_rcp =
isDirichletRow->getDataNonConst(0);
2018 Teuchos::ArrayView<int> dr = dr_rcp();
2019 Teuchos::ArrayRCP<int> dc_rcp = isDirichletCol->getDataNonConst(0);
2020 Teuchos::ArrayView<int> dc = dc_rcp();
2021 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
2022 dr[dirichletRows[i]] = 1;
2023 if (!has_import) dc[dirichletRows[i]] = 1;
2028 isDirichletCol->doImport(*
isDirichletRow, *importer, Xpetra::CombineMode::ADD);
2031template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2032RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
2035 using ISC =
typename KokkosKernels::ArithTraits<Scalar>::val_type;
2036 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
2037 using local_matrix_type =
typename CrsMatrix::local_matrix_device_type;
2038 using values_type =
typename local_matrix_type::values_type;
2040 const ISC ONE = KokkosKernels::ArithTraits<ISC>::one();
2041 const ISC ZERO = KokkosKernels::ArithTraits<ISC>::zero();
2044 auto localMatrix = original->getLocalMatrixDevice();
2045 TEUCHOS_TEST_FOR_EXCEPTION(!original->hasCrsGraph(),
Exceptions::RuntimeError,
"ReplaceNonZerosWithOnes: Cannot get CrsGraph");
2046 values_type new_values(
"values", localMatrix.nnz());
2048 Kokkos::parallel_for(
2049 "ReplaceNonZerosWithOnes", range_type(0, localMatrix.nnz()), KOKKOS_LAMBDA(
const size_t i) {
2050 if (localMatrix.values(i) != ZERO)
2051 new_values(i) = ONE;
2053 new_values(i) = ZERO;
2057 RCP<Matrix> NewMatrix = Xpetra::MatrixFactory<SC, LO, GO, NO>::Build(original->getCrsGraph(), new_values);
2058 TEUCHOS_TEST_FOR_EXCEPTION(NewMatrix.is_null(),
Exceptions::RuntimeError,
"ReplaceNonZerosWithOnes: MatrixFactory::Build() did not return matrix");
2059 NewMatrix->fillComplete(original->getDomainMap(), original->getRangeMap());
2063template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2064RCP<const Xpetra::BlockedMap<LocalOrdinal, GlobalOrdinal, Node>>
2067 const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>& Importer) {
2068 typedef Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node> IntVector;
2069 Xpetra::UnderlyingLib lib = sourceBlockedMap.lib();
2072 RCP<const Map> fullMap = sourceBlockedMap.getMap();
2073 RCP<const Map> stridedMap = Teuchos::rcp_dynamic_cast<const Xpetra::StridedMap<LocalOrdinal, GlobalOrdinal, Node>>(fullMap);
2074 if (!stridedMap.is_null()) fullMap = stridedMap->getMap();
2077 const size_t numSubMaps = sourceBlockedMap.getNumMaps();
2078 if (!Importer.getSourceMap()->isCompatible(*fullMap))
2079 throw std::runtime_error(
"GenerateBlockedTargetMap(): Map compatibility error");
2082 RCP<IntVector> block_ids = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(fullMap);
2084 for (
size_t i = 0; i < numSubMaps; i++) {
2085 RCP<const Map> map = sourceBlockedMap.getMap(i);
2087 for (
size_t j = 0; j < map->getLocalNumElements(); j++) {
2088 LocalOrdinal jj = fullMap->getLocalElement(map->getGlobalElement(j));
2089 block_ids->replaceLocalValue(jj, (
int)i);
2094 RCP<const Map> targetMap = Importer.getTargetMap();
2095 RCP<IntVector> new_block_ids = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(targetMap);
2096 new_block_ids->doImport(*block_ids, Importer, Xpetra::CombineMode::ADD);
2097 Teuchos::ArrayRCP<const int> dataRCP = new_block_ids->getData(0);
2098 Teuchos::ArrayView<const int> data = dataRCP();
2101 Teuchos::Array<Teuchos::Array<GlobalOrdinal>> elementsInSubMap(numSubMaps);
2102 for (
size_t i = 0; i < targetMap->getLocalNumElements(); i++) {
2103 elementsInSubMap[data[i]].push_back(targetMap->getGlobalElement(i));
2107 std::vector<RCP<const Map>> subMaps(numSubMaps);
2108 for (
size_t i = 0; i < numSubMaps; i++) {
2109 subMaps[i] = Xpetra::MapFactory<LocalOrdinal, GlobalOrdinal, Node>::Build(lib, Teuchos::OrdinalTraits<GlobalOrdinal>::invalid(), elementsInSubMap[i](), targetMap->getIndexBase(), targetMap->getComm());
2113 return rcp(
new BlockedMap(targetMap, subMaps));
2116template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2118 MapsAreNested(
const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& rowMap,
const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& colMap) {
2119 if ((rowMap.lib() == Xpetra::UseTpetra) && (colMap.lib() == Xpetra::UseTpetra)) {
2120 auto tpRowMap = toTpetra(rowMap);
2121 auto tpColMap = toTpetra(colMap);
2122 return tpColMap.isLocallyFitted(tpRowMap);
2125 ArrayView<const GlobalOrdinal> rowElements = rowMap.getLocalElementList();
2126 ArrayView<const GlobalOrdinal> colElements = colMap.getLocalElementList();
2128 const size_t numElements = rowElements.size();
2130 if (
size_t(colElements.size()) < numElements)
2133 bool goodMap =
true;
2134 for (
size_t i = 0; i < numElements; i++)
2135 if (rowElements[i] != colElements[i]) {
2143template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2144Teuchos::RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>>
2146 ReverseCuthillMcKee(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op) {
2147 using local_matrix_type =
typename Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::local_matrix_device_type;
2148 using local_graph_type =
typename local_matrix_type::staticcrsgraph_type;
2149 using lno_nnz_view_t =
typename local_graph_type::entries_type::non_const_type;
2150 using device =
typename local_graph_type::device_type;
2151 using execution_space =
typename local_matrix_type::execution_space;
2152 using ordinal_type =
typename local_matrix_type::ordinal_type;
2154 local_graph_type localGraph = Op.getLocalMatrixDevice().graph;
2156 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);
2158 RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>> retval =
2159 Xpetra::VectorFactory<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(Op.getRowMap());
2162 auto view1D = Kokkos::subview(retval->getLocalViewDevice(Tpetra::Access::ReadWrite), Kokkos::ALL(), 0);
2163 Kokkos::parallel_for(
2164 "Utilities::ReverseCuthillMcKee",
2165 Kokkos::RangePolicy<ordinal_type, execution_space>(0, localGraph.numRows()),
2166 KOKKOS_LAMBDA(
const ordinal_type rowIdx) {
2167 view1D(rcmOrder(rowIdx)) = rowIdx;
2172template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2173Teuchos::RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>>
2175 CuthillMcKee(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op) {
2176 using local_matrix_type =
typename Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::local_matrix_device_type;
2177 using local_graph_type =
typename local_matrix_type::staticcrsgraph_type;
2178 using lno_nnz_view_t =
typename local_graph_type::entries_type::non_const_type;
2179 using device =
typename local_graph_type::device_type;
2180 using execution_space =
typename local_matrix_type::execution_space;
2181 using ordinal_type =
typename local_matrix_type::ordinal_type;
2183 local_graph_type localGraph = Op.getLocalMatrixDevice().graph;
2186 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);
2188 RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>> retval =
2189 Xpetra::VectorFactory<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(Op.getRowMap());
2192 auto view1D = Kokkos::subview(retval->getLocalViewDevice(Tpetra::Access::ReadWrite), Kokkos::ALL(), 0);
2194 Kokkos::parallel_for(
2195 "Utilities::ReverseCuthillMcKee",
2196 Kokkos::RangePolicy<ordinal_type, execution_space>(0, numRows),
2197 KOKKOS_LAMBDA(
const ordinal_type rowIdx) {
2198 view1D(rcmOrder(numRows - 1 - rowIdx)) = rowIdx;
2203template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2205 TripleMatrixProduct(
const Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& R,
2206 const Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
2207 const Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& P,
2208 Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& Ac,
2209 const Teuchos::ParameterList& pL,
2211 Teuchos::RCP<Teuchos::ParameterList>& APparams,
2212 Teuchos::RCP<Teuchos::ParameterList>& RAPparams,
2213 Level* coarseLevel) {
2214 using Matrix = Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
2215 using MatrixMatrix = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
2216 using MatrixFactory = Xpetra::MatrixFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
2219 const bool doTranspose =
true;
2220 const bool doFillComplete =
true;
2221 const bool doOptimizeStorage =
true;
2223 const bool useImplicit = pL.get<
bool>(
"transpose: use implicit");
2225 const std::string matrixName = (pL.isType<std::string>(
"Matrix name")) ? pL.get<std::string>(
"Matrix name") :
"A";
2226 const std::string prolongatorName = (pL.isType<std::string>(
"Prolongator name")) ? pL.get<std::string>(
"Prolongator name") :
"P";
2227 const std::string restrictorName = (pL.isType<std::string>(
"Restrictor name")) ? pL.get<std::string>(
"Restrictor name") :
"R";
2228 std::string coarseMatrixName;
2229 if (pL.isType<std::string>(
"coarseMatrixName"))
2230 coarseMatrixName = pL.get<std::string>(
"coarseMatrixName");
2232 if (matrixName.size() == 1)
2233 coarseMatrixName = matrixName +
"c";
2235 coarseMatrixName = matrixName +
"_coarse";
2238 std::string levelstr, labelstr;
2239 if (coarseLevel !=
nullptr) {
2240 std::ostringstream levelss;
2242 levelstr = levelss.str();
2243 labelstr = FormattingHelper::getColonLabel(coarseLevel->getObjectLabel());
2246 bool isGPU = Node::is_gpu;
2249 if (RAPparams.is_null())
2250 RAPparams = rcp(
new ParameterList);
2251 if (pL.isSublist(
"matrixmatrix: kernel params"))
2252 RAPparams->setParameters(pL.sublist(
"matrixmatrix: kernel params"));
2254 if (RAPparams->isParameter(
"graph")) {
2255 Ac = RAPparams->get<RCP<Matrix>>(
"graph");
2259 Ac->SetMaxEigenvalueEstimate(-Teuchos::ScalarTraits<Scalar>::one());
2263 RAPparams->set(
"compute global constants: temporaries", RAPparams->get(
"compute global constants: temporaries",
false));
2264 RAPparams->set(
"compute global constants",
true);
2266 if (pL.get<
bool>(
"rap: triple product") ==
false || isGPU) {
2267 if (pL.get<
bool>(
"rap: triple product") && isGPU)
2268 verbObj.
GetOStream(
Warnings1) <<
"Switching from triple product to R x (A x P) since triple product has not been implemented for "
2269 << Node::execution_space::name() << std::endl;
2274 if (APparams.is_null())
2275 APparams = rcp(
new ParameterList);
2276 if (pL.isSublist(
"matrixmatrix: kernel params"))
2277 APparams = rcp(
new ParameterList(pL.sublist(
"matrixmatrix: kernel params")));
2280 APparams->set(
"compute global constants: temporaries", APparams->get(
"compute global constants: temporaries",
false));
2281 APparams->set(
"compute global constants", APparams->get(
"compute global constants",
false));
2283 if (APparams->isParameter(
"graph"))
2284 AP = APparams->get<RCP<Matrix>>(
"graph");
2286 std::string monitorstrAP =
"MxM: " + matrixName +
" x " + prolongatorName;
2287 std::string timerstrAP =
"MueLu::" + matrixName +
"*" + prolongatorName;
2288 if (!labelstr.empty())
2289 timerstrAP = labelstr + timerstrAP;
2290 if (!levelstr.empty())
2291 timerstrAP = timerstrAP +
"-" + levelstr;
2296 AP = MatrixMatrix::Multiply(*A, !doTranspose, *P, !doTranspose, AP, verbObj.
GetOStream(
Statistics2),
2297 doFillComplete, doOptimizeStorage, timerstrAP, APparams);
2304 std::string timerstrRAP, monitorstrRAP;
2306 monitorstrRAP =
"MxM: " + prolongatorName +
"' x (" + matrixName + prolongatorName +
") (implicit)";
2307 timerstrRAP =
"MueLu::" + restrictorName +
"*(" + matrixName +
"*" + prolongatorName +
")-implicit";
2309 monitorstrRAP =
"MxM: " + restrictorName +
" x (" + matrixName + prolongatorName +
") (explicit)";
2310 timerstrRAP =
"MueLu::" + restrictorName +
"*(" + matrixName +
"*" + prolongatorName +
")-explicit";
2312 if (!labelstr.empty())
2313 timerstrRAP = labelstr + timerstrRAP;
2314 if (!levelstr.empty())
2315 timerstrRAP = timerstrRAP +
"-" + levelstr;
2320 Ac = MatrixMatrix::Multiply(*P, doTranspose, *AP, !doTranspose, Ac, verbObj.
GetOStream(
Statistics2),
2321 doFillComplete, doOptimizeStorage, timerstrRAP, RAPparams);
2326 Ac = MatrixMatrix::Multiply(*R, !doTranspose, *AP, !doTranspose, Ac, verbObj.
GetOStream(
Statistics2),
2327 doFillComplete, doOptimizeStorage, timerstrRAP, RAPparams);
2331 APparams->set(
"graph", AP);
2335 std::string monitorstrRAP;
2336 std::string timerstrRAP;
2338 monitorstrRAP =
"MxMxM: " + restrictorName +
" x " + matrixName +
" x " + prolongatorName +
" (implicit)";
2339 timerstrRAP =
"MueLu::" + restrictorName +
"*" + matrixName +
"*" + prolongatorName +
"-implicit";
2341 monitorstrRAP =
"MxMxM: " + restrictorName +
" x " + matrixName +
" x " + prolongatorName +
" (explicit)";
2342 timerstrRAP =
"MueLu::" + restrictorName +
"*" + matrixName +
"*" + prolongatorName +
"-explicit";
2344 if (!labelstr.empty())
2345 timerstrRAP = labelstr + timerstrRAP;
2346 if (!levelstr.empty())
2347 timerstrRAP = timerstrRAP +
"-" + levelstr;
2350 Ac = MatrixFactory::Build(P->getDomainMap(), Teuchos::as<LocalOrdinal>(0));
2354 Xpetra::TripleMatrixMultiply<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
2355 MultiplyRAP(*P, doTranspose, *A, !doTranspose, *P, !doTranspose, *Ac, doFillComplete,
2356 doOptimizeStorage, timerstrRAP,
2359 Ac = MatrixFactory::Build(R->getRowMap(), Teuchos::as<LocalOrdinal>(0));
2363 Xpetra::TripleMatrixMultiply<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
2364 MultiplyRAP(*R, !doTranspose, *A, !doTranspose, *P, !doTranspose, *Ac, doFillComplete,
2365 doOptimizeStorage, timerstrRAP,
2370 Teuchos::ArrayView<const double> relativeFloor = pL.get<Teuchos::Array<double>>(
"rap: relative diagonal floor")();
2371 if (relativeFloor.size() > 0) {
2372 Xpetra::MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::RelativeDiagonalBoost(Ac, relativeFloor, verbObj.
GetOStream(
Statistics2));
2375 bool repairZeroDiagonals = pL.get<
bool>(
"RepairMainDiagonal") || pL.get<
bool>(
"rap: fix zero diagonals");
2376 bool checkAc = pL.get<
bool>(
"CheckMainDiagonal") || pL.get<
bool>(
"rap: fix zero diagonals");
2378 if (checkAc || repairZeroDiagonals) {
2379 using magnitudeType =
typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
2380 magnitudeType threshold;
2381 if (pL.isType<magnitudeType>(
"rap: fix zero diagonals threshold"))
2382 threshold = pL.get<magnitudeType>(
"rap: fix zero diagonals threshold");
2384 threshold = Teuchos::as<magnitudeType>(pL.get<
double>(
"rap: fix zero diagonals threshold"));
2385 Scalar replacement = Teuchos::as<Scalar>(pL.get<
double>(
"rap: fix zero diagonals replacement"));
2386 Xpetra::MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::CheckRepairMainDiagonal(Ac, repairZeroDiagonals, verbObj.
GetOStream(
Warnings1), threshold, replacement);
2390 RCP<ParameterList> params = rcp(
new ParameterList());
2391 params->set(
"printLoadBalancingInfo",
true);
2392 params->set(
"printCommInfo",
true);
2397 RAPparams->set(
"graph", Ac);
2400 if (Behavior::debug())
2401 MatrixUtils::checkLocalRowMapMatchesColMap(*Ac);