490 Kokkos::View<int*, execution_space> nnzPerRow(
"nnz per rows", diag_dev.extent(0));
491 Kokkos::View<scalar_type*, execution_space> regSum(
"regSum", diag_dev.extent(0));
492 Kokkos::View<mag_type, execution_space> avgAbsDiagVal_dev(
"avgAbsDiagVal");
493 Kokkos::View<int, execution_space> numDiagsEqualToOne_dev(
"numDiagsEqualToOne");
496 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"GetLumpedMatrixDiagonal: parallel_for (doReciprocal)");
497 Kokkos::parallel_for(
498 "GetLumpedMatrixDiagonal", my_policy,
499 KOKKOS_LAMBDA(
const int rowIdx) {
500 diag_dev(rowIdx, 0) = KAT_S::zero();
501 for (size_type entryIdx = local_mat_dev.graph.row_map(rowIdx);
502 entryIdx < local_mat_dev.graph.row_map(rowIdx + 1);
504 regSum(rowIdx) += local_mat_dev.values(entryIdx);
505 if (KAT_M::zero() < KAT_S::abs(local_mat_dev.values(entryIdx))) {
508 diag_dev(rowIdx, 0) += KAT_S::abs(local_mat_dev.values(entryIdx));
509 if (rowIdx == local_mat_dev.graph.entries(entryIdx)) {
510 Kokkos::atomic_add(&avgAbsDiagVal_dev(), KAT_S::abs(local_mat_dev.values(entryIdx)));
514 if (nnzPerRow(rowIdx) == 1 && KAT_S::magnitude(diag_dev(rowIdx, 0)) == KAT_M::one()) {
515 Kokkos::atomic_add(&numDiagsEqualToOne_dev(), 1);
519 if (useAverageAbsDiagVal) {
520 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"GetLumpedMatrixDiagonal: useAverageAbsDiagVal");
521 typename Kokkos::View<mag_type, execution_space>::host_mirror_type avgAbsDiagVal = Kokkos::create_mirror_view(avgAbsDiagVal_dev);
522 Kokkos::deep_copy(avgAbsDiagVal, avgAbsDiagVal_dev);
523 int numDiagsEqualToOne;
524 Kokkos::deep_copy(numDiagsEqualToOne, numDiagsEqualToOne_dev);
526 tol = TST::magnitude(100 * Teuchos::ScalarTraits<Scalar>::eps()) * (avgAbsDiagVal() - numDiagsEqualToOne) / (rowMap->getLocalNumElements() - numDiagsEqualToOne);
530 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"ComputeLumpedDiagonalInverse: parallel_for (doReciprocal)");
531 Kokkos::parallel_for(
532 "ComputeLumpedDiagonalInverse", my_policy,
533 KOKKOS_LAMBDA(
const int rowIdx) {
534 if (replaceSingleEntryRowWithZero && nnzPerRow(rowIdx) <= 1) {
535 diag_dev(rowIdx, 0) = KAT_S::zero();
536 }
else if ((diag_dev(rowIdx, 0) != KAT_S::zero()) && (KAT_S::magnitude(diag_dev(rowIdx, 0)) < KAT_S::magnitude(2 * regSum(rowIdx)))) {
537 diag_dev(rowIdx, 0) = KAT_S::one() / KAT_S::magnitude(2 * regSum(rowIdx));
539 if (KAT_S::magnitude(diag_dev(rowIdx, 0)) > tol) {
540 diag_dev(rowIdx, 0) = KAT_S::one() / diag_dev(rowIdx, 0);
542 diag_dev(rowIdx, 0) = valReplacement_dev;
549 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"GetLumpedMatrixDiagonal: parallel_for");
550 Kokkos::parallel_for(
551 "GetLumpedMatrixDiagonal", my_policy,
552 KOKKOS_LAMBDA(
const int rowIdx) {
553 diag_dev(rowIdx, 0) = KAT_S::zero();
554 for (size_type entryIdx = local_mat_dev.graph.row_map(rowIdx);
555 entryIdx < local_mat_dev.graph.row_map(rowIdx + 1);
557 diag_dev(rowIdx, 0) += KAT_S::magnitude(local_mat_dev.values(entryIdx));
563 Teuchos::TimeMonitor MMM = *Teuchos::TimeMonitor::getNewTimer(
"UtilitiesBase: GetLumpedMatrixDiagonal: (Teuchos implementation)");
564 ArrayRCP<Scalar> diagVals = diag->getDataNonConst(0);
565 Teuchos::Array<Scalar> regSum(diag->getLocalLength());
566 Teuchos::ArrayView<const LocalOrdinal> cols;
567 Teuchos::ArrayView<const Scalar> vals;
569 std::vector<int> nnzPerRow(rowMap->getLocalNumElements());
574 const Magnitude zeroMagn = TST::magnitude(zero);
575 Magnitude avgAbsDiagVal = TST::magnitude(zero);
576 int numDiagsEqualToOne = 0;
577 for (
size_t i = 0; i < rowMap->getLocalNumElements(); ++i) {
579 rcpA->getLocalRowView(i, cols, vals);
582 regSum[i] += vals[j];
583 const Magnitude rowEntryMagn = TST::magnitude(vals[j]);
584 if (rowEntryMagn > zeroMagn)
586 diagVals[i] += rowEntryMagn;
587 if (
static_cast<size_t>(cols[j]) == i)
588 avgAbsDiagVal += rowEntryMagn;
590 if (nnzPerRow[i] == 1 && TST::magnitude(diagVals[i]) == 1.)
591 numDiagsEqualToOne++;
593 if (useAverageAbsDiagVal)
594 tol = TST::magnitude(100 * Teuchos::ScalarTraits<Scalar>::eps()) * (avgAbsDiagVal - numDiagsEqualToOne) / (rowMap->getLocalNumElements() - numDiagsEqualToOne);
596 for (
size_t i = 0; i < rowMap->getLocalNumElements(); ++i) {
597 if (replaceSingleEntryRowWithZero && nnzPerRow[i] <=
static_cast<int>(1))
599 else if ((diagVals[i] != zero) && (TST::magnitude(diagVals[i]) < TST::magnitude(two * regSum[i])))
600 diagVals[i] = one / TST::magnitude((two * regSum[i]));
602 if (TST::magnitude(diagVals[i]) > tol)
603 diagVals[i] = one / diagVals[i];
605 diagVals[i] = valReplacement;
612 TEUCHOS_TEST_FOR_EXCEPTION(doReciprocal, Xpetra::Exceptions::RuntimeError,
613 "UtilitiesBase::GetLumpedMatrixDiagonal(): extracting reciprocal of diagonal of a blocked matrix is not supported");
614 diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(bA->getRangeMapExtractor()->getFullMap(),
true);
616 for (
size_t row = 0; row < bA->Rows(); ++row) {
617 for (
size_t col = 0; col < bA->Cols(); ++col) {
618 if (!bA->getMatrix(row, col).is_null()) {
620 bool bThyraMode = bA->getRangeMapExtractor()->getThyraMode() && (Teuchos::rcp_dynamic_cast<Xpetra::BlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>(bA->getMatrix(row, col)) == Teuchos::null);
621 RCP<Vector> ddtemp = bA->getRangeMapExtractor()->ExtractVector(diag, row, bThyraMode);
622 RCP<const Vector> dd = GetLumpedMatrixDiagonal(*(bA->getMatrix(row, col)));
623 ddtemp->update(Teuchos::as<Scalar>(1.0), *dd, Teuchos::as<Scalar>(1.0));
624 bA->getRangeMapExtractor()->InsertVector(ddtemp, row, diag, bThyraMode);
633template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
634Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
638 RCP<const Map> rowMap = A.getRowMap();
639 auto diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(rowMap,
false);
642 using local_vector_type =
typename Vector::dual_view_type::t_dev_um;
643 using local_matrix_type =
typename Matrix::local_matrix_device_type;
644 using execution_space =
typename local_vector_type::execution_space;
645 using values_type =
typename local_matrix_type::values_type;
646 using scalar_type =
typename values_type::non_const_value_type;
647 using KAT_S =
typename KokkosKernels::ArithTraits<scalar_type>;
649 auto diag_dev = diag->getLocalViewDevice(Tpetra::Access::OverwriteAll);
650 auto local_mat_dev = A.getLocalMatrixDevice();
651 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(diag_dev.extent(0)));
653 Kokkos::parallel_for(
654 "GetMatrixMaxMinusOffDiagonal", my_policy,
656 auto mymax = KAT_S::zero();
657 auto row = local_mat_dev.rowConst(rowIdx);
658 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
659 if (rowIdx != row.colidx(entryIdx)) {
660 if (KAT_S::real(mymax) < -KAT_S::real(row.value(entryIdx)))
661 mymax = -KAT_S::real(row.value(entryIdx));
664 diag_dev(rowIdx, 0) = mymax;
670template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
671Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
673 GetMatrixMaxMinusOffDiagonal(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber) {
674 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()), std::runtime_error,
"GetMatrixMaxMinusOffDiagonal: BlockNumber must match's A's column map.");
677 RCP<const Map> rowMap = A.getRowMap();
678 auto diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(rowMap,
false);
681 using local_vector_type =
typename Vector::dual_view_type::t_dev_um;
682 using local_matrix_type =
typename Matrix::local_matrix_device_type;
683 using execution_space =
typename local_vector_type::execution_space;
684 using values_type =
typename local_matrix_type::values_type;
685 using scalar_type =
typename values_type::non_const_value_type;
686 using KAT_S =
typename KokkosKernels::ArithTraits<scalar_type>;
688 auto diag_dev = diag->getLocalViewDevice(Tpetra::Access::OverwriteAll);
689 auto local_mat_dev = A.getLocalMatrixDevice();
690 auto local_block_dev = BlockNumber.getLocalViewDevice(Tpetra::Access::ReadOnly);
691 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(diag_dev.extent(0)));
693 Kokkos::parallel_for(
694 "GetMatrixMaxMinusOffDiagonal", my_policy,
696 auto mymax = KAT_S::zero();
697 auto row = local_mat_dev.row(rowIdx);
698 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
699 if ((rowIdx != row.colidx(entryIdx)) && (local_block_dev(rowIdx, 0) == local_block_dev(row.colidx(entryIdx), 0))) {
700 if (KAT_S::real(mymax) < -KAT_S::real(row.value(entryIdx)))
701 mymax = -KAT_S::real(row.value(entryIdx));
704 diag_dev(rowIdx, 0) = mymax;
710template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
711Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
713 GetInverse(Teuchos::RCP<
const Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> v,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tol,
Scalar valReplacement) {
714 RCP<Vector> ret = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(v->getMap(),
true);
717 RCP<const BlockedVector> bv = Teuchos::rcp_dynamic_cast<const BlockedVector>(v);
718 if (bv.is_null() ==
false) {
719 RCP<BlockedVector> bret = Teuchos::rcp_dynamic_cast<BlockedVector>(ret);
720 TEUCHOS_TEST_FOR_EXCEPTION(bret.is_null() ==
true,
MueLu::Exceptions::RuntimeError,
"MueLu::UtilitiesBase::GetInverse: return vector should be of type BlockedVector");
721 RCP<const BlockedMap> bmap = bv->getBlockedMap();
722 for (
size_t r = 0; r < bmap->getNumMaps(); ++r) {
723 RCP<const MultiVector> submvec = bv->getMultiVector(r, bmap->getThyraMode());
724 RCP<const Vector> subvec = submvec->getVector(0);
726 bret->setMultiVector(r, subvecinf, bmap->getThyraMode());
732 ArrayRCP<Scalar> retVals = ret->getDataNonConst(0);
733 ArrayRCP<const Scalar> inputVals = v->getData(0);
734 for (
size_t i = 0; i < v->getMap()->getLocalNumElements(); ++i) {
735 if (Teuchos::ScalarTraits<Scalar>::magnitude(inputVals[i]) > tol)
736 retVals[i] = Teuchos::ScalarTraits<Scalar>::one() / inputVals[i];
738 retVals[i] = valReplacement;
781template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
782RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
785 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
787 RCP<const Import> importer = A.getCrsGraph()->getImporter();
788 if (importer.is_null() && !rowMap->isSameAs(*colMap)) {
789 importer = ImportFactory::Build(rowMap, colMap);
791 if (!importer.is_null()) {
792 RCP<Vector> diagonal = VectorFactory::Build(colMap,
false);
793 diagonal->doImport(*localDiag, *(importer), Xpetra::INSERT);
799template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
800RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
803 using STS =
typename Teuchos::ScalarTraits<SC>;
806 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
807 RCP<const BlockedMap> browMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
808 if (!browMap.is_null()) rowMap = browMap->getMap();
810 RCP<Vector> local = Xpetra::VectorFactory<SC, LO, GO, Node>::Build(rowMap);
811 RCP<Vector> ghosted = Xpetra::VectorFactory<SC, LO, GO, Node>::Build(colMap,
true);
812 ArrayRCP<SC> localVals = local->getDataNonConst(0);
814 for (LO row = 0; row < static_cast<LO>(A.getRowMap()->getLocalNumElements()); ++row) {
815 size_t nnz = A.getNumEntriesInLocalRow(row);
816 ArrayView<const LO> indices;
817 ArrayView<const SC> vals;
818 A.getLocalRowView(row, indices, vals);
822 for (LO colID = 0; colID < static_cast<LO>(nnz); colID++) {
823 if (indices[colID] != row) {
830 RCP<const Xpetra::Import<LO, GO, Node>> importer;
831 importer = A.getCrsGraph()->getImporter();
832 if (importer == Teuchos::null) {
833 importer = Xpetra::ImportFactory<LO, GO, Node>::Build(rowMap, colMap);
835 ghosted->doImport(*local, *(importer), Xpetra::INSERT);
839template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
843 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
844 using STS =
typename Teuchos::ScalarTraits<Scalar>;
845 using MTS =
typename Teuchos::ScalarTraits<Magnitude>;
847 using RealValuedVector = Xpetra::Vector<MT, LO, GO, Node>;
850 RCP<const BlockedMap> browMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
851 if (!browMap.is_null()) rowMap = browMap->getMap();
853 RCP<RealValuedVector> local = Xpetra::VectorFactory<MT, LO, GO, Node>::Build(rowMap);
854 RCP<RealValuedVector> ghosted = Xpetra::VectorFactory<MT, LO, GO, Node>::Build(colMap,
true);
855 ArrayRCP<MT> localVals = local->getDataNonConst(0);
857 for (LO rowIdx = 0; rowIdx < static_cast<LO>(A.getRowMap()->getLocalNumElements()); ++rowIdx) {
858 size_t nnz = A.getNumEntriesInLocalRow(rowIdx);
859 ArrayView<const LO> indices;
860 ArrayView<const SC> vals;
861 A.getLocalRowView(rowIdx, indices, vals);
865 for (LO colID = 0; colID < static_cast<LO>(nnz); ++colID) {
866 if (indices[colID] != rowIdx) {
867 si += STS::magnitude(vals[colID]);
870 localVals[rowIdx] = si;
873 RCP<const Xpetra::Import<LO, GO, Node>> importer;
874 importer = A.getCrsGraph()->getImporter();
875 if (importer == Teuchos::null) {
876 importer = Xpetra::ImportFactory<LO, GO, Node>::Build(rowMap, colMap);
878 ghosted->doImport(*local, *(importer), Xpetra::INSERT);
882template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
886 using local_matrix_type =
typename Matrix::local_matrix_device_type;
887 using execution_space =
typename local_matrix_type::execution_space;
888 using KAT_S =
typename KokkosKernels::ArithTraits<typename local_matrix_type::value_type>;
890 auto local_mat_dev = A.getLocalMatrixDevice();
891 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(local_mat_dev.numRows()));
894 Kokkos::parallel_reduce(
895 "CountNegativeDiagonalEntries", my_policy,
897 auto row = local_mat_dev.row(rowIdx);
898 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
899 if (rowIdx == row.colidx(entryIdx) && KAT_S::real(row.value(entryIdx)) < 0)
905 MueLu_sumAll(A.getRowMap()->getComm(), count_l, count_g);
909template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
910Teuchos::Array<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>
912 ResidualNorm(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS) {
913 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
914 const size_t numVecs = X.getNumVectors();
915 RCP<MultiVector> RES =
Residual(Op, X, RHS);
916 Teuchos::Array<Magnitude> norms(numVecs);
921template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
922Teuchos::Array<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>
924 ResidualNorm(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS, MultiVector& Resid) {
925 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
926 const size_t numVecs = X.getNumVectors();
928 Teuchos::Array<Magnitude> norms(numVecs);
933template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
934RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
936 Residual(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS) {
937 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
938 const size_t numVecs = X.getNumVectors();
940 RCP<MultiVector> RES = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(RHS.getMap(), numVecs,
false);
941 Op.residual(X, RHS, *RES);
945template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
947 Residual(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS, MultiVector& Resid) {
948 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides");
949 TEUCHOS_TEST_FOR_EXCEPTION(Resid.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of residual vectors != number of right-hand sides");
950 Op.residual(X, RHS, Resid);
953template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
957 LocalOrdinal niters,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType diagonalReplacementTolerance,
bool verbose,
unsigned int seed) {
959 "Utils::PowerMethod: operator must have domain and range maps that are equivalent.");
962 RCP<Vector> diagInvVec;
964 diagInvVec = GetMatrixDiagonalInverse(A, diagonalReplacementTolerance);
967 Scalar lambda = PowerMethod(A, diagInvVec, niters, tolerance, verbose, seed);
971template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
974 PowerMethod(
const Matrix& A,
const RCP<Vector>& diagInvVec,
975 LocalOrdinal niters,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance,
bool verbose,
unsigned int seed) {
977 "Utils::PowerMethod: operator must have domain and range maps that are equivalent.");
980 RCP<Vector> q = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getDomainMap(),
true);
981 RCP<Vector> r = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRangeMap(),
true);
982 RCP<Vector> z = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRangeMap(),
false);
987 Teuchos::Array<Magnitude> norms(1);
989 typedef Teuchos::ScalarTraits<Scalar> STS;
991 const Scalar zero = STS::zero(), one = STS::one();
994 Magnitude residual = STS::magnitude(zero);
997 for (
int iter = 0; iter < niters; ++iter) {
999 q->update(one / norms[0], *z, zero);
1001 if (diagInvVec != Teuchos::null)
1002 z->elementWiseMultiply(one, *diagInvVec, *z, zero);
1003 lambda = q->dot(*z);
1005 if (iter % 100 == 0 || iter + 1 == niters) {
1006 r->update(1.0, *z, -lambda, *q, zero);
1008 residual = STS::magnitude(norms[0] / lambda);
1010 std::cout <<
"Iter = " << iter
1011 <<
" Lambda = " << lambda
1012 <<
" Residual of A*q - lambda*q = " << residual
1016 if (residual < tolerance)
1022template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1023RCP<Teuchos::FancyOStream>
1026 RCP<Teuchos::FancyOStream> fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(os));
1030template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1031typename Teuchos::ScalarTraits<Scalar>::magnitudeType
1034 const size_t numVectors = v.size();
1036 Scalar d = Teuchos::ScalarTraits<Scalar>::zero();
1037 for (
size_t j = 0; j < numVectors; j++) {
1038 d += (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>
1044typename Teuchos::ScalarTraits<Scalar>::magnitudeType
1047 const size_t numVectors = v.size();
1048 using MT =
typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
1050 Scalar d = Teuchos::ScalarTraits<Scalar>::zero();
1051 for (
size_t j = 0; j < numVectors; j++) {
1052 d += Teuchos::as<MT>(weight[j]) * (v[j][i0] - v[j][i1]) * (v[j][i0] - v[j][i1]);
1054 return Teuchos::ScalarTraits<Scalar>::magnitude(d);
1057template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1058Teuchos::ArrayRCP<const bool>
1060 DetectDirichletRows(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType& tol,
bool count_twos_as_dirichlet) {
1062 typedef Teuchos::ScalarTraits<Scalar> STS;
1063 ArrayRCP<bool> boundaryNodes(numRows,
true);
1064 if (count_twos_as_dirichlet) {
1066 ArrayView<const LocalOrdinal> indices;
1067 ArrayView<const Scalar> vals;
1068 A.getLocalRowView(row, indices, vals);
1069 size_t nnz = A.getNumEntriesInLocalRow(row);
1072 for (col = 0; col < nnz; col++)
1073 if ((indices[col] != row) && STS::magnitude(vals[col]) > tol) {
1074 if (!boundaryNodes[row])
1076 boundaryNodes[row] =
false;
1079 boundaryNodes[row] =
true;
1084 ArrayView<const LocalOrdinal> indices;
1085 ArrayView<const Scalar> vals;
1086 A.getLocalRowView(row, indices, vals);
1087 size_t nnz = A.getNumEntriesInLocalRow(row);
1089 for (
size_t col = 0; col < nnz; col++)
1090 if ((indices[col] != row) && STS::magnitude(vals[col]) > tol) {
1091 boundaryNodes[row] =
false;
1096 return boundaryNodes;
1099template <
class CrsMatrix>
1100KOKKOS_FORCEINLINE_FUNCTION
bool isDirichletRow(
typename CrsMatrix::ordinal_type rowId,
1101 KokkosSparse::SparseRowViewConst<CrsMatrix>& row,
1102 const typename KokkosKernels::ArithTraits<typename CrsMatrix::value_type>::magnitudeType& tol,
1103 const bool count_twos_as_dirichlet) {
1104 using ATS = KokkosKernels::ArithTraits<typename CrsMatrix::value_type>;
1106 auto length = row.length;
1107 bool boundaryNode =
true;
1109 if (count_twos_as_dirichlet) {
1111 decltype(length) colID = 0;
1112 for (; colID < length; colID++)
1113 if ((row.colidx(colID) != rowId) &&
1114 (ATS::magnitude(row.value(colID)) > tol)) {
1117 boundaryNode =
false;
1119 if (colID == length)
1120 boundaryNode =
true;
1123 for (
decltype(length) colID = 0; colID < length; colID++)
1124 if ((row.colidx(colID) != rowId) &&
1125 (ATS::magnitude(row.value(colID)) > tol)) {
1126 boundaryNode =
false;
1130 return boundaryNode;
1133template <
class SC,
class LO,
class GO,
class NO,
class memory_space>
1134Kokkos::View<bool*, memory_space>
1136 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1137 const bool count_twos_as_dirichlet) {
1138 using impl_scalar_type =
typename KokkosKernels::ArithTraits<SC>::val_type;
1139 using ATS = KokkosKernels::ArithTraits<impl_scalar_type>;
1140 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
1141 using helpers = Xpetra::Helpers<SC, LO, GO, NO>;
1143 Kokkos::View<bool*, typename NO::device_type::memory_space> boundaryNodes;
1145 if (helpers::isTpetraBlockCrs(A)) {
1146 const Tpetra::BlockCrsMatrix<SC, LO, GO, NO>& Am = toTpetraBlock(A);
1147 auto b_graph = Am.getCrsGraph().getLocalGraphDevice();
1148 auto b_rowptr = Am.getCrsGraph().getLocalRowPtrsDevice();
1149 auto values = Am.getValuesDevice();
1150 LO numBlockRows = Am.getLocalNumRows();
1151 const LO stride = Am.getBlockSize() * Am.getBlockSize();
1153 boundaryNodes = Kokkos::View<bool*, typename NO::device_type::memory_space>(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), numBlockRows);
1155 if (count_twos_as_dirichlet)
1158 Kokkos::parallel_for(
1159 "MueLu:Utils::DetectDirichletRowsBlockCrs", range_type(0, numBlockRows),
1160 KOKKOS_LAMBDA(
const LO row) {
1161 auto rowView = b_graph.rowConst(row);
1162 auto length = rowView.length;
1163 LO valstart = b_rowptr[row] * stride;
1165 boundaryNodes(row) =
true;
1166 decltype(length) colID = 0;
1167 for (; colID < length; colID++) {
1168 if (rowView.colidx(colID) != row) {
1169 LO current = valstart + colID * stride;
1170 for (LO k = 0; k < stride; k++) {
1171 if (ATS::magnitude(values[current + k]) > tol) {
1172 boundaryNodes(row) =
false;
1177 if (boundaryNodes(row) ==
false)
1182 auto localMatrix = A.getLocalMatrixDevice();
1183 LO numRows = A.getLocalNumRows();
1184 boundaryNodes = Kokkos::View<bool*, typename NO::device_type::memory_space>(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), numRows);
1186 Kokkos::parallel_for(
1187 "MueLu:Utils::DetectDirichletRows", range_type(0, numRows),
1188 KOKKOS_LAMBDA(
const LO row) {
1189 auto rowView = localMatrix.rowConst(row);
1190 boundaryNodes(row) =
isDirichletRow(row, rowView, tol, count_twos_as_dirichlet);
1193 if constexpr (std::is_same<memory_space, typename NO::device_type::memory_space>::value)
1194 return boundaryNodes;
1196 Kokkos::View<bool*, memory_space> boundaryNodes2(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), boundaryNodes.extent(0));
1197 Kokkos::deep_copy(boundaryNodes2, boundaryNodes);
1198 return boundaryNodes2;
1201 Kokkos::View<bool*, memory_space> dummy(
"dummy", 0);
1205template <
class SC,
class LO,
class GO,
class NO>
1206Kokkos::View<bool*, typename NO::device_type::memory_space>
1209 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1210 const bool count_twos_as_dirichlet) {
1214template <
class SC,
class LO,
class GO,
class NO>
1215Kokkos::View<bool*, typename Kokkos::HostSpace>
1218 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1219 const bool count_twos_as_dirichlet) {
1223template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1224Teuchos::ArrayRCP<const bool>
1226 DetectDirichletRowsExt(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
bool& bHasZeroDiagonal,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType& tol) {
1228 bHasZeroDiagonal =
false;
1230 Teuchos::RCP<Vector> diagVec = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRowMap());
1231 A.getLocalDiagCopy(*diagVec);
1232 Teuchos::ArrayRCP<const Scalar> diagVecData = diagVec->getData(0);
1235 typedef Teuchos::ScalarTraits<Scalar> STS;
1236 ArrayRCP<bool> boundaryNodes(numRows,
false);
1238 ArrayView<const LocalOrdinal> indices;
1239 ArrayView<const Scalar> vals;
1240 A.getLocalRowView(row, indices, vals);
1242 bool bHasDiag =
false;
1243 for (
decltype(indices.size()) col = 0; col < indices.size(); col++) {
1244 if (indices[col] != row) {
1245 if (STS::magnitude(vals[col] / STS::magnitude(sqrt(STS::magnitude(diagVecData[row]) * STS::magnitude(diagVecData[col])))) > tol) {
1251 if (bHasDiag ==
false)
1252 bHasZeroDiagonal =
true;
1254 boundaryNodes[row] =
true;
1256 return boundaryNodes;
1259template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1262 const Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>& RHS,
1263 Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>& InitialGuess,
1264 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1265 const bool count_twos_as_dirichlet) {
1266 using range_type = Kokkos::RangePolicy<LO, typename Node::execution_space>;
1270 TEUCHOS_ASSERT_EQUALITY(numVectors, Teuchos::as<LocalOrdinal>(InitialGuess.getNumVectors()));
1272 TEUCHOS_ASSERT(RHS.getMap()->isCompatible(*InitialGuess.getMap()));
1274 auto lclRHS = RHS.getLocalViewDevice(Tpetra::Access::ReadOnly);
1275 auto lclInitialGuess = InitialGuess.getLocalViewDevice(Tpetra::Access::ReadWrite);
1276 auto lclA = A.getLocalMatrixDevice();
1278 Kokkos::parallel_for(
1279 "MueLu:Utils::EnforceInitialCondition", range_type(0, numRows),
1280 KOKKOS_LAMBDA(
const LO i) {
1281 auto row = lclA.rowConst(i);
1284 lclInitialGuess(i, j) = lclRHS(i, j);
1289template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1291 FindNonZeros(
const Teuchos::ArrayRCP<const Scalar> vals,
1292 Teuchos::ArrayRCP<bool> nonzeros) {
1293 TEUCHOS_ASSERT(vals.size() == nonzeros.size());
1294 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType magnitudeType;
1295 const magnitudeType eps = 2.0 * Teuchos::ScalarTraits<magnitudeType>::eps();
1296 for (
size_t i = 0; i < static_cast<size_t>(vals.size()); i++) {
1297 nonzeros[i] = (Teuchos::ScalarTraits<Scalar>::magnitude(vals[i]) > eps);
1302template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1304 FindNonZeros(
const typename Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dual_view_type::t_dev_const_um vals,
1305 Kokkos::View<bool*, typename Node::device_type> nonzeros) {
1306 using ATS = KokkosKernels::ArithTraits<Scalar>;
1307 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1308 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1309 TEUCHOS_ASSERT(vals.extent(0) == nonzeros.extent(0));
1310 const typename ATS::magnitudeType eps = 2.0 * impl_ATS::eps();
1312 Kokkos::parallel_for(
1313 "MueLu:Maxwell1::FindNonZeros", range_type(0, vals.extent(0)),
1314 KOKKOS_LAMBDA(
const size_t i) {
1315 nonzeros(i) = (impl_ATS::magnitude(vals(i, 0)) > eps);
1319template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1322 const Teuchos::ArrayRCP<bool>& dirichletRows,
1323 Teuchos::ArrayRCP<bool> dirichletCols,
1324 Teuchos::ArrayRCP<bool> dirichletDomain) {
1325 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1326 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1327 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowMap = A.getRowMap();
1328 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1329 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == rowMap->getLocalNumElements());
1330 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletCols.size()) == colMap->getLocalNumElements());
1331 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletDomain.size()) == domMap->getLocalNumElements());
1332 RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, 1,
true);
1334 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1335 if (dirichletRows[i]) {
1336 ArrayView<const LocalOrdinal> indices;
1337 ArrayView<const Scalar> values;
1338 A.getLocalRowView(i, indices, values);
1339 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
1340 myColsToZero->replaceLocalValue(indices[j], 0, one);
1344 RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero;
1345 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A.getCrsGraph()->getImporter();
1346 if (!importer.is_null()) {
1347 globalColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap, 1,
true);
1349 globalColsToZero->doExport(*myColsToZero, *importer, Xpetra::ADD);
1351 myColsToZero->doImport(*globalColsToZero, *importer, Xpetra::INSERT);
1353 globalColsToZero = myColsToZero;
1355 FindNonZeros(globalColsToZero->getData(0), dirichletDomain);
1359template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1362 const Kokkos::View<bool*, typename Node::device_type>& dirichletRows,
1363 Kokkos::View<bool*, typename Node::device_type> dirichletCols,
1364 Kokkos::View<bool*, typename Node::device_type> dirichletDomain) {
1365 using ATS = KokkosKernels::ArithTraits<Scalar>;
1366 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1367 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1368 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1369 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowMap = A.getRowMap();
1370 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1371 TEUCHOS_ASSERT(dirichletRows.extent(0) == rowMap->getLocalNumElements());
1372 TEUCHOS_ASSERT(dirichletCols.extent(0) == colMap->getLocalNumElements());
1373 TEUCHOS_ASSERT(dirichletDomain.extent(0) == domMap->getLocalNumElements());
1374 RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap,
true);
1376 auto myColsToZeroView = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadWrite);
1377 auto localMatrix = A.getLocalMatrixDevice();
1378 Kokkos::parallel_for(
1379 "MueLu:Maxwell1::DetectDirichletCols", range_type(0, rowMap->getLocalNumElements()),
1381 if (dirichletRows(row)) {
1382 auto rowView = localMatrix.row(row);
1383 auto length = rowView.length;
1385 for (
decltype(length) colID = 0; colID < length; colID++)
1386 myColsToZeroView(rowView.colidx(colID), 0) = impl_ATS::one();
1390 RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero;
1391 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A.getCrsGraph()->getImporter();
1392 if (!importer.is_null()) {
1393 globalColsToZero = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap,
true);
1395 globalColsToZero->doExport(*myColsToZero, *importer, Xpetra::ADD);
1397 myColsToZero->doImport(*globalColsToZero, *importer, Xpetra::INSERT);
1399 globalColsToZero = myColsToZero;
1404template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1406 ApplyRowSumCriterion(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol, Teuchos::ArrayRCP<bool>& dirichletRows) {
1407 typedef Teuchos::ScalarTraits<Scalar> STS;
1408 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1409 typedef Teuchos::ScalarTraits<MT> MTS;
1410 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1411 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1412 size_t nnz = A.getNumEntriesInLocalRow(row);
1413 ArrayView<const LocalOrdinal> indices;
1414 ArrayView<const Scalar> vals;
1415 A.getLocalRowView(row, indices, vals);
1417 Scalar rowsum = STS::zero();
1418 Scalar diagval = STS::zero();
1420 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1423 diagval = vals[colID];
1424 rowsum += vals[colID];
1427 if (rowSumTol < MTS::one() && STS::magnitude(rowsum) > STS::magnitude(diagval) * rowSumTol) {
1429 dirichletRows[row] =
true;
1434template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1436 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) {
1437 typedef Teuchos::ScalarTraits<Scalar> STS;
1438 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1439 typedef Teuchos::ScalarTraits<MT> MTS;
1440 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1442 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()), std::runtime_error,
"ApplyRowSumCriterion: BlockNumber must match's A's column map.");
1444 Teuchos::ArrayRCP<const LocalOrdinal> block_id = BlockNumber.getData(0);
1445 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1446 size_t nnz = A.getNumEntriesInLocalRow(row);
1447 ArrayView<const LocalOrdinal> indices;
1448 ArrayView<const Scalar> vals;
1449 A.getLocalRowView(row, indices, vals);
1451 Scalar rowsum = STS::zero();
1452 Scalar diagval = STS::zero();
1453 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1456 diagval = vals[colID];
1457 if (block_id[row] == block_id[col])
1458 rowsum += vals[colID];
1462 if (rowSumTol < MTS::one() && STS::magnitude(rowsum) > STS::magnitude(diagval) * rowSumTol) {
1464 dirichletRows[row] =
true;
1470template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node,
class memory_space>
1472 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1473 Kokkos::View<bool*, memory_space>& dirichletRows) {
1474 typedef Teuchos::ScalarTraits<Scalar> STS;
1475 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1477 auto dirichletRowsHost = Kokkos::create_mirror_view(dirichletRows);
1478 Kokkos::deep_copy(dirichletRowsHost, dirichletRows);
1480 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1481 size_t nnz = A.getNumEntriesInLocalRow(row);
1482 ArrayView<const LocalOrdinal> indices;
1483 ArrayView<const Scalar> vals;
1484 A.getLocalRowView(row, indices, vals);
1486 Scalar rowsum = STS::zero();
1487 Scalar diagval = STS::zero();
1488 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1491 diagval = vals[colID];
1492 rowsum += vals[colID];
1494 if (STS::real(rowsum) > STS::magnitude(diagval) * rowSumTol)
1495 dirichletRowsHost(row) =
true;
1498 Kokkos::deep_copy(dirichletRows, dirichletRowsHost);
1501template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1504 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1505 Kokkos::View<bool*, typename Node::device_type::memory_space>& dirichletRows) {
1509template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1512 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1513 Kokkos::View<bool*, Kokkos::HostSpace>& dirichletRows) {
1518template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node,
class memory_space>
1520 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1521 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1522 Kokkos::View<bool*, memory_space>& dirichletRows) {
1523 typedef Teuchos::ScalarTraits<Scalar> STS;
1524 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1526 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()), std::runtime_error,
"ApplyRowSumCriterion: BlockNumber must match's A's column map.");
1528 auto dirichletRowsHost = Kokkos::create_mirror_view(dirichletRows);
1529 Kokkos::deep_copy(dirichletRowsHost, dirichletRows);
1531 Teuchos::ArrayRCP<const LocalOrdinal> block_id = BlockNumber.getData(0);
1532 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1533 size_t nnz = A.getNumEntriesInLocalRow(row);
1534 ArrayView<const LocalOrdinal> indices;
1535 ArrayView<const Scalar> vals;
1536 A.getLocalRowView(row, indices, vals);
1538 Scalar rowsum = STS::zero();
1539 Scalar diagval = STS::zero();
1540 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1543 diagval = vals[colID];
1544 if (block_id[row] == block_id[col])
1545 rowsum += vals[colID];
1547 if (STS::real(rowsum) > STS::magnitude(diagval) * rowSumTol)
1548 dirichletRowsHost(row) =
true;
1551 Kokkos::deep_copy(dirichletRows, dirichletRowsHost);
1554template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1557 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1558 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1559 Kokkos::View<bool*, typename Node::device_type::memory_space>& dirichletRows) {
1563template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1566 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1567 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1568 Kokkos::View<bool*, Kokkos::HostSpace>& dirichletRows) {
1572template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1573Teuchos::ArrayRCP<const bool>
1576 const Teuchos::ArrayRCP<const bool>& dirichletRows) {
1577 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1578 Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1579 Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1580 Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1581 Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, 1);
1582 myColsToZero->putScalar(zero);
1584 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1585 if (dirichletRows[i]) {
1586 Teuchos::ArrayView<const LocalOrdinal> indices;
1587 Teuchos::ArrayView<const Scalar> values;
1588 A.getLocalRowView(i, indices, values);
1589 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
1590 myColsToZero->replaceLocalValue(indices[j], 0, one);
1594 Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap, 1);
1595 globalColsToZero->putScalar(zero);
1596 Teuchos::RCP<Xpetra::Export<LocalOrdinal, GlobalOrdinal, Node>> exporter = Xpetra::ExportFactory<LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, domMap);
1598 globalColsToZero->doExport(*myColsToZero, *exporter, Xpetra::ADD);
1600 myColsToZero->doImport(*globalColsToZero, *exporter, Xpetra::INSERT);
1601 Teuchos::ArrayRCP<const Scalar> myCols = myColsToZero->getData(0);
1602 Teuchos::ArrayRCP<bool> dirichletCols(colMap->getLocalNumElements(),
true);
1603 Magnitude eps = Teuchos::ScalarTraits<Magnitude>::eps();
1604 for (
size_t i = 0; i < colMap->getLocalNumElements(); i++) {
1605 dirichletCols[i] = Teuchos::ScalarTraits<Scalar>::magnitude(myCols[i]) > 2.0 * eps;
1607 return dirichletCols;
1610template <
class SC,
class LO,
class GO,
class NO>
1611Kokkos::View<bool*, typename NO::device_type>
1614 const Kokkos::View<const bool*, typename NO::device_type>& dirichletRows) {
1615 using ATS = KokkosKernels::ArithTraits<SC>;
1616 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1617 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
1618 using scalar_type =
typename KokkosKernels::ArithTraits<SC>::val_type;
1619 using mag_type =
typename KokkosKernels::ArithTraits<scalar_type>::mag_type;
1620 using KAT_M =
typename KokkosKernels::ArithTraits<mag_type>;
1621 using KAT_S =
typename KokkosKernels::ArithTraits<scalar_type>;
1623 SC zero = ATS::zero();
1625 auto localMatrix = A.getLocalMatrixDevice();
1626 LO numRows = A.getLocalNumRows();
1628 Teuchos::RCP<const Xpetra::Map<LO, GO, NO>> domMap = A.getDomainMap();
1629 Teuchos::RCP<const Xpetra::Map<LO, GO, NO>> colMap = A.getColMap();
1630 Teuchos::RCP<Xpetra::MultiVector<SC, LO, GO, NO>> myColsToZero = Xpetra::MultiVectorFactory<SC, LO, GO, NO>::Build(colMap, 1);
1631 myColsToZero->putScalar(zero);
1632 auto myColsToZeroView = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadWrite);
1634 Kokkos::parallel_for(
1635 "MueLu:Utils::DetectDirichletCols1", range_type(0, numRows),
1636 KOKKOS_LAMBDA(
const LO row) {
1637 if (dirichletRows(row)) {
1638 auto rowView = localMatrix.row(row);
1639 auto length = rowView.length;
1641 for (
decltype(length) colID = 0; colID < length; colID++) {
1642 if (KAT_S::abs(rowView.value(colID)) > KAT_M::zero())
1643 myColsToZeroView(rowView.colidx(colID), 0) = impl_ATS::one();
1648 Teuchos::RCP<Xpetra::MultiVector<SC, LO, GO, NO>> globalColsToZero = Xpetra::MultiVectorFactory<SC, LO, GO, NO>::Build(domMap, 1);
1649 globalColsToZero->putScalar(zero);
1650 Teuchos::RCP<Xpetra::Export<LO, GO, NO>> exporter = Xpetra::ExportFactory<LO, GO, NO>::Build(colMap, domMap);
1652 globalColsToZero->doExport(*myColsToZero, *exporter, Xpetra::ADD);
1654 myColsToZero->doImport(*globalColsToZero, *exporter, Xpetra::INSERT);
1656 auto myCols = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadOnly);
1657 size_t numColEntries = colMap->getLocalNumElements();
1658 Kokkos::View<bool*, typename NO::device_type> dirichletCols(Kokkos::ViewAllocateWithoutInitializing(
"dirichletCols"), numColEntries);
1659 const typename ATS::magnitudeType eps = 2.0 * ATS::eps();
1661 Kokkos::parallel_for(
1662 "MueLu:Utils::DetectDirichletCols2", range_type(0, numColEntries),
1663 KOKKOS_LAMBDA(
const size_t i) {
1664 dirichletCols(i) = impl_ATS::magnitude(myCols(i, 0)) > eps;
1666 return dirichletCols;
1669template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1672 Frobenius(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& B) {
1677 TEUCHOS_TEST_FOR_EXCEPTION(!A.getRowMap()->isSameAs(*B.getRowMap()),
Exceptions::Incompatible,
"MueLu::CGSolver::Frobenius: row maps are incompatible");
1678 TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete() || !B.isFillComplete(),
Exceptions::RuntimeError,
"Matrices must be fill completed");
1680 const Map& AColMap = *A.getColMap();
1681 const Map& BColMap = *B.getColMap();
1683 Teuchos::ArrayView<const LocalOrdinal> indA, indB;
1684 Teuchos::ArrayView<const Scalar> valA, valB;
1685 size_t nnzA = 0, nnzB = 0;
1697 Teuchos::Array<Scalar> valBAll(BColMap.getLocalNumElements());
1699 LocalOrdinal invalid = Teuchos::OrdinalTraits<LocalOrdinal>::invalid();
1700 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero(), f = zero, gf;
1701 size_t numRows = A.getLocalNumRows();
1702 for (
size_t i = 0; i < numRows; i++) {
1703 A.getLocalRowView(i, indA, valA);
1704 B.getLocalRowView(i, indB, valB);
1709 for (
size_t j = 0; j < nnzB; j++)
1710 valBAll[indB[j]] = valB[j];
1712 for (
size_t j = 0; j < nnzA; j++) {
1715 LocalOrdinal ind = BColMap.getLocalElement(AColMap.getGlobalElement(indA[j]));
1717 f += valBAll[ind] * valA[j];
1721 for (
size_t j = 0; j < nnzB; j++)
1722 valBAll[indB[j]] = zero;
1730template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1738 int maxint = INT_MAX;
1739 int mySeed = Teuchos::as<int>((maxint - 1) * (one - (comm.getRank() + 1) / (comm.getSize() + one)));
1740 if (mySeed < 1 || mySeed == maxint) {
1741 std::ostringstream errStr;
1742 errStr <<
"Error detected with random seed = " << mySeed <<
". It should be in the interval [1,2^31-2].";
1747 Teuchos::ScalarTraits<Scalar>::seedrandom(mySeed);
1750template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1752 FindDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1753 std::vector<LocalOrdinal>& dirichletRows,
bool count_twos_as_dirichlet) {
1754 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1755 dirichletRows.resize(0);
1756 for (
size_t i = 0; i < A->getLocalNumRows(); i++) {
1757 Teuchos::ArrayView<const LocalOrdinal> indices;
1758 Teuchos::ArrayView<const Scalar> values;
1759 A->getLocalRowView(i, indices, values);
1761 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1762 if (Teuchos::ScalarTraits<Scalar>::magnitude(values[j]) > Teuchos::ScalarTraits<MT>::eps()) {
1766 if (nnz == 1 || (count_twos_as_dirichlet && nnz == 2)) {
1767 dirichletRows.push_back(i);
1772template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1774 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1775 const std::vector<LocalOrdinal>& dirichletRows) {
1776 RCP<const Map> Rmap = A->getRowMap();
1777 RCP<const Map> Cmap = A->getColMap();
1778 Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1779 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1781 for (
size_t i = 0; i < dirichletRows.size(); i++) {
1782 GlobalOrdinal row_gid = Rmap->getGlobalElement(dirichletRows[i]);
1784 Teuchos::ArrayView<const LocalOrdinal> indices;
1785 Teuchos::ArrayView<const Scalar> values;
1786 A->getLocalRowView(dirichletRows[i], indices, values);
1788 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1789 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1790 if (Cmap->getGlobalElement(indices[j]) == row_gid)
1798template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1800 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1801 const Teuchos::ArrayRCP<const bool>& dirichletRows) {
1802 TEUCHOS_ASSERT(A->isFillComplete());
1803 RCP<const Map> domMap = A->getDomainMap();
1804 RCP<const Map> ranMap = A->getRangeMap();
1805 RCP<const Map> Rmap = A->getRowMap();
1806 RCP<const Map> Cmap = A->getColMap();
1807 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == Rmap->getLocalNumElements());
1808 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1809 const Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1811 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1812 if (dirichletRows[i]) {
1815 Teuchos::ArrayView<const LocalOrdinal> indices;
1816 Teuchos::ArrayView<const Scalar> values;
1817 A->getLocalRowView(i, indices, values);
1819 Teuchos::ArrayRCP<Scalar> valuesNC(values.size());
1820 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1821 if (Cmap->getGlobalElement(indices[j]) == row_gid)
1826 A->replaceLocalValues(i, indices, valuesNC());
1829 A->fillComplete(domMap, ranMap);
1832template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1834 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1835 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows) {
1836 TEUCHOS_ASSERT(A->isFillComplete());
1837 using ATS = KokkosKernels::ArithTraits<Scalar>;
1838 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1839 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1841 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A->getDomainMap();
1842 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> ranMap = A->getRangeMap();
1843 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> Rmap = A->getRowMap();
1844 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> Cmap = A->getColMap();
1846 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == Rmap->getLocalNumElements());
1848 auto localMatrix = A->getLocalMatrixDevice();
1849 auto localRmap = Rmap->getLocalMap();
1850 auto localCmap = Cmap->getLocalMap();
1852 Kokkos::parallel_for(
1853 "MueLu::Utils::ApplyOAZ", range_type(0, dirichletRows.extent(0)),
1855 if (dirichletRows(row)) {
1856 auto rowView = localMatrix.row(row);
1857 auto length = rowView.length;
1858 auto row_gid = localRmap.getGlobalElement(row);
1859 auto row_lid = localCmap.getLocalElement(row_gid);
1861 for (
decltype(length) colID = 0; colID < length; colID++)
1862 if (rowView.colidx(colID) == row_lid)
1863 rowView.value(colID) = impl_ATS::one();
1865 rowView.value(colID) = impl_ATS::zero();
1870template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1872 ZeroDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1873 const std::vector<LocalOrdinal>& dirichletRows,
1875 for (
size_t i = 0; i < dirichletRows.size(); i++) {
1876 Teuchos::ArrayView<const LocalOrdinal> indices;
1877 Teuchos::ArrayView<const Scalar> values;
1878 A->getLocalRowView(dirichletRows[i], indices, values);
1880 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1881 for (
size_t j = 0; j < (size_t)indices.size(); j++)
1882 valuesNC[j] = replaceWith;
1886template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1888 ZeroDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1889 const Teuchos::ArrayRCP<const bool>& dirichletRows,
1891 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == A->getRowMap()->getLocalNumElements());
1892 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1893 if (dirichletRows[i]) {
1894 Teuchos::ArrayView<const LocalOrdinal> indices;
1895 Teuchos::ArrayView<const Scalar> values;
1896 A->getLocalRowView(i, indices, values);
1898 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1899 for (
size_t j = 0; j < (size_t)indices.size(); j++)
1900 valuesNC[j] = replaceWith;
1905template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1907 ZeroDirichletRows(Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& X,
1908 const Teuchos::ArrayRCP<const bool>& dirichletRows,
1910 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == X->getMap()->getLocalNumElements());
1911 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1912 if (dirichletRows[i]) {
1913 for (
size_t j = 0; j < X->getNumVectors(); j++)
1914 X->replaceLocalValue(i, j, replaceWith);
1919template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1921 ZeroDirichletRows(RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1922 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows,
1924 using ATS = KokkosKernels::ArithTraits<Scalar>;
1925 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1927 typename ATS::val_type impl_replaceWith = replaceWith;
1929 auto localMatrix = A->getLocalMatrixDevice();
1932 Kokkos::parallel_for(
1933 "MueLu:Utils::ZeroDirichletRows", range_type(0, numRows),
1935 if (dirichletRows(row)) {
1936 auto rowView = localMatrix.row(row);
1937 auto length = rowView.length;
1938 for (
decltype(length) colID = 0; colID < length; colID++)
1939 rowView.value(colID) = impl_replaceWith;
1944template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1946 ZeroDirichletRows(RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& X,
1947 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows,
1949 using ATS = KokkosKernels::ArithTraits<Scalar>;
1950 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1952 typename ATS::val_type impl_replaceWith = replaceWith;
1954 auto myCols = X->getLocalViewDevice(Tpetra::Access::ReadWrite);
1955 size_t numVecs = X->getNumVectors();
1956 Kokkos::parallel_for(
1957 "MueLu:Utils::ZeroDirichletRows_MV", range_type(0, dirichletRows.size()),
1958 KOKKOS_LAMBDA(
const size_t i) {
1959 if (dirichletRows(i)) {
1960 for (
size_t j = 0; j < numVecs; j++)
1961 myCols(i, j) = impl_replaceWith;
1966template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1969 const Teuchos::ArrayRCP<const bool>& dirichletCols,
1971 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletCols.size()) == A->getColMap()->getLocalNumElements());
1972 for (
size_t i = 0; i < A->getLocalNumRows(); i++) {
1973 Teuchos::ArrayView<const LocalOrdinal> indices;
1974 Teuchos::ArrayView<const Scalar> values;
1975 A->getLocalRowView(i, indices, values);
1977 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1978 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
1979 if (dirichletCols[indices[j]])
1980 valuesNC[j] = replaceWith;
1984template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1986 ZeroDirichletCols(RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1987 const Kokkos::View<const bool*, typename Node::device_type>& dirichletCols,
1988 Scalar replaceWith,
const bool DontZeroDiagEntries) {
1989 using ATS = KokkosKernels::ArithTraits<Scalar>;
1990 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1992 typename ATS::val_type impl_replaceWith = replaceWith;
1994 auto localMatrix = A->getLocalMatrixDevice();
1996 auto lclRowmap = A->getRowMap()->getLocalMap();
1997 auto lclCowmap = A->getColMap()->getLocalMap();
1999 Kokkos::parallel_for(
2000 "MueLu:Utils::ZeroDirichletCols", range_type(0, numRows),
2002 auto rowView = localMatrix.row(row);
2003 auto length = rowView.length;
2005 if (DontZeroDiagEntries) {
2006 auto rgid = lclRowmap.getGlobalElement(row);
2007 for (
decltype(length) colID = 0; colID < length; colID++) {
2008 if (dirichletCols(rowView.colidx(colID))) {
2009 auto cgid = lclCowmap.getGlobalElement(rowView.colidx(colID));
2010 if (rgid != cgid) rowView.value(colID) = impl_replaceWith;
2014 for (
decltype(length) colID = 0; colID < length; colID++)
2015 if (dirichletCols(rowView.colidx(colID))) {
2016 rowView.value(colID) = impl_replaceWith;
2022template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2025 Teuchos::RCP<Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node>>&
isDirichletRow,
2026 Teuchos::RCP<Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node>>& isDirichletCol) {
2028 if (!A->getRowMap()->isSameAs(*A->getDomainMap())) {
2029 throw std::runtime_error(
"UtilitiesBase::FindDirichletRowsAndPropagateToCols row and domain maps must match.");
2031 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A->getCrsGraph()->getImporter();
2032 bool has_import = !importer.is_null();
2035 std::vector<LocalOrdinal> dirichletRows;
2039 printf(
"[%d] DirichletRow Ids = ",A->getRowMap()->getComm()->getRank());
2040 for(
size_t i=0; i<(size_t) dirichletRows.size(); i++)
2041 printf(
"%d ",dirichletRows[i]);
2046 isDirichletRow = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(A->getRowMap(),
true);
2047 isDirichletCol = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(A->getColMap(),
true);
2050 Teuchos::ArrayRCP<int> dr_rcp =
isDirichletRow->getDataNonConst(0);
2051 Teuchos::ArrayView<int> dr = dr_rcp();
2052 Teuchos::ArrayRCP<int> dc_rcp = isDirichletCol->getDataNonConst(0);
2053 Teuchos::ArrayView<int> dc = dc_rcp();
2054 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
2055 dr[dirichletRows[i]] = 1;
2056 if (!has_import) dc[dirichletRows[i]] = 1;
2061 isDirichletCol->doImport(*
isDirichletRow, *importer, Xpetra::CombineMode::ADD);
2064template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2065RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
2068 using ISC =
typename KokkosKernels::ArithTraits<Scalar>::val_type;
2069 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
2070 using local_matrix_type =
typename CrsMatrix::local_matrix_device_type;
2071 using values_type =
typename local_matrix_type::values_type;
2073 const ISC ONE = KokkosKernels::ArithTraits<ISC>::one();
2074 const ISC ZERO = KokkosKernels::ArithTraits<ISC>::zero();
2077 auto localMatrix = original->getLocalMatrixDevice();
2078 TEUCHOS_TEST_FOR_EXCEPTION(!original->hasCrsGraph(),
Exceptions::RuntimeError,
"ReplaceNonZerosWithOnes: Cannot get CrsGraph");
2079 values_type new_values(
"values", localMatrix.nnz());
2081 Kokkos::parallel_for(
2082 "ReplaceNonZerosWithOnes", range_type(0, localMatrix.nnz()), KOKKOS_LAMBDA(
const size_t i) {
2083 if (localMatrix.values(i) != ZERO)
2084 new_values(i) = ONE;
2086 new_values(i) = ZERO;
2090 RCP<Matrix> NewMatrix = Xpetra::MatrixFactory<SC, LO, GO, NO>::Build(original->getCrsGraph(), new_values);
2091 TEUCHOS_TEST_FOR_EXCEPTION(NewMatrix.is_null(),
Exceptions::RuntimeError,
"ReplaceNonZerosWithOnes: MatrixFactory::Build() did not return matrix");
2092 NewMatrix->fillComplete(original->getDomainMap(), original->getRangeMap());
2096template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2097RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
2105#ifdef HAVE_MUELU_TIMER_SYNCHRONIZATION
2106 miniLevel.
SetComm(M->getRowMap()->getComm());
2108 miniLevel.
Set(
"A", M);
2112 if (MinvScheme ==
"fsai")
2113 invapproxFact->SetParameter(
"inverse: approximation type", Teuchos::ParameterEntry(std::string(
"factoredsparseapproxinverse")));
2115 invapproxFact->SetParameter(
"inverse: approximation type", Teuchos::ParameterEntry(std::string(
"sparseapproxinverse")));
2117 miniLevel.
Request(
"Ainv", invapproxFact.get());
2118 invapproxFact->Build(miniLevel);
2119 RCP<Matrix> NewMatrix = miniLevel.
Get<RCP<Matrix>>(
"Ainv", invapproxFact.get());
2120 TEUCHOS_TEST_FOR_EXCEPTION(NewMatrix.is_null(),
Exceptions::RuntimeError,
"SPAI: MatrixFactory::Build() did not return matrix");
2124template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2125RCP<const Xpetra::BlockedMap<LocalOrdinal, GlobalOrdinal, Node>>
2128 const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>& Importer) {
2129 typedef Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node> IntVector;
2130 Xpetra::UnderlyingLib lib = sourceBlockedMap.lib();
2133 RCP<const Map> fullMap = sourceBlockedMap.getMap();
2134 RCP<const Map> stridedMap = Teuchos::rcp_dynamic_cast<const Xpetra::StridedMap<LocalOrdinal, GlobalOrdinal, Node>>(fullMap);
2135 if (!stridedMap.is_null()) fullMap = stridedMap->getMap();
2138 const size_t numSubMaps = sourceBlockedMap.getNumMaps();
2139 if (!Importer.getSourceMap()->isCompatible(*fullMap))
2140 throw std::runtime_error(
"GenerateBlockedTargetMap(): Map compatibility error");
2143 RCP<IntVector> block_ids = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(fullMap);
2145 for (
size_t i = 0; i < numSubMaps; i++) {
2146 RCP<const Map> map = sourceBlockedMap.getMap(i);
2148 for (
size_t j = 0; j < map->getLocalNumElements(); j++) {
2149 LocalOrdinal jj = fullMap->getLocalElement(map->getGlobalElement(j));
2150 block_ids->replaceLocalValue(jj, (
int)i);
2155 RCP<const Map> targetMap = Importer.getTargetMap();
2156 RCP<IntVector> new_block_ids = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(targetMap);
2157 new_block_ids->doImport(*block_ids, Importer, Xpetra::CombineMode::ADD);
2158 Teuchos::ArrayRCP<const int> dataRCP = new_block_ids->getData(0);
2159 Teuchos::ArrayView<const int> data = dataRCP();
2162 Teuchos::Array<Teuchos::Array<GlobalOrdinal>> elementsInSubMap(numSubMaps);
2163 for (
size_t i = 0; i < targetMap->getLocalNumElements(); i++) {
2164 elementsInSubMap[data[i]].push_back(targetMap->getGlobalElement(i));
2168 std::vector<RCP<const Map>> subMaps(numSubMaps);
2169 for (
size_t i = 0; i < numSubMaps; i++) {
2170 subMaps[i] = Xpetra::MapFactory<LocalOrdinal, GlobalOrdinal, Node>::Build(lib, Teuchos::OrdinalTraits<GlobalOrdinal>::invalid(), elementsInSubMap[i](), targetMap->getIndexBase(), targetMap->getComm());
2174 return rcp(
new BlockedMap(targetMap, subMaps));
2177template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2179 MapsAreNested(
const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& rowMap,
const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& colMap) {
2180 if ((rowMap.lib() == Xpetra::UseTpetra) && (colMap.lib() == Xpetra::UseTpetra)) {
2181 auto tpRowMap = toTpetra(rowMap);
2182 auto tpColMap = toTpetra(colMap);
2183 return tpColMap.isLocallyFitted(tpRowMap);
2186 ArrayView<const GlobalOrdinal> rowElements = rowMap.getLocalElementList();
2187 ArrayView<const GlobalOrdinal> colElements = colMap.getLocalElementList();
2189 const size_t numElements = rowElements.size();
2191 if (
size_t(colElements.size()) < numElements)
2194 bool goodMap =
true;
2195 for (
size_t i = 0; i < numElements; i++)
2196 if (rowElements[i] != colElements[i]) {
2204template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2205Teuchos::RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>>
2207 ReverseCuthillMcKee(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op) {
2208 using local_matrix_type =
typename Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::local_matrix_device_type;
2209 using local_graph_type =
typename local_matrix_type::staticcrsgraph_type;
2210 using lno_nnz_view_t =
typename local_graph_type::entries_type::non_const_type;
2211 using device =
typename local_graph_type::device_type;
2212 using execution_space =
typename local_matrix_type::execution_space;
2213 using ordinal_type =
typename local_matrix_type::ordinal_type;
2215 local_graph_type localGraph = Op.getLocalMatrixDevice().graph;
2217 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);
2219 RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>> retval =
2220 Xpetra::VectorFactory<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(Op.getRowMap());
2223 auto view1D = Kokkos::subview(retval->getLocalViewDevice(Tpetra::Access::ReadWrite), Kokkos::ALL(), 0);
2224 Kokkos::parallel_for(
2225 "Utilities::ReverseCuthillMcKee",
2226 Kokkos::RangePolicy<ordinal_type, execution_space>(0, localGraph.numRows()),
2227 KOKKOS_LAMBDA(
const ordinal_type rowIdx) {
2228 view1D(rcmOrder(rowIdx)) = rowIdx;
2233template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2234Teuchos::RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>>
2236 CuthillMcKee(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op) {
2237 using local_matrix_type =
typename Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::local_matrix_device_type;
2238 using local_graph_type =
typename local_matrix_type::staticcrsgraph_type;
2239 using lno_nnz_view_t =
typename local_graph_type::entries_type::non_const_type;
2240 using device =
typename local_graph_type::device_type;
2241 using execution_space =
typename local_matrix_type::execution_space;
2242 using ordinal_type =
typename local_matrix_type::ordinal_type;
2244 local_graph_type localGraph = Op.getLocalMatrixDevice().graph;
2247 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);
2249 RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>> retval =
2250 Xpetra::VectorFactory<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(Op.getRowMap());
2253 auto view1D = Kokkos::subview(retval->getLocalViewDevice(Tpetra::Access::ReadWrite), Kokkos::ALL(), 0);
2255 Kokkos::parallel_for(
2256 "Utilities::ReverseCuthillMcKee",
2257 Kokkos::RangePolicy<ordinal_type, execution_space>(0, numRows),
2258 KOKKOS_LAMBDA(
const ordinal_type rowIdx) {
2259 view1D(rcmOrder(numRows - 1 - rowIdx)) = rowIdx;
2264template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2266 TripleMatrixProduct(
const Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& R,
2267 const Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
2268 const Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& P,
2269 Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& Ac,
2270 const Teuchos::ParameterList& pL,
2272 Teuchos::RCP<Teuchos::ParameterList>& APparams,
2273 Teuchos::RCP<Teuchos::ParameterList>& RAPparams,
2274 Level* coarseLevel) {
2275 using Matrix = Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
2276 using MatrixMatrix = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
2277 using MatrixFactory = Xpetra::MatrixFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>;
2280 const bool doTranspose =
true;
2281 const bool doFillComplete =
true;
2282 const bool doOptimizeStorage =
true;
2284 const bool useImplicit = pL.get<
bool>(
"transpose: use implicit");
2286 const std::string matrixName = (pL.isType<std::string>(
"Matrix name")) ? pL.get<std::string>(
"Matrix name") :
"A";
2287 const std::string prolongatorName = (pL.isType<std::string>(
"Prolongator name")) ? pL.get<std::string>(
"Prolongator name") :
"P";
2288 const std::string restrictorName = (pL.isType<std::string>(
"Restrictor name")) ? pL.get<std::string>(
"Restrictor name") :
"R";
2289 std::string coarseMatrixName;
2290 if (pL.isType<std::string>(
"coarseMatrixName"))
2291 coarseMatrixName = pL.get<std::string>(
"coarseMatrixName");
2293 if (matrixName.size() == 1)
2294 coarseMatrixName = matrixName +
"c";
2296 coarseMatrixName = matrixName +
"_coarse";
2299 std::string levelstr, labelstr;
2300 if (coarseLevel !=
nullptr) {
2301 std::ostringstream levelss;
2303 levelstr = levelss.str();
2307 bool isGPU = Node::is_gpu;
2310 if (RAPparams.is_null())
2311 RAPparams = rcp(
new ParameterList);
2312 if (pL.isSublist(
"matrixmatrix: kernel params"))
2313 RAPparams->setParameters(pL.sublist(
"matrixmatrix: kernel params"));
2315 if (RAPparams->isParameter(
"graph")) {
2316 Ac = RAPparams->get<RCP<Matrix>>(
"graph");
2320 Ac->SetMaxEigenvalueEstimate(-Teuchos::ScalarTraits<Scalar>::one());
2324 RAPparams->set(
"compute global constants: temporaries", RAPparams->get(
"compute global constants: temporaries",
false));
2325 RAPparams->set(
"compute global constants", RAPparams->get(
"compute global constants",
true));
2327 if (pL.get<
bool>(
"rap: triple product") ==
false || isGPU) {
2328 if (pL.get<
bool>(
"rap: triple product") && isGPU)
2329 verbObj.
GetOStream(
Warnings1) <<
"Switching from triple product to R x (A x P) since triple product has not been implemented for "
2330 << Node::execution_space::name() << std::endl;
2335 if (APparams.is_null())
2336 APparams = rcp(
new ParameterList);
2337 if (pL.isSublist(
"matrixmatrix: kernel params"))
2338 APparams = rcp(
new ParameterList(pL.sublist(
"matrixmatrix: kernel params")));
2341 APparams->set(
"compute global constants: temporaries", APparams->get(
"compute global constants: temporaries",
false));
2342 APparams->set(
"compute global constants", APparams->get(
"compute global constants",
false));
2344 if (APparams->isParameter(
"graph"))
2345 AP = APparams->get<RCP<Matrix>>(
"graph");
2347 std::string monitorstrAP =
"MxM: " + matrixName +
" x " + prolongatorName;
2348 std::string timerstrAP =
"MueLu::" + matrixName +
"*" + prolongatorName;
2349 if (!labelstr.empty())
2350 timerstrAP = labelstr + timerstrAP;
2351 if (!levelstr.empty())
2352 timerstrAP = timerstrAP +
"-" + levelstr;
2357 AP = MatrixMatrix::Multiply(*A, !doTranspose, *P, !doTranspose, AP, verbObj.
GetOStream(
Statistics2),
2358 doFillComplete, doOptimizeStorage, timerstrAP, APparams);
2365 std::string timerstrRAP, monitorstrRAP;
2367 monitorstrRAP =
"MxM: " + prolongatorName +
"' x (" + matrixName + prolongatorName +
") (implicit)";
2368 timerstrRAP =
"MueLu::" + restrictorName +
"*(" + matrixName +
"*" + prolongatorName +
")-implicit";
2370 monitorstrRAP =
"MxM: " + restrictorName +
" x (" + matrixName + prolongatorName +
") (explicit)";
2371 timerstrRAP =
"MueLu::" + restrictorName +
"*(" + matrixName +
"*" + prolongatorName +
")-explicit";
2373 if (!labelstr.empty())
2374 timerstrRAP = labelstr + timerstrRAP;
2375 if (!levelstr.empty())
2376 timerstrRAP = timerstrRAP +
"-" + levelstr;
2381 Ac = MatrixMatrix::Multiply(*P, doTranspose, *AP, !doTranspose, Ac, verbObj.
GetOStream(
Statistics2),
2382 doFillComplete, doOptimizeStorage, timerstrRAP, RAPparams);
2387 Ac = MatrixMatrix::Multiply(*R, !doTranspose, *AP, !doTranspose, Ac, verbObj.
GetOStream(
Statistics2),
2388 doFillComplete, doOptimizeStorage, timerstrRAP, RAPparams);
2392 APparams->set(
"graph", AP);
2396 std::string monitorstrRAP;
2397 std::string timerstrRAP;
2399 monitorstrRAP =
"MxMxM: " + restrictorName +
" x " + matrixName +
" x " + prolongatorName +
" (implicit)";
2400 timerstrRAP =
"MueLu::" + restrictorName +
"*" + matrixName +
"*" + prolongatorName +
"-implicit";
2402 monitorstrRAP =
"MxMxM: " + restrictorName +
" x " + matrixName +
" x " + prolongatorName +
" (explicit)";
2403 timerstrRAP =
"MueLu::" + restrictorName +
"*" + matrixName +
"*" + prolongatorName +
"-explicit";
2405 if (!labelstr.empty())
2406 timerstrRAP = labelstr + timerstrRAP;
2407 if (!levelstr.empty())
2408 timerstrRAP = timerstrRAP +
"-" + levelstr;
2411 Ac = MatrixFactory::Build(P->getDomainMap(), Teuchos::as<LocalOrdinal>(0));
2415 Xpetra::TripleMatrixMultiply<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
2416 MultiplyRAP(*P, doTranspose, *A, !doTranspose, *P, !doTranspose, *Ac, doFillComplete,
2417 doOptimizeStorage, timerstrRAP,
2420 Ac = MatrixFactory::Build(R->getRowMap(), Teuchos::as<LocalOrdinal>(0));
2424 Xpetra::TripleMatrixMultiply<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
2425 MultiplyRAP(*R, !doTranspose, *A, !doTranspose, *P, !doTranspose, *Ac, doFillComplete,
2426 doOptimizeStorage, timerstrRAP,
2431 Teuchos::ArrayView<const double> relativeFloor = pL.get<Teuchos::Array<double>>(
"rap: relative diagonal floor")();
2432 if (relativeFloor.size() > 0) {
2433 Xpetra::MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::RelativeDiagonalBoost(Ac, relativeFloor, verbObj.
GetOStream(
Statistics2));
2436 bool repairZeroDiagonals = pL.get<
bool>(
"RepairMainDiagonal") || pL.get<
bool>(
"rap: fix zero diagonals");
2437 bool checkAc = pL.get<
bool>(
"CheckMainDiagonal") || pL.get<
bool>(
"rap: fix zero diagonals");
2439 if (checkAc || repairZeroDiagonals) {
2440 using magnitudeType =
typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
2441 magnitudeType threshold;
2442 if (pL.isType<magnitudeType>(
"rap: fix zero diagonals threshold"))
2443 threshold = pL.get<magnitudeType>(
"rap: fix zero diagonals threshold");
2445 threshold = Teuchos::as<magnitudeType>(pL.get<
double>(
"rap: fix zero diagonals threshold"));
2446 Scalar replacement = Teuchos::as<Scalar>(pL.get<
double>(
"rap: fix zero diagonals replacement"));
2447 Xpetra::MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::CheckRepairMainDiagonal(Ac, repairZeroDiagonals, verbObj.
GetOStream(
Warnings1), threshold, replacement);
2451 RCP<ParameterList> params = rcp(
new ParameterList());
2452 params->set(
"printLoadBalancingInfo",
true);
2453 params->set(
"printCommInfo",
true);
2458 RAPparams->set(
"graph", Ac);
2462 MatrixUtils::checkLocalRowMapMatchesColMap(*Ac);