560 if (!isKokkosKernelsStream_) {
562 LevelOfFill_, 0, Overalloc_));
564 std::vector<int> weights(num_streams_);
565 std::fill(weights.begin(), weights.end(), 1);
566 exec_space_instances_ = Kokkos::Experimental::partition_space(execution_space(), weights);
568 auto lclMtx = A_local_crs_->getLocalMatrixDevice();
569 if (!hasStreamReordered_) {
570 if (hasStreamsWithRCB_) {
571 TEUCHOS_TEST_FOR_EXCEPTION(A_coordinates_.is_null(), std::runtime_error, prefix <<
"The coordinates associated with rows of the input matrix is null while RILUK uses streams with RCB. Please call setCoord() with a nonnull input before calling this method.");
572 auto A_coordinates_lcl = A_coordinates_->getLocalViewDevice(Tpetra::Access::ReadOnly);
573 perm_rcb_ = perm_view_t(Kokkos::view_alloc(Kokkos::WithoutInitializing,
"perm_rcb_"), A_coordinates_lcl.extent(0));
574#if KOKKOS_VERSION >= 50100
575 reverse_perm_rcb_ = perm_view_t(Kokkos::view_alloc(Kokkos::WithoutInitializing,
"reverse_perm_rcb_"), A_coordinates_lcl.extent(0));
577 coors_rcb_ = coors_view_t(Kokkos::view_alloc(Kokkos::WithoutInitializing,
"coors_rcb_"), A_coordinates_lcl.extent(0), A_coordinates_lcl.extent(1));
578 Kokkos::deep_copy(coors_rcb_, A_coordinates_lcl);
579#if KOKKOS_VERSION >= 50100
580 local_ordinal_type n_levels =
static_cast<local_ordinal_type
>(std::log2(
static_cast<double>(num_streams_)) + 1);
581 partition_sizes_rcb_ = KokkosGraph::Experimental::recursive_coordinate_bisection(coors_rcb_, perm_rcb_, reverse_perm_rcb_, n_levels);
582 KokkosSparse::Experimental::kk_extract_diagonal_blocks_crsmatrix_with_rcb_sequential(lclMtx, perm_rcb_, reverse_perm_rcb_, partition_sizes_rcb_,
583 A_local_diagblks_v_);
585 KokkosSparse::Impl::kk_extract_diagonal_blocks_crsmatrix_with_rcb_sequential(lclMtx, coors_rcb_,
586 A_local_diagblks_v_, perm_rcb_);
589#if KOKKOS_VERSION >= 50100
590 KokkosSparse::Experimental::kk_extract_diagonal_blocks_crsmatrix_sequential(lclMtx, A_local_diagblks_v_);
592 KokkosSparse::Impl::kk_extract_diagonal_blocks_crsmatrix_sequential(lclMtx, A_local_diagblks_v_);
596#if KOKKOS_VERSION >= 50100
597 perm_v_ = KokkosSparse::Experimental::kk_extract_diagonal_blocks_crsmatrix_sequential(lclMtx, A_local_diagblks_v_,
true);
599 perm_v_ = KokkosSparse::Impl::kk_extract_diagonal_blocks_crsmatrix_sequential(lclMtx, A_local_diagblks_v_,
true);
601 reverse_perm_v_.resize(perm_v_.size());
602 for (
size_t istream = 0; istream < perm_v_.size(); ++istream) {
603 using perm_type =
typename lno_nonzero_view_t::non_const_type;
604 const auto perm = perm_v_[istream];
605 const auto perm_length = perm.extent(0);
606 perm_type reverse_perm(
607 Kokkos::view_alloc(Kokkos::WithoutInitializing,
"reverse_perm"),
609 Kokkos::parallel_for(
610 Kokkos::RangePolicy<execution_space>(exec_space_instances_[istream], 0, perm_length),
611 KOKKOS_LAMBDA(
const local_ordinal_type ii) {
612 reverse_perm(perm(ii)) = ii;
614 reverse_perm_v_[istream] = reverse_perm;
618 A_local_diagblks_rowmap_v_ = std::vector<lno_row_view_t>(num_streams_);
619 A_local_diagblks_entries_v_ = std::vector<lno_nonzero_view_t>(num_streams_);
620 A_local_diagblks_values_v_ = std::vector<scalar_nonzero_view_t>(num_streams_);
622 for (
int i = 0; i < num_streams_; i++) {
623 A_local_diagblks_rowmap_v_[i] = A_local_diagblks_v_[i].graph.row_map;
624 A_local_diagblks_entries_v_[i] = A_local_diagblks_v_[i].graph.entries;
625 A_local_diagblks_values_v_[i] = A_local_diagblks_v_[i].values;
627 Teuchos::RCP<const crs_map_type> A_local_diagblks_RowMap = rcp(
new crs_map_type(A_local_diagblks_v_[i].numRows(),
628 A_local_diagblks_v_[i].numRows(),
629 A_local_crs_->getRowMap()->getComm()));
630 Teuchos::RCP<const crs_map_type> A_local_diagblks_ColMap = rcp(
new crs_map_type(A_local_diagblks_v_[i].numCols(),
631 A_local_diagblks_v_[i].numCols(),
632 A_local_crs_->getColMap()->getComm()));
633 Teuchos::RCP<crs_matrix_type> A_local_diagblks = rcp(
new crs_matrix_type(A_local_diagblks_RowMap,
634 A_local_diagblks_ColMap,
635 A_local_diagblks_v_[i]));
637 LevelOfFill_, 0, Overalloc_));
642 if (this->isKokkosKernelsSpiluk_) {
643 if (!isKokkosKernelsStream_) {
644 this->KernelHandle_ = Teuchos::rcp(
new kk_handle_type());
645 KernelHandle_->create_spiluk_handle(KokkosSparse::Experimental::SPILUKAlgorithm::SEQLVLSCHD_TP1,
646 A_local_->getLocalNumRows(),
647 2 * A_local_->getLocalNumEntries() * (LevelOfFill_ + 1),
648 2 * A_local_->getLocalNumEntries() * (LevelOfFill_ + 1));
649 Graph_->initialize(KernelHandle_);
651 KernelHandle_v_ = std::vector<Teuchos::RCP<kk_handle_type> >(num_streams_);
652 for (
int i = 0; i < num_streams_; i++) {
653 KernelHandle_v_[i] = Teuchos::rcp(
new kk_handle_type());
654 KernelHandle_v_[i]->create_spiluk_handle(KokkosSparse::Experimental::SPILUKAlgorithm::SEQLVLSCHD_TP1,
655 A_local_diagblks_v_[i].numRows(),
656 2 * A_local_diagblks_v_[i].nnz() * (LevelOfFill_ + 1),
657 2 * A_local_diagblks_v_[i].nnz() * (LevelOfFill_ + 1));
658 Graph_v_[i]->initialize(KernelHandle_v_[i]);
662 Graph_->initialize();
666 checkOrderingConsistency(*A_local_);
667 if (!isKokkosKernelsStream_) {
668 L_solver_->setMatrix(L_);
670 L_solver_->setStreamInfo(isKokkosKernelsStream_, num_streams_, exec_space_instances_);
671 L_solver_->setMatrices(L_v_);
673 L_solver_->initialize();
675 if (!isKokkosKernelsStream_) {
676 U_solver_->setMatrix(U_);
678 U_solver_->setStreamInfo(isKokkosKernelsStream_, num_streams_, exec_space_instances_);
679 U_solver_->setMatrices(U_v_);
681 U_solver_->initialize();
688 isInitialized_ =
true;
690 initializeTime_ += (timer.wallTime() - startTime);
693template <
class MatrixType>
694void RILUK<MatrixType>::
695 checkOrderingConsistency(
const row_matrix_type& A) {
699 Teuchos::ArrayView<const global_ordinal_type> rowGIDs = A.getRowMap()->getLocalElementList();
700 Teuchos::ArrayView<const global_ordinal_type> colGIDs = A.getColMap()->getLocalElementList();
701 bool gidsAreConsistentlyOrdered =
true;
702 global_ordinal_type indexOfInconsistentGID = 0;
703 for (global_ordinal_type i = 0; i < rowGIDs.size(); ++i) {
704 if (rowGIDs[i] != colGIDs[i]) {
705 gidsAreConsistentlyOrdered =
false;
706 indexOfInconsistentGID = i;
710 TEUCHOS_TEST_FOR_EXCEPTION(gidsAreConsistentlyOrdered ==
false, std::runtime_error,
711 "The ordering of the local GIDs in the row and column maps is not the same"
713 <<
"at index " << indexOfInconsistentGID
714 <<
". Consistency is required, as all calculations are done with"
716 <<
"local indexing.");
719template <
class MatrixType>
720void RILUK<MatrixType>::
721 initAllValues(
const row_matrix_type& A) {
722 using Teuchos::ArrayRCP;
726 using Teuchos::REDUCE_SUM;
727 using Teuchos::reduceAll;
728 typedef Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
729 typedef Tpetra::CrsGraph<local_ordinal_type,
734 auto crsMat = Details::getCrsMatrix(A_);
735 if (!crsMat.is_null())
736 Teuchos::rcp_const_cast<crs_graph_type>(crsMat->getCrsGraph())->computeGlobalConstants();
738 size_t NumIn = 0, NumL = 0, NumU = 0;
739 bool DiagFound =
false;
740 size_t NumNonzeroDiags = 0;
741 size_t MaxNumEntries = A.getGlobalMaxNumRowEntries();
745 nonconst_local_inds_host_view_type InI(
"InI", MaxNumEntries);
746 Teuchos::Array<local_ordinal_type> LI(MaxNumEntries);
747 Teuchos::Array<local_ordinal_type> UI(MaxNumEntries);
748 nonconst_values_host_view_type InV(
"InV", MaxNumEntries);
749 Teuchos::Array<scalar_type> LV(MaxNumEntries);
750 Teuchos::Array<scalar_type> UV(MaxNumEntries);
753 const bool ReplaceValues = L_->isStaticGraph() || L_->isLocallyIndexed();
758 L_->setAllToScalar(STS::zero());
759 U_->setAllToScalar(STS::zero());
762 D_->putScalar(STS::zero());
763 auto DV = Kokkos::subview(D_->getLocalViewHost(Tpetra::Access::ReadWrite), Kokkos::ALL(), 0);
765 RCP<const map_type> rowMap = L_->getRowMap();
775 Teuchos::ArrayView<const global_ordinal_type> nodeGIDs = rowMap->getLocalElementList();
776 for (
size_t myRow = 0; myRow < A.getLocalNumRows(); ++myRow) {
777 local_ordinal_type local_row = myRow;
781 A.getLocalRowCopy(local_row, InI, InV, NumIn);
789 for (
size_t j = 0; j < NumIn; ++j) {
790 const local_ordinal_type k = InI[j];
792 if (k == local_row) {
795 DV(local_row) += Rthresh_ * InV[j] + IFPACK2_SGN(InV[j]) * Athresh_;
797 TEUCHOS_TEST_FOR_EXCEPTION(
798 true, std::runtime_error,
799 "Ifpack2::RILUK::initAllValues: current "
801 << k <<
" < 0. I'm not sure why this is an error; it is "
802 "probably an artifact of the undocumented assumptions of the "
803 "original implementation (likely copied and pasted from Ifpack). "
804 "Nevertheless, the code I found here insisted on this being an error "
805 "state, so I will throw an exception here.");
806 }
else if (k < local_row) {
810 }
else if (Teuchos::as<size_t>(k) <= rowMap->getLocalNumElements()) {
822 DV(local_row) = Athresh_;
827 L_->replaceLocalValues(local_row, LI(0, NumL), LV(0, NumL));
831 L_->insertLocalValues(local_row, LI(0, NumL), LV(0, NumL));
837 U_->replaceLocalValues(local_row, UI(0, NumU), UV(0, NumU));
841 U_->insertLocalValues(local_row, UI(0, NumU), UV(0, NumU));
849 isInitialized_ =
true;
852template <
class MatrixType>
853void RILUK<MatrixType>::compute_serial() {
856 initAllValues(*A_local_);
861 const scalar_type MinDiagonalValue = STS::rmin();
862 const scalar_type MaxDiagonalValue = STS::one() / MinDiagonalValue;
864 size_t NumIn, NumL, NumU;
867 const size_t MaxNumEntries =
868 L_->getLocalMaxNumRowEntries() + U_->getLocalMaxNumRowEntries() + 1;
870 Teuchos::Array<local_ordinal_type> InI(MaxNumEntries);
871 Teuchos::Array<scalar_type> InV(MaxNumEntries);
872 size_t num_cols = U_->getColMap()->getLocalNumElements();
873 Teuchos::Array<int> colflag(num_cols, -1);
875 auto DV = Kokkos::subview(D_->getLocalViewHost(Tpetra::Access::ReadWrite), Kokkos::ALL(), 0);
879 using IST =
typename row_matrix_type::impl_scalar_type;
880 for (
size_t i = 0; i < L_->getLocalNumRows(); ++i) {
881 local_ordinal_type local_row = i;
884 local_inds_host_view_type UUI;
885 values_host_view_type UUV;
889 NumIn = MaxNumEntries;
890 nonconst_local_inds_host_view_type InI_v(InI.data(), MaxNumEntries);
891 nonconst_values_host_view_type InV_v(
reinterpret_cast<IST*
>(InV.data()), MaxNumEntries);
893 L_->getLocalRowCopy(local_row, InI_v, InV_v, NumL);
896 InI[NumL] = local_row;
898 nonconst_local_inds_host_view_type InI_sub(InI.data() + NumL + 1, MaxNumEntries - NumL - 1);
899 nonconst_values_host_view_type InV_sub(
reinterpret_cast<IST*
>(InV.data()) + NumL + 1, MaxNumEntries - NumL - 1);
901 U_->getLocalRowCopy(local_row, InI_sub, InV_sub, NumU);
902 NumIn = NumL + NumU + 1;
905 for (
size_t j = 0; j < NumIn; ++j) {
909 scalar_type diagmod = STS::zero();
911 for (
size_t jj = 0; jj < NumL; ++jj) {
912 local_ordinal_type j = InI[jj];
913 IST multiplier = InV[jj];
915 InV[jj] *=
static_cast<scalar_type
>(DV(j));
917 U_->getLocalRowView(j, UUI, UUV);
920 if (RelaxValue_ == STM::zero()) {
921 for (
size_t k = 0; k < NumUU; ++k) {
922 const int kk = colflag[UUI[k]];
927 InV[kk] -=
static_cast<scalar_type
>(multiplier * UUV[k]);
932 for (
size_t k = 0; k < NumUU; ++k) {
936 const int kk = colflag[UUI[k]];
938 InV[kk] -=
static_cast<scalar_type
>(multiplier * UUV[k]);
940 diagmod -=
static_cast<scalar_type
>(multiplier * UUV[k]);
948 L_->replaceLocalValues(local_row, InI(0, NumL), InV(0, NumL));
953 if (RelaxValue_ != STM::zero()) {
954 DV(i) += RelaxValue_ * diagmod;
957 if (STS::magnitude(DV(i)) > STS::magnitude(MaxDiagonalValue)) {
958 if (STS::real(DV(i)) < STM::zero()) {
959 DV(i) = -MinDiagonalValue;
961 DV(i) = MinDiagonalValue;
964 DV(i) =
static_cast<impl_scalar_type
>(STS::one()) / DV(i);
967 for (
size_t j = 0; j < NumU; ++j) {
968 InV[NumL + 1 + j] *=
static_cast<scalar_type
>(DV(i));
973 U_->replaceLocalValues(local_row, InI(NumL + 1, NumU), InV(NumL + 1, NumU));
977 for (
size_t j = 0; j < NumIn; ++j) {
978 colflag[InI[j]] = -1;
989 L_->fillComplete(L_->getColMap(), A_local_->getRangeMap());
990 U_->fillComplete(A_local_->getDomainMap(), U_->getRowMap());
993 L_solver_->setMatrix(L_);
994 L_solver_->compute();
995 U_solver_->setMatrix(U_);
996 U_solver_->compute();
999template <
class MatrixType>
1000void RILUK<MatrixType>::compute_kkspiluk() {
1004 L_->setAllToScalar(STS::zero());
1005 U_->setAllToScalar(STS::zero());
1007 using row_map_type =
typename crs_matrix_type::local_matrix_device_type::row_map_type;
1008 auto lclL = L_->getLocalMatrixDevice();
1009 row_map_type L_rowmap = lclL.graph.row_map;
1010 auto L_entries = lclL.graph.entries;
1011 auto L_values = lclL.values;
1013 auto lclU = U_->getLocalMatrixDevice();
1014 row_map_type U_rowmap = lclU.graph.row_map;
1015 auto U_entries = lclU.graph.entries;
1016 auto U_values = lclU.values;
1018 auto lclMtx = A_local_crs_->getLocalMatrixDevice();
1019 KokkosSparse::spiluk_numeric(KernelHandle_.getRawPtr(), LevelOfFill_,
1020 lclMtx.graph.row_map, lclMtx.graph.entries, lclMtx.values,
1021 L_rowmap, L_entries, L_values, U_rowmap, U_entries, U_values);
1023 L_->fillComplete(L_->getColMap(), A_local_->getRangeMap());
1024 U_->fillComplete(A_local_->getDomainMap(), U_->getRowMap());
1026 L_solver_->compute();
1027 U_solver_->compute();
1030template <
class MatrixType>
1031void RILUK<MatrixType>::compute_kkspiluk_stream() {
1032 std::vector<lno_row_view_t> L_rowmap_v(num_streams_);
1033 std::vector<lno_nonzero_view_t> L_entries_v(num_streams_);
1034 std::vector<scalar_nonzero_view_t> L_values_v(num_streams_);
1035 std::vector<lno_row_view_t> U_rowmap_v(num_streams_);
1036 std::vector<lno_nonzero_view_t> U_entries_v(num_streams_);
1037 std::vector<scalar_nonzero_view_t> U_values_v(num_streams_);
1038 std::vector<kk_handle_type*> KernelHandle_rawptr_v_(num_streams_);
1039 for (
int i = 0; i < num_streams_; i++) {
1040 L_v_[i]->resumeFill();
1041 U_v_[i]->resumeFill();
1043 L_v_[i]->setAllToScalar(STS::zero());
1044 U_v_[i]->setAllToScalar(STS::zero());
1046 auto lclL = L_v_[i]->getLocalMatrixDevice();
1047 L_rowmap_v[i] = lclL.graph.row_map;
1048 L_entries_v[i] = lclL.graph.entries;
1049 L_values_v[i] = lclL.values;
1051 auto lclU = U_v_[i]->getLocalMatrixDevice();
1052 U_rowmap_v[i] = lclU.graph.row_map;
1053 U_entries_v[i] = lclU.graph.entries;
1054 U_values_v[i] = lclU.values;
1055 KernelHandle_rawptr_v_[i] = KernelHandle_v_[i].getRawPtr();
1058 if (hasStreamReordered_) {
1062 auto lclMtx = A_local_crs_->getLocalMatrixDevice();
1065 using TeamPolicy = Kokkos::TeamPolicy<execution_space>;
1066 const auto A_nrows = lclMtx.numRows();
1067 auto rows_per_block = ((A_nrows % num_streams_) == 0)
1068 ? (A_nrows / num_streams_)
1069 : (A_nrows / num_streams_ + 1);
1070 for (
int i = 0; i < num_streams_; i++) {
1071 const auto start_row_offset = i * rows_per_block;
1072 auto rowptrs = A_local_diagblks_rowmap_v_[i];
1073 auto colindices = A_local_diagblks_entries_v_[i];
1074 auto values = A_local_diagblks_values_v_[i];
1075 const bool reordered = hasStreamReordered_;
1076 typename lno_nonzero_view_t::non_const_type reverse_perm = hasStreamReordered_ ? reverse_perm_v_[i] :
typename lno_nonzero_view_t::non_const_type{};
1077 TeamPolicy pol(exec_space_instances_[i], A_local_diagblks_rowmap_v_[i].extent(0) - 1, Kokkos::AUTO);
1078 Kokkos::parallel_for(
1079 pol, KOKKOS_LAMBDA(
const typename TeamPolicy::member_type& team) {
1080 const auto irow = team.league_rank();
1081 const auto irow_A = start_row_offset + (reordered ? reverse_perm(irow) : irow);
1082 const auto A_local_crs_row = lclMtx.rowConst(irow_A);
1083 const auto begin_row = rowptrs(irow);
1084 const auto num_entries = rowptrs(irow + 1) - begin_row;
1085 Kokkos::parallel_for(Kokkos::TeamThreadRange(team, num_entries), [&](
const int j) {
1086 const auto colidx = colindices(begin_row + j);
1087 const auto colidx_A = start_row_offset + (reordered ? reverse_perm(colidx) : colidx);
1089 const int offset = KokkosSparse::findRelOffset(
1090 &A_local_crs_row.colidx(0), A_local_crs_row.length, colidx_A, 0,
false);
1091 values(begin_row + j) = A_local_crs_row.value(offset);
1097 KokkosSparse::Experimental::spiluk_numeric_streams(exec_space_instances_, KernelHandle_rawptr_v_, LevelOfFill_,
1098 A_local_diagblks_rowmap_v_, A_local_diagblks_entries_v_, A_local_diagblks_values_v_,
1099 L_rowmap_v, L_entries_v, L_values_v,
1100 U_rowmap_v, U_entries_v, U_values_v);
1102 for (
int i = 0; i < num_streams_; i++) {
1103 L_v_[i]->fillComplete();
1104 U_v_[i]->fillComplete();
1107 L_solver_->compute();
1108 U_solver_->compute();
1111template <
class MatrixType>
1113 using Teuchos::Array;
1114 using Teuchos::ArrayView;
1117 using Teuchos::rcp_const_cast;
1118 using Teuchos::rcp_dynamic_cast;
1119 const char prefix[] =
"Ifpack2::RILUK::compute: ";
1124 TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error, prefix <<
"The matrix is null. Please "
1125 "call setMatrix() with a nonnull input before calling this method.");
1126 TEUCHOS_TEST_FOR_EXCEPTION(!A_->isFillComplete(), std::runtime_error, prefix <<
"The matrix is not "
1127 "fill complete. You may not invoke initialize() or compute() with this "
1128 "matrix until the matrix is fill complete. If your matrix is a "
1129 "Tpetra::CrsMatrix, please call fillComplete on it (with the domain and "
1130 "range Maps, if appropriate) before calling this method.");
1132 if (!isInitialized()) {
1136 Teuchos::Time timer(
"RILUK::compute");
1139 Teuchos::TimeMonitor timeMon(timer);
1140 double startTime = timer.wallTime();
1142 isComputed_ =
false;
1144 if (!this->isKokkosKernelsSpiluk_) {
1148 if (!A_local_crs_nc_.is_null()) {
1150 A_local_crs_nc_->resumeFill();
1152 nonconst_local_inds_host_view_type indices(
"indices", A_local_->getLocalMaxNumRowEntries());
1153 nonconst_values_host_view_type values(
"values", A_local_->getLocalMaxNumRowEntries());
1155 size_t numEntries = 0;
1156 A_local_->getLocalRowCopy(i, indices, values, numEntries);
1157 A_local_crs_nc_->replaceLocalValues(i, numEntries,
reinterpret_cast<scalar_type*
>(values.data()), indices.data());
1159 A_local_crs_nc_->fillComplete(A_local_->getDomainMap(), A_local_->getRangeMap());
1162 if (!isKokkosKernelsStream_) {
1166 auto lclMtx = A_local_crs_->getLocalMatrixDevice();
1167 if (!hasStreamsWithRCB_) {
1168#if KOKKOS_VERSION >= 50100
1169 KokkosSparse::Experimental::kk_extract_diagonal_blocks_crsmatrix_sequential(lclMtx, A_local_diagblks_v_, hasStreamReordered_);
1171 KokkosSparse::Impl::kk_extract_diagonal_blocks_crsmatrix_sequential(lclMtx, A_local_diagblks_v_, hasStreamReordered_);
1174#if KOKKOS_VERSION >= 50100
1175 KokkosSparse::Experimental::kk_extract_diagonal_blocks_crsmatrix_with_rcb_sequential(lclMtx, perm_rcb_, reverse_perm_rcb_, partition_sizes_rcb_,
1176 A_local_diagblks_v_);
1178 auto A_coordinates_lcl = A_coordinates_->getLocalViewDevice(Tpetra::Access::ReadOnly);
1179 Kokkos::deep_copy(coors_rcb_, A_coordinates_lcl);
1180 KokkosSparse::Impl::kk_extract_diagonal_blocks_crsmatrix_with_rcb_sequential(lclMtx, coors_rcb_,
1181 A_local_diagblks_v_, perm_rcb_);
1184 for (
int i = 0; i < num_streams_; i++) {
1185 A_local_diagblks_values_v_[i] = A_local_diagblks_v_[i].values;
1188 compute_kkspiluk_stream();
1194 computeTime_ += (timer.wallTime() - startTime);
1198template <
typename MV,
typename Map>
1199void resetMultiVecIfNeeded(std::unique_ptr<MV>& mv_ptr,
const Map& map,
const size_t numVectors,
bool initialize) {
1200 if (!mv_ptr || mv_ptr->getNumVectors() != numVectors) {
1201 mv_ptr.reset(
new MV(map, numVectors, initialize));
1206template <
class MatrixType>
1208 apply(
const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
1209 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
1210 Teuchos::ETransp mode,
1214 using Teuchos::rcpFromRef;
1216 TEUCHOS_TEST_FOR_EXCEPTION(
1217 A_.is_null(), std::runtime_error,
1218 "Ifpack2::RILUK::apply: The matrix is "
1219 "null. Please call setMatrix() with a nonnull input, then initialize() "
1220 "and compute(), before calling this method.");
1221 TEUCHOS_TEST_FOR_EXCEPTION(
1222 !isComputed(), std::runtime_error,
1223 "Ifpack2::RILUK::apply: If you have not yet called compute(), "
1224 "you must call compute() before calling this method.");
1225 TEUCHOS_TEST_FOR_EXCEPTION(
1226 X.getNumVectors() != Y.getNumVectors(), std::invalid_argument,
1227 "Ifpack2::RILUK::apply: X and Y do not have the same number of columns. "
1228 "X.getNumVectors() = "
1229 << X.getNumVectors()
1230 <<
" != Y.getNumVectors() = " << Y.getNumVectors() <<
".");
1231 TEUCHOS_TEST_FOR_EXCEPTION(
1232 STS::isComplex && mode == Teuchos::CONJ_TRANS, std::logic_error,
1233 "Ifpack2::RILUK::apply: mode = Teuchos::CONJ_TRANS is not implemented for "
1234 "complex Scalar type. Please talk to the Ifpack2 developers to get this "
1235 "fixed. There is a FIXME in this file about this very issue.");
1237 if (!isKokkosKernelsStream_) {
1239 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.");
1241 Teuchos::Array<magnitude_type> norms(X.getNumVectors());
1244 for (
size_t j = 0; j < X.getNumVectors(); ++j) {
1245 if (STM::isnaninf(norms[j])) {
1250 TEUCHOS_TEST_FOR_EXCEPTION(!good, std::runtime_error,
"Ifpack2::RILUK::apply: The 1-norm of the input X is NaN or Inf.");
1256 Teuchos::Time timer(
"RILUK::apply");
1257 double startTime = timer.wallTime();
1259 Teuchos::TimeMonitor timeMon(timer);
1260 if (alpha == one && beta == zero) {
1261 if (isKokkosKernelsSpiluk_ && isKokkosKernelsStream_ && (hasStreamReordered_ || hasStreamsWithRCB_)) {
1262 Impl::resetMultiVecIfNeeded(reordered_x_, X.getMap(), X.getNumVectors(),
false);
1263 Impl::resetMultiVecIfNeeded(reordered_y_, Y.getMap(), Y.getNumVectors(),
false);
1266 for (
size_t j = 0; j < X.getNumVectors(); j++) {
1267 auto X_j = X.getVector(j);
1268 auto ReorderedX_j = reordered_x_->getVectorNonConst(j);
1269 auto X_lcl = X_j->getLocalViewDevice(Tpetra::Access::ReadOnly);
1270 auto ReorderedX_lcl = ReorderedX_j->getLocalViewDevice(Tpetra::Access::ReadWrite);
1271 if (hasStreamReordered_) {
1274 for (
int i = 0; i < num_streams_; i++) {
1275 auto perm_i = perm_v_[i];
1276 stream_end = stream_begin + perm_i.extent(0);
1277 auto X_lcl_sub = Kokkos::subview(X_lcl, Kokkos::make_pair(stream_begin, stream_end), 0);
1278 auto ReorderedX_lcl_sub = Kokkos::subview(ReorderedX_lcl, Kokkos::make_pair(stream_begin, stream_end), 0);
1279 Kokkos::parallel_for(
1280 Kokkos::RangePolicy<execution_space>(exec_space_instances_[i], 0,
static_cast<int>(perm_i.extent(0))), KOKKOS_LAMBDA(
const int& ii) {
1281 ReorderedX_lcl_sub(perm_i(ii)) = X_lcl_sub(ii);
1283 stream_begin = stream_end;
1286 auto perm = perm_rcb_;
1287 Kokkos::parallel_for(
1288 Kokkos::RangePolicy<execution_space>(0,
static_cast<int>(X_lcl.extent(0))), KOKKOS_LAMBDA(
const int& ii) {
1289 ReorderedX_lcl(perm(ii), 0) = X_lcl(ii, 0);
1295 if (mode == Teuchos::NO_TRANS) {
1297 L_solver_->apply(*reordered_x_, Y, mode);
1299 U_solver_->apply(Y, *reordered_y_, mode);
1302 U_solver_->apply(*reordered_x_, Y, mode);
1304 L_solver_->apply(Y, *reordered_y_, mode);
1307 for (
size_t j = 0; j < Y.getNumVectors(); j++) {
1308 auto Y_j = Y.getVectorNonConst(j);
1309 auto ReorderedY_j = reordered_y_->getVector(j);
1310 auto Y_lcl = Y_j->getLocalViewDevice(Tpetra::Access::ReadWrite);
1311 auto ReorderedY_lcl = ReorderedY_j->getLocalViewDevice(Tpetra::Access::ReadOnly);
1312 if (hasStreamReordered_) {
1315 for (
int i = 0; i < num_streams_; i++) {
1316 auto perm_i = perm_v_[i];
1317 stream_end = stream_begin + perm_i.extent(0);
1318 auto Y_lcl_sub = Kokkos::subview(Y_lcl, Kokkos::make_pair(stream_begin, stream_end), 0);
1319 auto ReorderedY_lcl_sub = Kokkos::subview(ReorderedY_lcl, Kokkos::make_pair(stream_begin, stream_end), 0);
1320 Kokkos::parallel_for(
1321 Kokkos::RangePolicy<execution_space>(exec_space_instances_[i], 0,
static_cast<int>(perm_i.extent(0))), KOKKOS_LAMBDA(
const int& ii) {
1322 Y_lcl_sub(ii) = ReorderedY_lcl_sub(perm_i(ii));
1324 stream_begin = stream_end;
1327 auto perm = perm_rcb_;
1328 Kokkos::parallel_for(
1329 Kokkos::RangePolicy<execution_space>(0,
static_cast<int>(Y_lcl.extent(0))), KOKKOS_LAMBDA(
const int& ii) {
1330 Y_lcl(ii, 0) = ReorderedY_lcl(perm(ii), 0);
1336 if (mode == Teuchos::NO_TRANS) {
1337#if defined(KOKKOSKERNELS_ENABLE_TPL_CUSPARSE) && defined(KOKKOS_ENABLE_CUDA) && (CUDA_VERSION >= 11030)
1341 Impl::resetMultiVecIfNeeded(Y_tmp_, Y.getMap(), Y.getNumVectors(),
false);
1344 L_solver_->apply(X, *Y_tmp_, mode);
1346 if (!this->isKokkosKernelsSpiluk_) {
1349 Y_tmp_->elementWiseMultiply(one, *D_, *Y_tmp_, zero);
1352 U_solver_->apply(*Y_tmp_, Y, mode);
1355 L_solver_->apply(X, Y, mode);
1357 if (!this->isKokkosKernelsSpiluk_) {
1360 Y.elementWiseMultiply(one, *D_, Y, zero);
1363 U_solver_->apply(Y, Y, mode);
1366#if defined(KOKKOSKERNELS_ENABLE_TPL_CUSPARSE) && defined(KOKKOS_ENABLE_CUDA) && (CUDA_VERSION >= 11030)
1370 Impl::resetMultiVecIfNeeded(Y_tmp_, Y.getMap(), Y.getNumVectors(),
false);
1373 U_solver_->apply(X, *Y_tmp_, mode);
1375 if (!this->isKokkosKernelsSpiluk_) {
1381 Y_tmp_->elementWiseMultiply(one, *D_, *Y_tmp_, zero);
1384 L_solver_->apply(*Y_tmp_, Y, mode);
1387 U_solver_->apply(X, Y, mode);
1389 if (!this->isKokkosKernelsSpiluk_) {
1395 Y.elementWiseMultiply(one, *D_, Y, zero);
1398 L_solver_->apply(Y, Y, mode);
1403 if (alpha == zero) {
1413 Impl::resetMultiVecIfNeeded(Y_tmp_, Y.getMap(), Y.getNumVectors(),
false);
1414 apply(X, *Y_tmp_, mode);
1415 Y.update(alpha, *Y_tmp_, beta);
1421 Teuchos::Array<magnitude_type> norms(Y.getNumVectors());
1424 for (
size_t j = 0; j < Y.getNumVectors(); ++j) {
1425 if (STM::isnaninf(norms[j])) {
1430 TEUCHOS_TEST_FOR_EXCEPTION(!good, std::runtime_error,
"Ifpack2::RILUK::apply: The 1-norm of the output Y is NaN or Inf.");
1434 applyTime_ += (timer.wallTime() - startTime);
1470template <
class MatrixType>
1472 std::ostringstream os;
1477 os <<
"\"Ifpack2::RILUK\": {";
1478 os <<
"Initialized: " << (isInitialized() ?
"true" :
"false") <<
", "
1479 <<
"Computed: " << (isComputed() ?
"true" :
"false") <<
", ";
1481 os <<
"Level-of-fill: " << getLevelOfFill() <<
", ";
1483 if (isKokkosKernelsSpiluk_) os <<
"KK-SPILUK, ";
1484 if (isKokkosKernelsStream_) os <<
"KK-Stream, ";
1487 os <<
"Matrix: null";
1489 auto crsMat = Details::getCrsMatrix(A_);
1490 os <<
"Global matrix dimensions: ["
1491 << A_->getGlobalNumRows() <<
", " << A_->getGlobalNumCols() <<
"]";
1492 if (!crsMat.is_null() && crsMat->haveGlobalConstants())
1493 os <<
", Global nnz: " << A_->getGlobalNumEntries();
1496 if (!L_solver_.is_null()) os <<
", " << L_solver_->description();
1497 if (!U_solver_.is_null()) os <<
", " << U_solver_->description();
1505#define IFPACK2_RILUK_INSTANT(S, LO, GO, N) \
1506 template class Ifpack2::RILUK<Tpetra::RowMatrix<S, LO, GO, N> >;