721 using Teuchos::rcp_const_cast;
722 using Teuchos::rcp_dynamic_cast;
723 using Teuchos::Array;
724 using Teuchos::ArrayView;
725 const char prefix[] =
"Ifpack2::RILUK::compute: ";
730 TEUCHOS_TEST_FOR_EXCEPTION
731 (A_.is_null (), std::runtime_error, prefix <<
"The matrix is null. Please "
732 "call setMatrix() with a nonnull input before calling this method.");
733 TEUCHOS_TEST_FOR_EXCEPTION
734 (! A_->isFillComplete (), std::runtime_error, prefix <<
"The matrix is not "
735 "fill complete. You may not invoke initialize() or compute() with this "
736 "matrix until the matrix is fill complete. If your matrix is a "
737 "Tpetra::CrsMatrix, please call fillComplete on it (with the domain and "
738 "range Maps, if appropriate) before calling this method.");
740 if (! isInitialized ()) {
744 Teuchos::Time timer (
"RILUK::compute");
747 Teuchos::TimeMonitor timeMon (timer);
748 double startTime = timer.wallTime();
752 if (!this->isKokkosKernelsSpiluk_) {
755 initAllValues (*A_local_);
761 const scalar_type MaxDiagonalValue = STS::one () / MinDiagonalValue;
763 size_t NumIn, NumL, NumU;
766 const size_t MaxNumEntries =
767 L_->getNodeMaxNumRowEntries () + U_->getNodeMaxNumRowEntries () + 1;
769 Teuchos::Array<local_ordinal_type> InI(MaxNumEntries);
770 Teuchos::Array<scalar_type> InV(MaxNumEntries);
771 size_t num_cols = U_->getColMap()->getNodeNumElements();
772 Teuchos::Array<int> colflag(num_cols);
774 auto DV = Kokkos::subview(D_->getLocalViewHost(Tpetra::Access::ReadWrite), Kokkos::ALL(), 0);
778 for (
size_t j = 0; j < num_cols; ++j) {
781 using IST =
typename row_matrix_type::impl_scalar_type;
782 for (
size_t i = 0; i < L_->getNodeNumRows (); ++i) {
786 local_inds_host_view_type UUI;
787 values_host_view_type UUV;
791 NumIn = MaxNumEntries;
792 nonconst_local_inds_host_view_type InI_v(InI.data(),MaxNumEntries);
793 nonconst_values_host_view_type InV_v(
reinterpret_cast<IST*
>(InV.data()),MaxNumEntries);
795 L_->getLocalRowCopy (local_row, InI_v , InV_v, NumL);
798 InI[NumL] = local_row;
800 nonconst_local_inds_host_view_type InI_sub(InI.data()+NumL+1,MaxNumEntries-NumL-1);
801 nonconst_values_host_view_type InV_sub(
reinterpret_cast<IST*
>(InV.data())+NumL+1,MaxNumEntries-NumL-1);
803 U_->getLocalRowCopy (local_row, InI_sub,InV_sub, NumU);
807 for (
size_t j = 0; j < NumIn; ++j) {
813 for (
size_t jj = 0; jj < NumL; ++jj) {
815 IST multiplier = InV[jj];
819 U_->getLocalRowView(j, UUI, UUV);
822 if (RelaxValue_ == STM::zero ()) {
823 for (
size_t k = 0; k < NumUU; ++k) {
824 const int kk = colflag[UUI[k]];
829 InV[kk] -=
static_cast<scalar_type>(multiplier * UUV[k]);
835 for (
size_t k = 0; k < NumUU; ++k) {
839 const int kk = colflag[UUI[k]];
841 InV[kk] -=
static_cast<scalar_type>(multiplier*UUV[k]);
844 diagmod -=
static_cast<scalar_type>(multiplier*UUV[k]);
852 L_->replaceLocalValues (local_row, InI (0, NumL), InV (0, NumL));
857 if (RelaxValue_ != STM::zero ()) {
858 DV(i) += RelaxValue_*diagmod;
861 if (STS::magnitude (DV(i)) > STS::magnitude (MaxDiagonalValue)) {
862 if (STS::real (DV(i)) < STM::zero ()) {
863 DV(i) = -MinDiagonalValue;
866 DV(i) = MinDiagonalValue;
873 for (
size_t j = 0; j < NumU; ++j) {
879 U_->replaceLocalValues (local_row, InI (NumL+1, NumU), InV (NumL+1, NumU));
883 for (
size_t j = 0; j < NumIn; ++j) {
884 colflag[InI[j]] = -1;
895 L_->fillComplete (L_->getColMap (), A_local_->getRangeMap ());
896 U_->fillComplete (A_local_->getDomainMap (), U_->getRowMap ());
899 L_solver_->setMatrix (L_);
900 L_solver_->compute ();
901 U_solver_->setMatrix (U_);
902 U_solver_->compute ();
906 RCP<const crs_matrix_type> A_local_crs =
907 rcp_dynamic_cast<const crs_matrix_type> (A_local_);
908 if (A_local_crs.is_null ()) {
910 Array<size_t> entriesPerRow(numRows);
912 entriesPerRow[i] = A_local_->getNumEntriesInLocalRow(i);
914 RCP<crs_matrix_type> A_local_crs_nc =
916 A_local_->getColMap (),
919 nonconst_local_inds_host_view_type indices(
"indices",A_local_->getNodeMaxNumRowEntries());
920 nonconst_values_host_view_type values(
"values",A_local_->getNodeMaxNumRowEntries());
922 size_t numEntries = 0;
923 A_local_->getLocalRowCopy(i, indices, values, numEntries);
924 A_local_crs_nc->insertLocalValues(i, numEntries,
reinterpret_cast<scalar_type*
>(values.data()),indices.data());
926 A_local_crs_nc->fillComplete (A_local_->getDomainMap (), A_local_->getRangeMap ());
927 A_local_crs = rcp_const_cast<const crs_matrix_type> (A_local_crs_nc);
929 A_local_rowmap_ = A_local_crs->getLocalMatrixDevice().graph.row_map;
930 A_local_entries_ = A_local_crs->getLocalMatrixDevice().graph.entries;
931 A_local_values_ = A_local_crs->getLocalValuesView();
937 if (L_->isStaticGraph () || L_->isLocallyIndexed ()) {
938 L_->setAllToScalar (STS::zero ());
939 U_->setAllToScalar (STS::zero ());
942 using row_map_type =
typename crs_matrix_type::local_matrix_device_type::row_map_type;
944 row_map_type L_rowmap = L_->getLocalMatrixDevice().graph.row_map;
945 auto L_entries = L_->getLocalMatrixDevice().graph.entries;
946 auto L_values = L_->getLocalValuesView();
947 row_map_type U_rowmap = U_->getLocalMatrixDevice().graph.row_map;
948 auto U_entries = U_->getLocalMatrixDevice().graph.entries;
949 auto U_values = U_->getLocalValuesView();
951 KokkosSparse::Experimental::spiluk_numeric( KernelHandle_.getRawPtr(), LevelOfFill_,
952 A_local_rowmap_, A_local_entries_, A_local_values_,
953 L_rowmap, L_entries, L_values, U_rowmap, U_entries, U_values );
955 L_->fillComplete (L_->getColMap (), A_local_->getRangeMap ());
956 U_->fillComplete (A_local_->getDomainMap (), U_->getRowMap ());
958 L_solver_->setMatrix (L_);
959 L_solver_->compute ();
960 U_solver_->setMatrix (U_);
961 U_solver_->compute ();
966 computeTime_ += (timer.wallTime() - startTime);
973apply (
const Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type>& X,
974 Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type>& Y,
975 Teuchos::ETransp mode,
980 using Teuchos::rcpFromRef;
982 TEUCHOS_TEST_FOR_EXCEPTION(
983 A_.is_null (), std::runtime_error,
"Ifpack2::RILUK::apply: The matrix is "
984 "null. Please call setMatrix() with a nonnull input, then initialize() "
985 "and compute(), before calling this method.");
986 TEUCHOS_TEST_FOR_EXCEPTION(
987 ! isComputed (), std::runtime_error,
988 "Ifpack2::RILUK::apply: If you have not yet called compute(), "
989 "you must call compute() before calling this method.");
990 TEUCHOS_TEST_FOR_EXCEPTION(
991 X.getNumVectors () != Y.getNumVectors (), std::invalid_argument,
992 "Ifpack2::RILUK::apply: X and Y do not have the same number of columns. "
993 "X.getNumVectors() = " << X.getNumVectors ()
994 <<
" != Y.getNumVectors() = " << Y.getNumVectors () <<
".");
995 TEUCHOS_TEST_FOR_EXCEPTION(
996 STS::isComplex && mode == Teuchos::CONJ_TRANS, std::logic_error,
997 "Ifpack2::RILUK::apply: mode = Teuchos::CONJ_TRANS is not implemented for "
998 "complex Scalar type. Please talk to the Ifpack2 developers to get this "
999 "fixed. There is a FIXME in this file about this very issue.");
1000#ifdef HAVE_IFPACK2_DEBUG
1003 TEUCHOS_TEST_FOR_EXCEPTION( STM::isnaninf (D_nrm1), std::runtime_error,
"Ifpack2::RILUK::apply: The 1-norm of the stored diagonal is NaN or Inf.");
1004 Teuchos::Array<magnitude_type> norms (X.getNumVectors ());
1007 for (
size_t j = 0; j < X.getNumVectors (); ++j) {
1008 if (STM::isnaninf (norms[j])) {
1013 TEUCHOS_TEST_FOR_EXCEPTION( ! good, std::runtime_error,
"Ifpack2::RILUK::apply: The 1-norm of the input X is NaN or Inf.");
1020 Teuchos::Time timer (
"RILUK::apply");
1021 double startTime = timer.wallTime();
1023 Teuchos::TimeMonitor timeMon (timer);
1024 if (alpha == one && beta == zero) {
1025 if (mode == Teuchos::NO_TRANS) {
1027 L_solver_->apply (X, Y, mode);
1029 if (!this->isKokkosKernelsSpiluk_) {
1032 Y.elementWiseMultiply (one, *D_, Y, zero);
1035 U_solver_->apply (Y, Y, mode);
1039 U_solver_->apply (X, Y, mode);
1041 if (!this->isKokkosKernelsSpiluk_) {
1047 Y.elementWiseMultiply (one, *D_, Y, zero);
1050 L_solver_->apply (Y, Y, mode);
1054 if (alpha == zero) {
1064 MV Y_tmp (Y.getMap (), Y.getNumVectors ());
1065 apply (X, Y_tmp, mode);
1066 Y.update (alpha, Y_tmp, beta);
1071#ifdef HAVE_IFPACK2_DEBUG
1073 Teuchos::Array<magnitude_type> norms (Y.getNumVectors ());
1076 for (
size_t j = 0; j < Y.getNumVectors (); ++j) {
1077 if (STM::isnaninf (norms[j])) {
1082 TEUCHOS_TEST_FOR_EXCEPTION( ! good, std::runtime_error,
"Ifpack2::RILUK::apply: The 1-norm of the output Y is NaN or Inf.");
1087 applyTime_ += (timer.wallTime() - startTime);