466 if (nnzPerRow[i] == 1 && TST::magnitude(diagVals[i]) == 1.)
467 numDiagsEqualToOne++;
469 if (useAverageAbsDiagVal)
470 tol = TST::magnitude(100 * Teuchos::ScalarTraits<Scalar>::eps()) * (avgAbsDiagVal - numDiagsEqualToOne) / (rowMap->getLocalNumElements() - numDiagsEqualToOne);
472 for (
size_t i = 0; i < rowMap->getLocalNumElements(); ++i) {
473 if (replaceSingleEntryRowWithZero && nnzPerRow[i] <=
static_cast<int>(1))
475 else if ((diagVals[i] != zero) && (TST::magnitude(diagVals[i]) < TST::magnitude(two * regSum[i])))
476 diagVals[i] = one / TST::magnitude((two * regSum[i]));
478 if (TST::magnitude(diagVals[i]) > tol)
479 diagVals[i] = one / diagVals[i];
481 diagVals[i] = valReplacement;
488 TEUCHOS_TEST_FOR_EXCEPTION(doReciprocal, Xpetra::Exceptions::RuntimeError,
489 "UtilitiesBase::GetLumpedMatrixDiagonal(): extracting reciprocal of diagonal of a blocked matrix is not supported");
490 diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(bA->getRangeMapExtractor()->getFullMap(),
true);
492 for (
size_t row = 0; row < bA->Rows(); ++row) {
493 for (
size_t col = 0; col < bA->Cols(); ++col) {
494 if (!bA->getMatrix(row, col).is_null()) {
496 bool bThyraMode = bA->getRangeMapExtractor()->getThyraMode() && (Teuchos::rcp_dynamic_cast<Xpetra::BlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>(bA->getMatrix(row, col)) == Teuchos::null);
497 RCP<Vector> ddtemp = bA->getRangeMapExtractor()->ExtractVector(diag, row, bThyraMode);
498 RCP<const Vector> dd = GetLumpedMatrixDiagonal(*(bA->getMatrix(row, col)));
499 ddtemp->update(Teuchos::as<Scalar>(1.0), *dd, Teuchos::as<Scalar>(1.0));
500 bA->getRangeMapExtractor()->InsertVector(ddtemp, row, diag, bThyraMode);
509template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
510Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
514 RCP<const Map> rowMap = A.getRowMap();
515 auto diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(rowMap,
false);
518 using local_vector_type =
typename Vector::dual_view_type::t_dev_um;
519 using local_matrix_type =
typename Matrix::local_matrix_device_type;
520 using execution_space =
typename local_vector_type::execution_space;
521 using values_type =
typename local_matrix_type::values_type;
522 using scalar_type =
typename values_type::non_const_value_type;
523 using KAT_S =
typename KokkosKernels::ArithTraits<scalar_type>;
525 auto diag_dev = diag->getLocalViewDevice(Tpetra::Access::OverwriteAll);
526 auto local_mat_dev = A.getLocalMatrixDevice();
527 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(diag_dev.extent(0)));
529 Kokkos::parallel_for(
530 "GetMatrixMaxMinusOffDiagonal", my_policy,
532 auto mymax = KAT_S::zero();
533 auto row = local_mat_dev.rowConst(rowIdx);
534 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
535 if (rowIdx != row.colidx(entryIdx)) {
536 if (KAT_S::real(mymax) < -KAT_S::real(row.value(entryIdx)))
537 mymax = -KAT_S::real(row.value(entryIdx));
540 diag_dev(rowIdx, 0) = mymax;
546template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
547Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
549 GetMatrixMaxMinusOffDiagonal(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber) {
550 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()), std::runtime_error,
"GetMatrixMaxMinusOffDiagonal: BlockNumber must match's A's column map.");
553 RCP<const Map> rowMap = A.getRowMap();
554 auto diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(rowMap,
false);
557 using local_vector_type =
typename Vector::dual_view_type::t_dev_um;
558 using local_matrix_type =
typename Matrix::local_matrix_device_type;
559 using execution_space =
typename local_vector_type::execution_space;
560 using values_type =
typename local_matrix_type::values_type;
561 using scalar_type =
typename values_type::non_const_value_type;
562 using KAT_S =
typename KokkosKernels::ArithTraits<scalar_type>;
564 auto diag_dev = diag->getLocalViewDevice(Tpetra::Access::OverwriteAll);
565 auto local_mat_dev = A.getLocalMatrixDevice();
566 auto local_block_dev = BlockNumber.getLocalViewDevice(Tpetra::Access::ReadOnly);
567 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(diag_dev.extent(0)));
569 Kokkos::parallel_for(
570 "GetMatrixMaxMinusOffDiagonal", my_policy,
572 auto mymax = KAT_S::zero();
573 auto row = local_mat_dev.row(rowIdx);
574 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
575 if ((rowIdx != row.colidx(entryIdx)) && (local_block_dev(rowIdx, 0) == local_block_dev(row.colidx(entryIdx), 0))) {
576 if (KAT_S::real(mymax) < -KAT_S::real(row.value(entryIdx)))
577 mymax = -KAT_S::real(row.value(entryIdx));
580 diag_dev(rowIdx, 0) = mymax;
586template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
587Teuchos::RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
589 GetInverse(Teuchos::RCP<
const Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> v,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tol,
Scalar valReplacement) {
590 RCP<Vector> ret = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(v->getMap(),
true);
593 RCP<const BlockedVector> bv = Teuchos::rcp_dynamic_cast<const BlockedVector>(v);
594 if (bv.is_null() ==
false) {
595 RCP<BlockedVector> bret = Teuchos::rcp_dynamic_cast<BlockedVector>(ret);
596 TEUCHOS_TEST_FOR_EXCEPTION(bret.is_null() ==
true,
MueLu::Exceptions::RuntimeError,
"MueLu::UtilitiesBase::GetInverse: return vector should be of type BlockedVector");
597 RCP<const BlockedMap> bmap = bv->getBlockedMap();
598 for (
size_t r = 0; r < bmap->getNumMaps(); ++r) {
599 RCP<const MultiVector> submvec = bv->getMultiVector(r, bmap->getThyraMode());
600 RCP<const Vector> subvec = submvec->getVector(0);
602 bret->setMultiVector(r, subvecinf, bmap->getThyraMode());
608 ArrayRCP<Scalar> retVals = ret->getDataNonConst(0);
609 ArrayRCP<const Scalar> inputVals = v->getData(0);
610 for (
size_t i = 0; i < v->getMap()->getLocalNumElements(); ++i) {
611 if (Teuchos::ScalarTraits<Scalar>::magnitude(inputVals[i]) > tol)
612 retVals[i] = Teuchos::ScalarTraits<Scalar>::one() / inputVals[i];
614 retVals[i] = valReplacement;
657template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
658RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
661 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
662 RCP<Vector> localDiag = GetMatrixDiagonal(A);
663 RCP<const Import> importer = A.getCrsGraph()->getImporter();
664 if (importer.is_null() && !rowMap->isSameAs(*colMap)) {
665 importer = ImportFactory::Build(rowMap, colMap);
667 if (!importer.is_null()) {
668 RCP<Vector> diagonal = VectorFactory::Build(colMap,
false);
669 diagonal->doImport(*localDiag, *(importer), Xpetra::INSERT);
675template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
676RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
679 using STS =
typename Teuchos::ScalarTraits<SC>;
682 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
683 RCP<const BlockedMap> browMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
684 if (!browMap.is_null()) rowMap = browMap->getMap();
686 RCP<Vector> local = Xpetra::VectorFactory<SC, LO, GO, Node>::Build(rowMap);
687 RCP<Vector> ghosted = Xpetra::VectorFactory<SC, LO, GO, Node>::Build(colMap,
true);
688 ArrayRCP<SC> localVals = local->getDataNonConst(0);
690 for (LO row = 0; row < static_cast<LO>(A.getRowMap()->getLocalNumElements()); ++row) {
691 size_t nnz = A.getNumEntriesInLocalRow(row);
692 ArrayView<const LO> indices;
693 ArrayView<const SC> vals;
694 A.getLocalRowView(row, indices, vals);
698 for (LO colID = 0; colID < static_cast<LO>(nnz); colID++) {
699 if (indices[colID] != row) {
706 RCP<const Xpetra::Import<LO, GO, Node>> importer;
707 importer = A.getCrsGraph()->getImporter();
708 if (importer == Teuchos::null) {
709 importer = Xpetra::ImportFactory<LO, GO, Node>::Build(rowMap, colMap);
711 ghosted->doImport(*local, *(importer), Xpetra::INSERT);
715template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
719 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
720 using STS =
typename Teuchos::ScalarTraits<Scalar>;
721 using MTS =
typename Teuchos::ScalarTraits<Magnitude>;
723 using RealValuedVector = Xpetra::Vector<MT, LO, GO, Node>;
726 RCP<const BlockedMap> browMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
727 if (!browMap.is_null()) rowMap = browMap->getMap();
729 RCP<RealValuedVector> local = Xpetra::VectorFactory<MT, LO, GO, Node>::Build(rowMap);
730 RCP<RealValuedVector> ghosted = Xpetra::VectorFactory<MT, LO, GO, Node>::Build(colMap,
true);
731 ArrayRCP<MT> localVals = local->getDataNonConst(0);
733 for (LO rowIdx = 0; rowIdx < static_cast<LO>(A.getRowMap()->getLocalNumElements()); ++rowIdx) {
734 size_t nnz = A.getNumEntriesInLocalRow(rowIdx);
735 ArrayView<const LO> indices;
736 ArrayView<const SC> vals;
737 A.getLocalRowView(rowIdx, indices, vals);
741 for (LO colID = 0; colID < static_cast<LO>(nnz); ++colID) {
742 if (indices[colID] != rowIdx) {
743 si += STS::magnitude(vals[colID]);
746 localVals[rowIdx] = si;
749 RCP<const Xpetra::Import<LO, GO, Node>> importer;
750 importer = A.getCrsGraph()->getImporter();
751 if (importer == Teuchos::null) {
752 importer = Xpetra::ImportFactory<LO, GO, Node>::Build(rowMap, colMap);
754 ghosted->doImport(*local, *(importer), Xpetra::INSERT);
758template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
762 using local_matrix_type =
typename Matrix::local_matrix_device_type;
763 using execution_space =
typename local_matrix_type::execution_space;
764 using KAT_S =
typename KokkosKernels::ArithTraits<typename local_matrix_type::value_type>;
766 auto local_mat_dev = A.getLocalMatrixDevice();
767 Kokkos::RangePolicy<execution_space, int> my_policy(0,
static_cast<int>(local_mat_dev.numRows()));
770 Kokkos::parallel_reduce(
771 "CountNegativeDiagonalEntries", my_policy,
773 auto row = local_mat_dev.row(rowIdx);
774 for (
LocalOrdinal entryIdx = 0; entryIdx < row.length; ++entryIdx) {
775 if (rowIdx == row.colidx(entryIdx) && KAT_S::real(row.value(entryIdx)) < 0)
781 MueLu_sumAll(A.getRowMap()->getComm(), count_l, count_g);
785template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
786Teuchos::Array<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>
788 ResidualNorm(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS) {
789 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
790 const size_t numVecs = X.getNumVectors();
791 RCP<MultiVector> RES = Residual(Op, X, RHS);
792 Teuchos::Array<Magnitude> norms(numVecs);
797template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
798Teuchos::Array<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>
800 ResidualNorm(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS, MultiVector& Resid) {
801 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
802 const size_t numVecs = X.getNumVectors();
803 Residual(Op, X, RHS, Resid);
804 Teuchos::Array<Magnitude> norms(numVecs);
809template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
810RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
812 Residual(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS) {
813 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides")
814 const size_t numVecs = X.getNumVectors();
816 RCP<MultiVector> RES = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(RHS.getMap(), numVecs,
false);
817 Op.residual(X, RHS, *RES);
821template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
823 Residual(
const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op,
const MultiVector& X,
const MultiVector& RHS, MultiVector& Resid) {
824 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of solution vectors != number of right-hand sides");
825 TEUCHOS_TEST_FOR_EXCEPTION(Resid.getNumVectors() != RHS.getNumVectors(),
Exceptions::RuntimeError,
"Number of residual vectors != number of right-hand sides");
826 Op.residual(X, RHS, Resid);
829template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
833 LocalOrdinal niters,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance,
bool verbose,
unsigned int seed) {
835 "Utils::PowerMethod: operator must have domain and range maps that are equivalent.");
838 RCP<Vector> diagInvVec;
840 diagInvVec = GetMatrixDiagonalInverse(A);
843 Scalar lambda = PowerMethod(A, diagInvVec, niters, tolerance, verbose, seed);
847template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
849UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
850 PowerMethod(
const Matrix& A,
const RCP<Vector>& diagInvVec,
851 LocalOrdinal niters,
typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance,
bool verbose,
unsigned int seed) {
852 TEUCHOS_TEST_FOR_EXCEPTION(!(A.getRangeMap()->isSameAs(*(A.getDomainMap()))), Exceptions::Incompatible,
853 "Utils::PowerMethod: operator must have domain and range maps that are equivalent.");
856 RCP<Vector> q = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getDomainMap(),
true);
857 RCP<Vector> r = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRangeMap(),
true);
858 RCP<Vector> z = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRangeMap(),
false);
863 Teuchos::Array<Magnitude> norms(1);
865 typedef Teuchos::ScalarTraits<Scalar> STS;
867 const Scalar zero = STS::zero(), one = STS::one();
870 Magnitude residual = STS::magnitude(zero);
873 for (
int iter = 0; iter < niters; ++iter) {
875 q->update(one / norms[0], *z, zero);
877 if (diagInvVec != Teuchos::null)
878 z->elementWiseMultiply(one, *diagInvVec, *z, zero);
881 if (iter % 100 == 0 || iter + 1 == niters) {
882 r->update(1.0, *z, -lambda, *q, zero);
884 residual = STS::magnitude(norms[0] / lambda);
886 std::cout <<
"Iter = " << iter
887 <<
" Lambda = " << lambda
888 <<
" Residual of A*q - lambda*q = " << residual
892 if (residual < tolerance)
898template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
899RCP<Teuchos::FancyOStream>
902 RCP<Teuchos::FancyOStream> fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(os));
906template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
907typename Teuchos::ScalarTraits<Scalar>::magnitudeType
910 const size_t numVectors = v.size();
912 Scalar d = Teuchos::ScalarTraits<Scalar>::zero();
913 for (
size_t j = 0; j < numVectors; j++) {
914 d += (v[j][i0] - v[j][i1]) * (v[j][i0] - v[j][i1]);
916 return Teuchos::ScalarTraits<Scalar>::magnitude(d);
919template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
920typename Teuchos::ScalarTraits<Scalar>::magnitudeType
923 const size_t numVectors = v.size();
924 using MT =
typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
926 Scalar d = Teuchos::ScalarTraits<Scalar>::zero();
927 for (
size_t j = 0; j < numVectors; j++) {
928 d += Teuchos::as<MT>(weight[j]) * (v[j][i0] - v[j][i1]) * (v[j][i0] - v[j][i1]);
930 return Teuchos::ScalarTraits<Scalar>::magnitude(d);
933template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
934Teuchos::ArrayRCP<const bool>
936 DetectDirichletRows(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType& tol,
bool count_twos_as_dirichlet) {
938 typedef Teuchos::ScalarTraits<Scalar> STS;
939 ArrayRCP<bool> boundaryNodes(numRows,
true);
940 if (count_twos_as_dirichlet) {
942 ArrayView<const LocalOrdinal> indices;
943 ArrayView<const Scalar> vals;
944 A.getLocalRowView(row, indices, vals);
945 size_t nnz = A.getNumEntriesInLocalRow(row);
948 for (col = 0; col < nnz; col++)
949 if ((indices[col] != row) && STS::magnitude(vals[col]) > tol) {
950 if (!boundaryNodes[row])
952 boundaryNodes[row] =
false;
955 boundaryNodes[row] =
true;
960 ArrayView<const LocalOrdinal> indices;
961 ArrayView<const Scalar> vals;
962 A.getLocalRowView(row, indices, vals);
963 size_t nnz = A.getNumEntriesInLocalRow(row);
965 for (
size_t col = 0; col < nnz; col++)
966 if ((indices[col] != row) && STS::magnitude(vals[col]) > tol) {
967 boundaryNodes[row] =
false;
972 return boundaryNodes;
975template <
class CrsMatrix>
976KOKKOS_FORCEINLINE_FUNCTION
bool isDirichletRow(
typename CrsMatrix::ordinal_type rowId,
977 KokkosSparse::SparseRowViewConst<CrsMatrix>& row,
978 const typename KokkosKernels::ArithTraits<typename CrsMatrix::value_type>::magnitudeType& tol,
979 const bool count_twos_as_dirichlet) {
980 using ATS = KokkosKernels::ArithTraits<typename CrsMatrix::value_type>;
982 auto length = row.length;
983 bool boundaryNode =
true;
985 if (count_twos_as_dirichlet) {
987 decltype(length) colID = 0;
988 for (; colID < length; colID++)
989 if ((row.colidx(colID) != rowId) &&
990 (ATS::magnitude(row.value(colID)) > tol)) {
993 boundaryNode =
false;
999 for (
decltype(length) colID = 0; colID < length; colID++)
1000 if ((row.colidx(colID) != rowId) &&
1001 (ATS::magnitude(row.value(colID)) > tol)) {
1002 boundaryNode =
false;
1006 return boundaryNode;
1009template <
class SC,
class LO,
class GO,
class NO,
class memory_space>
1010Kokkos::View<bool*, memory_space>
1012 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1013 const bool count_twos_as_dirichlet) {
1014 using impl_scalar_type =
typename KokkosKernels::ArithTraits<SC>::val_type;
1015 using ATS = KokkosKernels::ArithTraits<impl_scalar_type>;
1016 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
1017 using helpers = Xpetra::Helpers<SC, LO, GO, NO>;
1019 Kokkos::View<bool*, typename NO::device_type::memory_space> boundaryNodes;
1021 if (helpers::isTpetraBlockCrs(A)) {
1022 const Tpetra::BlockCrsMatrix<SC, LO, GO, NO>& Am = toTpetraBlock(A);
1023 auto b_graph = Am.getCrsGraph().getLocalGraphDevice();
1024 auto b_rowptr = Am.getCrsGraph().getLocalRowPtrsDevice();
1025 auto values = Am.getValuesDevice();
1026 LO numBlockRows = Am.getLocalNumRows();
1027 const LO stride = Am.getBlockSize() * Am.getBlockSize();
1029 boundaryNodes = Kokkos::View<bool*, typename NO::device_type::memory_space>(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), numBlockRows);
1031 if (count_twos_as_dirichlet)
1034 Kokkos::parallel_for(
1035 "MueLu:Utils::DetectDirichletRowsBlockCrs", range_type(0, numBlockRows),
1036 KOKKOS_LAMBDA(
const LO row) {
1037 auto rowView = b_graph.rowConst(row);
1038 auto length = rowView.length;
1039 LO valstart = b_rowptr[row] * stride;
1041 boundaryNodes(row) =
true;
1042 decltype(length) colID = 0;
1043 for (; colID < length; colID++) {
1044 if (rowView.colidx(colID) != row) {
1045 LO current = valstart + colID * stride;
1046 for (LO k = 0; k < stride; k++) {
1047 if (ATS::magnitude(values[current + k]) > tol) {
1048 boundaryNodes(row) =
false;
1053 if (boundaryNodes(row) ==
false)
1058 auto localMatrix = A.getLocalMatrixDevice();
1059 LO numRows = A.getLocalNumRows();
1060 boundaryNodes = Kokkos::View<bool*, typename NO::device_type::memory_space>(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), numRows);
1062 Kokkos::parallel_for(
1063 "MueLu:Utils::DetectDirichletRows", range_type(0, numRows),
1064 KOKKOS_LAMBDA(
const LO row) {
1065 auto rowView = localMatrix.rowConst(row);
1066 boundaryNodes(row) =
isDirichletRow(row, rowView, tol, count_twos_as_dirichlet);
1069 if constexpr (std::is_same<memory_space, typename NO::device_type::memory_space>::value)
1070 return boundaryNodes;
1072 Kokkos::View<bool*, memory_space> boundaryNodes2(Kokkos::ViewAllocateWithoutInitializing(
"boundaryNodes"), boundaryNodes.extent(0));
1073 Kokkos::deep_copy(boundaryNodes2, boundaryNodes);
1074 return boundaryNodes2;
1077 Kokkos::View<bool*, memory_space> dummy(
"dummy", 0);
1081template <
class SC,
class LO,
class GO,
class NO>
1082Kokkos::View<bool*, typename NO::device_type::memory_space>
1085 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1086 const bool count_twos_as_dirichlet) {
1087 return MueLu::DetectDirichletRows_kokkos<SC, LO, GO, NO, typename NO::device_type::memory_space>(A, tol, count_twos_as_dirichlet);
1090template <
class SC,
class LO,
class GO,
class NO>
1091Kokkos::View<bool*, typename Kokkos::HostSpace>
1094 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1095 const bool count_twos_as_dirichlet) {
1096 return MueLu::DetectDirichletRows_kokkos<SC, LO, GO, NO, typename Kokkos::HostSpace>(A, tol, count_twos_as_dirichlet);
1099template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1100Teuchos::ArrayRCP<const bool>
1102 DetectDirichletRowsExt(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
bool& bHasZeroDiagonal,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType& tol) {
1104 bHasZeroDiagonal =
false;
1106 Teuchos::RCP<Vector> diagVec = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(A.getRowMap());
1107 A.getLocalDiagCopy(*diagVec);
1108 Teuchos::ArrayRCP<const Scalar> diagVecData = diagVec->getData(0);
1111 typedef Teuchos::ScalarTraits<Scalar> STS;
1112 ArrayRCP<bool> boundaryNodes(numRows,
false);
1114 ArrayView<const LocalOrdinal> indices;
1115 ArrayView<const Scalar> vals;
1116 A.getLocalRowView(row, indices, vals);
1118 bool bHasDiag =
false;
1119 for (
decltype(indices.size()) col = 0; col < indices.size(); col++) {
1120 if (indices[col] != row) {
1121 if (STS::magnitude(vals[col] / STS::magnitude(sqrt(STS::magnitude(diagVecData[row]) * STS::magnitude(diagVecData[col])))) > tol) {
1127 if (bHasDiag ==
false)
1128 bHasZeroDiagonal =
true;
1130 boundaryNodes[row] =
true;
1132 return boundaryNodes;
1135template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1138 const Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>& RHS,
1139 Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>& InitialGuess,
1140 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
1141 const bool count_twos_as_dirichlet) {
1142 using range_type = Kokkos::RangePolicy<LO, typename Node::execution_space>;
1146 TEUCHOS_ASSERT_EQUALITY(numVectors, Teuchos::as<LocalOrdinal>(InitialGuess.getNumVectors()));
1148 TEUCHOS_ASSERT(RHS.getMap()->isCompatible(InitialGuess.getMap()));
1151 auto lclRHS = RHS.getLocalViewDevice(Tpetra::Access::ReadOnly);
1152 auto lclInitialGuess = InitialGuess.getLocalViewDevice(Tpetra::Access::ReadWrite);
1153 auto lclA = A.getLocalMatrixDevice();
1155 Kokkos::parallel_for(
1156 "MueLu:Utils::EnforceInitialCondition", range_type(0, numRows),
1157 KOKKOS_LAMBDA(
const LO i) {
1158 auto row = lclA.rowConst(i);
1161 lclInitialGuess(i, j) = lclRHS(i, j);
1166template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1168 FindNonZeros(
const Teuchos::ArrayRCP<const Scalar> vals,
1169 Teuchos::ArrayRCP<bool> nonzeros) {
1170 TEUCHOS_ASSERT(vals.size() == nonzeros.size());
1171 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType magnitudeType;
1172 const magnitudeType eps = 2.0 * Teuchos::ScalarTraits<magnitudeType>::eps();
1173 for (
size_t i = 0; i < static_cast<size_t>(vals.size()); i++) {
1174 nonzeros[i] = (Teuchos::ScalarTraits<Scalar>::magnitude(vals[i]) > eps);
1179template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1181 FindNonZeros(
const typename Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>::dual_view_type::t_dev_const_um vals,
1182 Kokkos::View<bool*, typename Node::device_type> nonzeros) {
1183 using ATS = KokkosKernels::ArithTraits<Scalar>;
1184 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1185 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1186 TEUCHOS_ASSERT(vals.extent(0) == nonzeros.extent(0));
1187 const typename ATS::magnitudeType eps = 2.0 * impl_ATS::eps();
1189 Kokkos::parallel_for(
1190 "MueLu:Maxwell1::FindNonZeros", range_type(0, vals.extent(0)),
1191 KOKKOS_LAMBDA(
const size_t i) {
1192 nonzeros(i) = (impl_ATS::magnitude(vals(i, 0)) > eps);
1196template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1199 const Teuchos::ArrayRCP<bool>& dirichletRows,
1200 Teuchos::ArrayRCP<bool> dirichletCols,
1201 Teuchos::ArrayRCP<bool> dirichletDomain) {
1202 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1203 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1204 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowMap = A.getRowMap();
1205 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1206 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == rowMap->getLocalNumElements());
1207 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletCols.size()) == colMap->getLocalNumElements());
1208 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletDomain.size()) == domMap->getLocalNumElements());
1209 RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, 1,
true);
1211 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1212 if (dirichletRows[i]) {
1213 ArrayView<const LocalOrdinal> indices;
1214 ArrayView<const Scalar> values;
1215 A.getLocalRowView(i, indices, values);
1216 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
1217 myColsToZero->replaceLocalValue(indices[j], 0, one);
1221 RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero;
1222 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A.getCrsGraph()->getImporter();
1223 if (!importer.is_null()) {
1224 globalColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap, 1,
true);
1226 globalColsToZero->doExport(*myColsToZero, *importer, Xpetra::ADD);
1228 myColsToZero->doImport(*globalColsToZero, *importer, Xpetra::INSERT);
1230 globalColsToZero = myColsToZero;
1232 FindNonZeros(globalColsToZero->getData(0), dirichletDomain);
1233 FindNonZeros(myColsToZero->getData(0), dirichletCols);
1236template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1239 const Kokkos::View<bool*, typename Node::device_type>& dirichletRows,
1240 Kokkos::View<bool*, typename Node::device_type> dirichletCols,
1241 Kokkos::View<bool*, typename Node::device_type> dirichletDomain) {
1242 using ATS = KokkosKernels::ArithTraits<Scalar>;
1243 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1244 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1245 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1246 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowMap = A.getRowMap();
1247 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1248 TEUCHOS_ASSERT(dirichletRows.extent(0) == rowMap->getLocalNumElements());
1249 TEUCHOS_ASSERT(dirichletCols.extent(0) == colMap->getLocalNumElements());
1250 TEUCHOS_ASSERT(dirichletDomain.extent(0) == domMap->getLocalNumElements());
1251 RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap,
true);
1253 auto myColsToZeroView = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadWrite);
1254 auto localMatrix = A.getLocalMatrixDevice();
1255 Kokkos::parallel_for(
1256 "MueLu:Maxwell1::DetectDirichletCols", range_type(0, rowMap->getLocalNumElements()),
1258 if (dirichletRows(row)) {
1259 auto rowView = localMatrix.row(row);
1260 auto length = rowView.length;
1262 for (
decltype(length) colID = 0; colID < length; colID++)
1263 myColsToZeroView(rowView.colidx(colID), 0) = impl_ATS::one();
1267 RCP<Xpetra::Vector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero;
1268 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A.getCrsGraph()->getImporter();
1269 if (!importer.is_null()) {
1270 globalColsToZero = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap,
true);
1272 globalColsToZero->doExport(*myColsToZero, *importer, Xpetra::ADD);
1274 myColsToZero->doImport(*globalColsToZero, *importer, Xpetra::INSERT);
1276 globalColsToZero = myColsToZero;
1281template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1283 ApplyRowSumCriterion(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol, Teuchos::ArrayRCP<bool>& dirichletRows) {
1284 typedef Teuchos::ScalarTraits<Scalar> STS;
1285 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1286 typedef Teuchos::ScalarTraits<MT> MTS;
1287 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1288 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1289 size_t nnz = A.getNumEntriesInLocalRow(row);
1290 ArrayView<const LocalOrdinal> indices;
1291 ArrayView<const Scalar> vals;
1292 A.getLocalRowView(row, indices, vals);
1294 Scalar rowsum = STS::zero();
1295 Scalar diagval = STS::zero();
1297 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1300 diagval = vals[colID];
1301 rowsum += vals[colID];
1304 if (rowSumTol < MTS::one() && STS::magnitude(rowsum) > STS::magnitude(diagval) * rowSumTol) {
1306 dirichletRows[row] =
true;
1311template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1312void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1313 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) {
1314 typedef Teuchos::ScalarTraits<Scalar> STS;
1315 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1316 typedef Teuchos::ScalarTraits<MT> MTS;
1317 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1319 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()), std::runtime_error,
"ApplyRowSumCriterion: BlockNumber must match's A's column map.");
1321 Teuchos::ArrayRCP<const LocalOrdinal> block_id = BlockNumber.getData(0);
1322 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1323 size_t nnz = A.getNumEntriesInLocalRow(row);
1324 ArrayView<const LocalOrdinal> indices;
1325 ArrayView<const Scalar> vals;
1326 A.getLocalRowView(row, indices, vals);
1328 Scalar rowsum = STS::zero();
1329 Scalar diagval = STS::zero();
1330 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1333 diagval = vals[colID];
1334 if (block_id[row] == block_id[col])
1335 rowsum += vals[colID];
1339 if (rowSumTol < MTS::one() && STS::magnitude(rowsum) > STS::magnitude(diagval) * rowSumTol) {
1341 dirichletRows[row] =
true;
1347template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node,
class memory_space>
1349 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1350 Kokkos::View<bool*, memory_space>& dirichletRows) {
1351 typedef Teuchos::ScalarTraits<Scalar> STS;
1352 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1354 auto dirichletRowsHost = Kokkos::create_mirror_view(dirichletRows);
1355 Kokkos::deep_copy(dirichletRowsHost, dirichletRows);
1357 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1358 size_t nnz = A.getNumEntriesInLocalRow(row);
1359 ArrayView<const LocalOrdinal> indices;
1360 ArrayView<const Scalar> vals;
1361 A.getLocalRowView(row, indices, vals);
1363 Scalar rowsum = STS::zero();
1364 Scalar diagval = STS::zero();
1365 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1368 diagval = vals[colID];
1369 rowsum += vals[colID];
1371 if (STS::real(rowsum) > STS::magnitude(diagval) * rowSumTol)
1372 dirichletRowsHost(row) =
true;
1375 Kokkos::deep_copy(dirichletRows, dirichletRowsHost);
1378template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1379void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1380 ApplyRowSumCriterion(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1381 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1382 Kokkos::View<bool*, typename Node::device_type::memory_space>& dirichletRows) {
1383 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, typename Node::device_type::memory_space>(A, rowSumTol, dirichletRows);
1386template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1387void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1388 ApplyRowSumCriterionHost(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1389 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1390 Kokkos::View<bool*, Kokkos::HostSpace>& dirichletRows) {
1391 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, Kokkos::HostSpace>(A, rowSumTol, dirichletRows);
1395template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node,
class memory_space>
1397 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1398 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1399 Kokkos::View<bool*, memory_space>& dirichletRows) {
1400 typedef Teuchos::ScalarTraits<Scalar> STS;
1401 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> rowmap = A.getRowMap();
1403 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()), std::runtime_error,
"ApplyRowSumCriterion: BlockNumber must match's A's column map.");
1405 auto dirichletRowsHost = Kokkos::create_mirror_view(dirichletRows);
1406 Kokkos::deep_copy(dirichletRowsHost, dirichletRows);
1408 Teuchos::ArrayRCP<const LocalOrdinal> block_id = BlockNumber.getData(0);
1409 for (
LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1410 size_t nnz = A.getNumEntriesInLocalRow(row);
1411 ArrayView<const LocalOrdinal> indices;
1412 ArrayView<const Scalar> vals;
1413 A.getLocalRowView(row, indices, vals);
1415 Scalar rowsum = STS::zero();
1416 Scalar diagval = STS::zero();
1417 for (
LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1420 diagval = vals[colID];
1421 if (block_id[row] == block_id[col])
1422 rowsum += vals[colID];
1424 if (STS::real(rowsum) > STS::magnitude(diagval) * rowSumTol)
1425 dirichletRowsHost(row) =
true;
1428 Kokkos::deep_copy(dirichletRows, dirichletRowsHost);
1431template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1432void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1433 ApplyRowSumCriterion(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1434 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1435 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1436 Kokkos::View<bool*, typename Node::device_type::memory_space>& dirichletRows) {
1437 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, typename Node::device_type::memory_space>(A, BlockNumber, rowSumTol, dirichletRows);
1440template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1441void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1442 ApplyRowSumCriterionHost(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
1443 const Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>& BlockNumber,
1444 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1445 Kokkos::View<bool*, Kokkos::HostSpace>& dirichletRows) {
1446 MueLu::ApplyRowSumCriterion<Scalar, LocalOrdinal, GlobalOrdinal, Node, Kokkos::HostSpace>(A, BlockNumber, rowSumTol, dirichletRows);
1449template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1450Teuchos::ArrayRCP<const bool>
1453 const Teuchos::ArrayRCP<const bool>& dirichletRows) {
1454 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1455 Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1456 Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A.getDomainMap();
1457 Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> colMap = A.getColMap();
1458 Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> myColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, 1);
1459 myColsToZero->putScalar(zero);
1461 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1462 if (dirichletRows[i]) {
1463 Teuchos::ArrayView<const LocalOrdinal> indices;
1464 Teuchos::ArrayView<const Scalar> values;
1465 A.getLocalRowView(i, indices, values);
1466 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
1467 myColsToZero->replaceLocalValue(indices[j], 0, one);
1471 Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> globalColsToZero = Xpetra::MultiVectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(domMap, 1);
1472 globalColsToZero->putScalar(zero);
1473 Teuchos::RCP<Xpetra::Export<LocalOrdinal, GlobalOrdinal, Node>> exporter = Xpetra::ExportFactory<LocalOrdinal, GlobalOrdinal, Node>::Build(colMap, domMap);
1475 globalColsToZero->doExport(*myColsToZero, *exporter, Xpetra::ADD);
1477 myColsToZero->doImport(*globalColsToZero, *exporter, Xpetra::INSERT);
1478 Teuchos::ArrayRCP<const Scalar> myCols = myColsToZero->getData(0);
1479 Teuchos::ArrayRCP<bool> dirichletCols(colMap->getLocalNumElements(),
true);
1480 Magnitude eps = Teuchos::ScalarTraits<Magnitude>::eps();
1481 for (
size_t i = 0; i < colMap->getLocalNumElements(); i++) {
1482 dirichletCols[i] = Teuchos::ScalarTraits<Scalar>::magnitude(myCols[i]) > 2.0 * eps;
1484 return dirichletCols;
1487template <
class SC,
class LO,
class GO,
class NO>
1488Kokkos::View<bool*, typename NO::device_type>
1491 const Kokkos::View<const bool*, typename NO::device_type>& dirichletRows) {
1492 using ATS = KokkosKernels::ArithTraits<SC>;
1493 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1494 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
1496 SC zero = ATS::zero();
1498 auto localMatrix = A.getLocalMatrixDevice();
1499 LO numRows = A.getLocalNumRows();
1501 Teuchos::RCP<const Xpetra::Map<LO, GO, NO>> domMap = A.getDomainMap();
1502 Teuchos::RCP<const Xpetra::Map<LO, GO, NO>> colMap = A.getColMap();
1503 Teuchos::RCP<Xpetra::MultiVector<SC, LO, GO, NO>> myColsToZero = Xpetra::MultiVectorFactory<SC, LO, GO, NO>::Build(colMap, 1);
1504 myColsToZero->putScalar(zero);
1505 auto myColsToZeroView = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadWrite);
1507 Kokkos::parallel_for(
1508 "MueLu:Utils::DetectDirichletCols1", range_type(0, numRows),
1509 KOKKOS_LAMBDA(
const LO row) {
1510 if (dirichletRows(row)) {
1511 auto rowView = localMatrix.row(row);
1512 auto length = rowView.length;
1514 for (
decltype(length) colID = 0; colID < length; colID++)
1515 myColsToZeroView(rowView.colidx(colID), 0) = impl_ATS::one();
1519 Teuchos::RCP<Xpetra::MultiVector<SC, LO, GO, NO>> globalColsToZero = Xpetra::MultiVectorFactory<SC, LO, GO, NO>::Build(domMap, 1);
1520 globalColsToZero->putScalar(zero);
1521 Teuchos::RCP<Xpetra::Export<LO, GO, NO>> exporter = Xpetra::ExportFactory<LO, GO, NO>::Build(colMap, domMap);
1523 globalColsToZero->doExport(*myColsToZero, *exporter, Xpetra::ADD);
1525 myColsToZero->doImport(*globalColsToZero, *exporter, Xpetra::INSERT);
1527 auto myCols = myColsToZero->getLocalViewDevice(Tpetra::Access::ReadOnly);
1528 size_t numColEntries = colMap->getLocalNumElements();
1529 Kokkos::View<bool*, typename NO::device_type> dirichletCols(Kokkos::ViewAllocateWithoutInitializing(
"dirichletCols"), numColEntries);
1530 const typename ATS::magnitudeType eps = 2.0 * ATS::eps();
1532 Kokkos::parallel_for(
1533 "MueLu:Utils::DetectDirichletCols2", range_type(0, numColEntries),
1534 KOKKOS_LAMBDA(
const size_t i) {
1535 dirichletCols(i) = impl_ATS::magnitude(myCols(i, 0)) > eps;
1537 return dirichletCols;
1540template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1543 Frobenius(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& B) {
1548 TEUCHOS_TEST_FOR_EXCEPTION(!A.getRowMap()->isSameAs(*B.getRowMap()),
Exceptions::Incompatible,
"MueLu::CGSolver::Frobenius: row maps are incompatible");
1549 TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete() || !B.isFillComplete(),
Exceptions::RuntimeError,
"Matrices must be fill completed");
1551 const Map& AColMap = *A.getColMap();
1552 const Map& BColMap = *B.getColMap();
1554 Teuchos::ArrayView<const LocalOrdinal> indA, indB;
1555 Teuchos::ArrayView<const Scalar> valA, valB;
1556 size_t nnzA = 0, nnzB = 0;
1568 Teuchos::Array<Scalar> valBAll(BColMap.getLocalNumElements());
1570 LocalOrdinal invalid = Teuchos::OrdinalTraits<LocalOrdinal>::invalid();
1571 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero(), f = zero, gf;
1572 size_t numRows = A.getLocalNumRows();
1573 for (
size_t i = 0; i < numRows; i++) {
1574 A.getLocalRowView(i, indA, valA);
1575 B.getLocalRowView(i, indB, valB);
1580 for (
size_t j = 0; j < nnzB; j++)
1581 valBAll[indB[j]] = valB[j];
1583 for (
size_t j = 0; j < nnzA; j++) {
1586 LocalOrdinal ind = BColMap.getLocalElement(AColMap.getGlobalElement(indA[j]));
1588 f += valBAll[ind] * valA[j];
1592 for (
size_t j = 0; j < nnzB; j++)
1593 valBAll[indB[j]] = zero;
1601template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1609 int maxint = INT_MAX;
1610 int mySeed = Teuchos::as<int>((maxint - 1) * (one - (comm.getRank() + 1) / (comm.getSize() + one)));
1611 if (mySeed < 1 || mySeed == maxint) {
1612 std::ostringstream errStr;
1613 errStr <<
"Error detected with random seed = " << mySeed <<
". It should be in the interval [1,2^31-2].";
1618 Teuchos::ScalarTraits<Scalar>::seedrandom(mySeed);
1625template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1627 FindDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1628 std::vector<LocalOrdinal>& dirichletRows,
bool count_twos_as_dirichlet) {
1629 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1630 dirichletRows.resize(0);
1631 for (
size_t i = 0; i < A->getLocalNumRows(); i++) {
1632 Teuchos::ArrayView<const LocalOrdinal> indices;
1633 Teuchos::ArrayView<const Scalar> values;
1634 A->getLocalRowView(i, indices, values);
1636 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1637 if (Teuchos::ScalarTraits<Scalar>::magnitude(values[j]) > Teuchos::ScalarTraits<MT>::eps()) {
1641 if (nnz == 1 || (count_twos_as_dirichlet && nnz == 2)) {
1642 dirichletRows.push_back(i);
1647template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1649 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1650 const std::vector<LocalOrdinal>& dirichletRows) {
1651 RCP<const Map> Rmap = A->getRowMap();
1652 RCP<const Map> Cmap = A->getColMap();
1653 Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1654 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1656 for (
size_t i = 0; i < dirichletRows.size(); i++) {
1657 GlobalOrdinal row_gid = Rmap->getGlobalElement(dirichletRows[i]);
1659 Teuchos::ArrayView<const LocalOrdinal> indices;
1660 Teuchos::ArrayView<const Scalar> values;
1661 A->getLocalRowView(dirichletRows[i], indices, values);
1663 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1664 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1665 if (Cmap->getGlobalElement(indices[j]) == row_gid)
1673template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1675 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1676 const Teuchos::ArrayRCP<const bool>& dirichletRows) {
1677 TEUCHOS_ASSERT(A->isFillComplete());
1678 RCP<const Map> domMap = A->getDomainMap();
1679 RCP<const Map> ranMap = A->getRangeMap();
1680 RCP<const Map> Rmap = A->getRowMap();
1681 RCP<const Map> Cmap = A->getColMap();
1682 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == Rmap->getLocalNumElements());
1683 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1684 const Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1686 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1687 if (dirichletRows[i]) {
1690 Teuchos::ArrayView<const LocalOrdinal> indices;
1691 Teuchos::ArrayView<const Scalar> values;
1692 A->getLocalRowView(i, indices, values);
1694 Teuchos::ArrayRCP<Scalar> valuesNC(values.size());
1695 for (
size_t j = 0; j < (size_t)indices.size(); j++) {
1696 if (Cmap->getGlobalElement(indices[j]) == row_gid)
1701 A->replaceLocalValues(i, indices, valuesNC());
1704 A->fillComplete(domMap, ranMap);
1707template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1709 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1710 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows) {
1711 TEUCHOS_ASSERT(A->isFillComplete());
1712 using ATS = KokkosKernels::ArithTraits<Scalar>;
1713 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
1714 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1716 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> domMap = A->getDomainMap();
1717 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> ranMap = A->getRangeMap();
1718 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> Rmap = A->getRowMap();
1719 RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> Cmap = A->getColMap();
1721 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == Rmap->getLocalNumElements());
1723 auto localMatrix = A->getLocalMatrixDevice();
1724 auto localRmap = Rmap->getLocalMap();
1725 auto localCmap = Cmap->getLocalMap();
1727 Kokkos::parallel_for(
1728 "MueLu::Utils::ApplyOAZ", range_type(0, dirichletRows.extent(0)),
1730 if (dirichletRows(row)) {
1731 auto rowView = localMatrix.row(row);
1732 auto length = rowView.length;
1733 auto row_gid = localRmap.getGlobalElement(row);
1734 auto row_lid = localCmap.getLocalElement(row_gid);
1736 for (
decltype(length) colID = 0; colID < length; colID++)
1737 if (rowView.colidx(colID) == row_lid)
1738 rowView.value(colID) = impl_ATS::one();
1740 rowView.value(colID) = impl_ATS::zero();
1745template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1747 ZeroDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1748 const std::vector<LocalOrdinal>& dirichletRows,
1750 for (
size_t i = 0; i < dirichletRows.size(); i++) {
1751 Teuchos::ArrayView<const LocalOrdinal> indices;
1752 Teuchos::ArrayView<const Scalar> values;
1753 A->getLocalRowView(dirichletRows[i], indices, values);
1755 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1756 for (
size_t j = 0; j < (size_t)indices.size(); j++)
1757 valuesNC[j] = replaceWith;
1761template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1763 ZeroDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1764 const Teuchos::ArrayRCP<const bool>& dirichletRows,
1766 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == A->getRowMap()->getLocalNumElements());
1767 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1768 if (dirichletRows[i]) {
1769 Teuchos::ArrayView<const LocalOrdinal> indices;
1770 Teuchos::ArrayView<const Scalar> values;
1771 A->getLocalRowView(i, indices, values);
1773 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1774 for (
size_t j = 0; j < (size_t)indices.size(); j++)
1775 valuesNC[j] = replaceWith;
1780template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1782 ZeroDirichletRows(Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& X,
1783 const Teuchos::ArrayRCP<const bool>& dirichletRows,
1785 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletRows.size()) == X->getMap()->getLocalNumElements());
1786 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1787 if (dirichletRows[i]) {
1788 for (
size_t j = 0; j < X->getNumVectors(); j++)
1789 X->replaceLocalValue(i, j, replaceWith);
1794template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1796 ZeroDirichletRows(RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1797 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows,
1799 using ATS = KokkosKernels::ArithTraits<Scalar>;
1800 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1802 typename ATS::val_type impl_replaceWith = replaceWith;
1804 auto localMatrix = A->getLocalMatrixDevice();
1807 Kokkos::parallel_for(
1808 "MueLu:Utils::ZeroDirichletRows", range_type(0, numRows),
1810 if (dirichletRows(row)) {
1811 auto rowView = localMatrix.row(row);
1812 auto length = rowView.length;
1813 for (
decltype(length) colID = 0; colID < length; colID++)
1814 rowView.value(colID) = impl_replaceWith;
1819template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1820void UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
1821 ZeroDirichletRows(RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& X,
1822 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows,
1824 using ATS = KokkosKernels::ArithTraits<Scalar>;
1825 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1827 typename ATS::val_type impl_replaceWith = replaceWith;
1829 auto myCols = X->getLocalViewDevice(Tpetra::Access::ReadWrite);
1830 size_t numVecs = X->getNumVectors();
1831 Kokkos::parallel_for(
1832 "MueLu:Utils::ZeroDirichletRows_MV", range_type(0, dirichletRows.size()),
1833 KOKKOS_LAMBDA(
const size_t i) {
1834 if (dirichletRows(i)) {
1835 for (
size_t j = 0; j < numVecs; j++)
1836 myCols(i, j) = impl_replaceWith;
1841template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1844 const Teuchos::ArrayRCP<const bool>& dirichletCols,
1846 TEUCHOS_ASSERT(
static_cast<size_t>(dirichletCols.size()) == A->getColMap()->getLocalNumElements());
1847 for (
size_t i = 0; i < A->getLocalNumRows(); i++) {
1848 Teuchos::ArrayView<const LocalOrdinal> indices;
1849 Teuchos::ArrayView<const Scalar> values;
1850 A->getLocalRowView(i, indices, values);
1852 Scalar* valuesNC =
const_cast<Scalar*
>(values.getRawPtr());
1853 for (
size_t j = 0; j < static_cast<size_t>(indices.size()); j++)
1854 if (dirichletCols[indices[j]])
1855 valuesNC[j] = replaceWith;
1859template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1861 ZeroDirichletCols(RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
1862 const Kokkos::View<const bool*, typename Node::device_type>& dirichletCols,
1864 using ATS = KokkosKernels::ArithTraits<Scalar>;
1865 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1867 typename ATS::val_type impl_replaceWith = replaceWith;
1869 auto localMatrix = A->getLocalMatrixDevice();
1872 Kokkos::parallel_for(
1873 "MueLu:Utils::ZeroDirichletCols", range_type(0, numRows),
1875 auto rowView = localMatrix.row(row);
1876 auto length = rowView.length;
1877 for (
decltype(length) colID = 0; colID < length; colID++)
1878 if (dirichletCols(rowView.colidx(colID))) {
1879 rowView.value(colID) = impl_replaceWith;
1884template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1887 Teuchos::RCP<Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node>>& isDirichletRow,
1888 Teuchos::RCP<Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node>>& isDirichletCol) {
1890 if (!A->getRowMap()->isSameAs(*A->getDomainMap())) {
1891 throw std::runtime_error(
"UtilitiesBase::FindDirichletRowsAndPropagateToCols row and domain maps must match.");
1893 RCP<const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>> importer = A->getCrsGraph()->getImporter();
1894 bool has_import = !importer.is_null();
1897 std::vector<LocalOrdinal> dirichletRows;
1898 FindDirichletRows(A, dirichletRows);
1901 printf(
"[%d] DirichletRow Ids = ",A->getRowMap()->getComm()->getRank());
1902 for(
size_t i=0; i<(size_t) dirichletRows.size(); i++)
1903 printf(
"%d ",dirichletRows[i]);
1908 isDirichletRow = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(A->getRowMap(),
true);
1909 isDirichletCol = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(A->getColMap(),
true);
1912 Teuchos::ArrayRCP<int> dr_rcp =
isDirichletRow->getDataNonConst(0);
1913 Teuchos::ArrayView<int> dr = dr_rcp();
1914 Teuchos::ArrayRCP<int> dc_rcp = isDirichletCol->getDataNonConst(0);
1915 Teuchos::ArrayView<int> dc = dc_rcp();
1916 for (
size_t i = 0; i < (size_t)dirichletRows.size(); i++) {
1917 dr[dirichletRows[i]] = 1;
1918 if (!has_import) dc[dirichletRows[i]] = 1;
1923 isDirichletCol->doImport(*
isDirichletRow, *importer, Xpetra::CombineMode::ADD);
1926template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1927RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
1930 using ISC =
typename KokkosKernels::ArithTraits<Scalar>::val_type;
1931 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1932 using local_matrix_type =
typename CrsMatrix::local_matrix_device_type;
1933 using values_type =
typename local_matrix_type::values_type;
1935 const ISC ONE = KokkosKernels::ArithTraits<ISC>::one();
1936 const ISC ZERO = KokkosKernels::ArithTraits<ISC>::zero();
1939 auto localMatrix = original->getLocalMatrixDevice();
1940 TEUCHOS_TEST_FOR_EXCEPTION(!original->hasCrsGraph(),
Exceptions::RuntimeError,
"ReplaceNonZerosWithOnes: Cannot get CrsGraph");
1941 values_type new_values(
"values", localMatrix.nnz());
1943 Kokkos::parallel_for(
1944 "ReplaceNonZerosWithOnes", range_type(0, localMatrix.nnz()), KOKKOS_LAMBDA(
const size_t i) {
1945 if (localMatrix.values(i) != ZERO)
1946 new_values(i) = ONE;
1948 new_values(i) = ZERO;
1952 RCP<Matrix> NewMatrix = Xpetra::MatrixFactory<SC, LO, GO, NO>::Build(original->getCrsGraph(), new_values);
1953 TEUCHOS_TEST_FOR_EXCEPTION(NewMatrix.is_null(),
Exceptions::RuntimeError,
"ReplaceNonZerosWithOnes: MatrixFactory::Build() did not return matrix");
1954 NewMatrix->fillComplete(original->getDomainMap(), original->getRangeMap());
1958template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
1959RCP<const Xpetra::BlockedMap<LocalOrdinal, GlobalOrdinal, Node>>
1962 const Xpetra::Import<LocalOrdinal, GlobalOrdinal, Node>& Importer) {
1963 typedef Xpetra::Vector<int, LocalOrdinal, GlobalOrdinal, Node> IntVector;
1964 Xpetra::UnderlyingLib lib = sourceBlockedMap.lib();
1967 RCP<const Map> fullMap = sourceBlockedMap.getMap();
1968 RCP<const Map> stridedMap = Teuchos::rcp_dynamic_cast<const Xpetra::StridedMap<LocalOrdinal, GlobalOrdinal, Node>>(fullMap);
1969 if (!stridedMap.is_null()) fullMap = stridedMap->getMap();
1972 const size_t numSubMaps = sourceBlockedMap.getNumMaps();
1973 if (!Importer.getSourceMap()->isCompatible(*fullMap))
1974 throw std::runtime_error(
"GenerateBlockedTargetMap(): Map compatibility error");
1977 RCP<IntVector> block_ids = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(fullMap);
1979 for (
size_t i = 0; i < numSubMaps; i++) {
1980 RCP<const Map> map = sourceBlockedMap.getMap(i);
1982 for (
size_t j = 0; j < map->getLocalNumElements(); j++) {
1983 LocalOrdinal jj = fullMap->getLocalElement(map->getGlobalElement(j));
1984 block_ids->replaceLocalValue(jj, (
int)i);
1989 RCP<const Map> targetMap = Importer.getTargetMap();
1990 RCP<IntVector> new_block_ids = Xpetra::VectorFactory<int, LocalOrdinal, GlobalOrdinal, Node>::Build(targetMap);
1991 new_block_ids->doImport(*block_ids, Importer, Xpetra::CombineMode::ADD);
1992 Teuchos::ArrayRCP<const int> dataRCP = new_block_ids->getData(0);
1993 Teuchos::ArrayView<const int> data = dataRCP();
1996 Teuchos::Array<Teuchos::Array<GlobalOrdinal>> elementsInSubMap(numSubMaps);
1997 for (
size_t i = 0; i < targetMap->getLocalNumElements(); i++) {
1998 elementsInSubMap[data[i]].push_back(targetMap->getGlobalElement(i));
2002 std::vector<RCP<const Map>> subMaps(numSubMaps);
2003 for (
size_t i = 0; i < numSubMaps; i++) {
2004 subMaps[i] = Xpetra::MapFactory<LocalOrdinal, GlobalOrdinal, Node>::Build(lib, Teuchos::OrdinalTraits<GlobalOrdinal>::invalid(), elementsInSubMap[i](), targetMap->getIndexBase(), targetMap->getComm());
2008 return rcp(
new BlockedMap(targetMap, subMaps));
2011template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2013 MapsAreNested(
const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& rowMap,
const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& colMap) {
2014 if ((rowMap.lib() == Xpetra::UseTpetra) && (colMap.lib() == Xpetra::UseTpetra)) {
2015 auto tpRowMap = toTpetra(rowMap);
2016 auto tpColMap = toTpetra(colMap);
2017 return tpColMap.isLocallyFitted(tpRowMap);
2020 ArrayView<const GlobalOrdinal> rowElements = rowMap.getLocalElementList();
2021 ArrayView<const GlobalOrdinal> colElements = colMap.getLocalElementList();
2023 const size_t numElements = rowElements.size();
2025 if (
size_t(colElements.size()) < numElements)
2028 bool goodMap =
true;
2029 for (
size_t i = 0; i < numElements; i++)
2030 if (rowElements[i] != colElements[i]) {
2038template <
class Scalar,
class LocalOrdinal,
class GlobalOrdinal,
class Node>
2039Teuchos::RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>>
2041 ReverseCuthillMcKee(
const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& Op) {
2042 using local_matrix_type =
typename Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::local_matrix_device_type;
2043 using local_graph_type =
typename local_matrix_type::staticcrsgraph_type;
2044 using lno_nnz_view_t =
typename local_graph_type::entries_type::non_const_type;
2045 using device =
typename local_graph_type::device_type;
2046 using execution_space =
typename local_matrix_type::execution_space;
2047 using ordinal_type =
typename local_matrix_type::ordinal_type;
2049 local_graph_type localGraph = Op.getLocalMatrixDevice().graph;
2051 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);
2053 RCP<Xpetra::Vector<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>> retval =
2054 Xpetra::VectorFactory<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(Op.getRowMap());
2057 auto view1D = Kokkos::subview(retval->getLocalViewDevice(Tpetra::Access::ReadWrite), Kokkos::ALL(), 0);
2058 Kokkos::parallel_for(
2059 "Utilities::ReverseCuthillMcKee",
2060 Kokkos::RangePolicy<ordinal_type, execution_space>(0, localGraph.numRows()),
2061 KOKKOS_LAMBDA(
const ordinal_type rowIdx) {
2062 view1D(rcmOrder(rowIdx)) = rowIdx;