198 using Ifpack2::Details::getParamTryingTypes;
199 const char prefix[] =
"Ifpack2::ILUT: ";
206 IlutImplType::Enum ilutimplType = IlutImplType::Serial;
208 static const char typeName[] =
"fact: type";
210 if (!params.isType<std::string>(typeName))
break;
213 Teuchos::Array<std::string> ilutimplTypeStrs;
214 Teuchos::Array<IlutImplType::Enum> ilutimplTypeEnums;
215 IlutImplType::loadPLTypeOption(ilutimplTypeStrs, ilutimplTypeEnums);
216 Teuchos::StringToIntegralParameterEntryValidator<IlutImplType::Enum>
217 s2i(ilutimplTypeStrs(), ilutimplTypeEnums(), typeName,
false);
219 ilutimplType = s2i.getIntegralValue(params.get<std::string>(typeName));
222 if (ilutimplType == IlutImplType::PAR_ILUT) {
223 this->useKokkosKernelsParILUT_ =
true;
225 this->useKokkosKernelsParILUT_ =
false;
231 double fillLevel = LevelOfFill_;
233 const std::string paramName(
"fact: ilut level-of-fill");
234 TEUCHOS_TEST_FOR_EXCEPTION(
235 (params.isParameter(paramName) && this->useKokkosKernelsParILUT_), std::runtime_error,
236 "Ifpack2::ILUT: Parameter " << paramName <<
" is meaningless for algorithm par_ilut.");
237 getParamTryingTypes<double, double, float>(fillLevel, params, paramName, prefix);
238 TEUCHOS_TEST_FOR_EXCEPTION(fillLevel < 1.0, std::runtime_error,
239 "Ifpack2::ILUT: The \"" << paramName <<
"\" parameter must be >= "
240 "1.0, but you set it to "
241 << fillLevel <<
". For ILUT, the fill level "
242 "means something different than it does for ILU(k). ILU(0) produces "
243 "factors with the same sparsity structure as the input matrix A. For "
244 "ILUT, level-of-fill = 1.0 will produce factors with nonzeros matching "
245 "the sparsity structure of A. level-of-fill > 1.0 allows for additional "
251 const std::string paramName(
"fact: absolute threshold");
252 getParamTryingTypes<magnitude_type, magnitude_type, double>(absThresh, params, paramName, prefix);
257 const std::string paramName(
"fact: relative threshold");
258 getParamTryingTypes<magnitude_type, magnitude_type, double>(relThresh, params, paramName, prefix);
263 const std::string paramName(
"fact: relax value");
264 getParamTryingTypes<magnitude_type, magnitude_type, double>(relaxValue, params, paramName, prefix);
269 const std::string paramName(
"fact: drop tolerance");
270 getParamTryingTypes<magnitude_type, magnitude_type, double>(dropTol, params, paramName, prefix);
273 int par_ilut_max_iter = 20;
275 int par_ilut_team_size = 0;
276 int par_ilut_vector_size = 0;
277 float par_ilut_fill_in_limit = 0.75;
278 bool par_ilut_verbose =
false;
279 if (this->useKokkosKernelsParILUT_) {
280 par_ilut_max_iter = par_ilut_options_.max_iter;
281 par_ilut_residual_norm_delta_stop = par_ilut_options_.residual_norm_delta_stop;
282 par_ilut_team_size = par_ilut_options_.team_size;
283 par_ilut_vector_size = par_ilut_options_.vector_size;
284 par_ilut_fill_in_limit = par_ilut_options_.fill_in_limit;
285 par_ilut_verbose = par_ilut_options_.verbose;
287 std::string par_ilut_plist_name(
"parallel ILUT options");
288 if (params.isSublist(par_ilut_plist_name)) {
289 Teuchos::ParameterList
const& par_ilut_plist = params.sublist(par_ilut_plist_name);
291 std::string paramName(
"maximum iterations");
292 getParamTryingTypes<int, int>(par_ilut_max_iter, par_ilut_plist, paramName, prefix);
294 paramName =
"residual norm delta stop";
295 getParamTryingTypes<magnitude_type, magnitude_type, double>(par_ilut_residual_norm_delta_stop, par_ilut_plist, paramName, prefix);
297 paramName =
"team size";
298 getParamTryingTypes<int, int>(par_ilut_team_size, par_ilut_plist, paramName, prefix);
300 paramName =
"vector size";
301 getParamTryingTypes<int, int>(par_ilut_vector_size, par_ilut_plist, paramName, prefix);
303 paramName =
"fill in limit";
304 getParamTryingTypes<float, float, double>(par_ilut_fill_in_limit, par_ilut_plist, paramName, prefix);
306 paramName =
"verbose";
307 getParamTryingTypes<bool, bool>(par_ilut_verbose, par_ilut_plist, paramName, prefix);
311 par_ilut_options_.max_iter = par_ilut_max_iter;
312 par_ilut_options_.residual_norm_delta_stop = par_ilut_residual_norm_delta_stop;
313 par_ilut_options_.team_size = par_ilut_team_size;
314 par_ilut_options_.vector_size = par_ilut_vector_size;
315 par_ilut_options_.fill_in_limit = par_ilut_fill_in_limit;
316 par_ilut_options_.verbose = par_ilut_verbose;
321 L_solver_->setParameters(params);
322 U_solver_->setParameters(params);
324 LevelOfFill_ = fillLevel;
325 Athresh_ = absThresh;
326 Rthresh_ = relThresh;
327 RelaxValue_ = relaxValue;
328 DropTolerance_ = dropTol;
501 using Teuchos::Array;
503 using Teuchos::rcp_const_cast;
504 Teuchos::Time timer(
"ILUT::initialize");
505 double startTime = timer.wallTime();
507 Teuchos::TimeMonitor timeMon(timer);
510 TEUCHOS_TEST_FOR_EXCEPTION(
511 A_.is_null(), std::runtime_error,
512 "Ifpack2::ILUT::initialize: "
513 "The matrix to precondition is null. Please call setMatrix() with a "
514 "nonnull input before calling this method.");
517 IsInitialized_ =
false;
519 A_local_ = Teuchos::null;
520 A_local_crs_ = Teuchos::null;
521 A_local_crs_nc_ = Teuchos::null;
525 A_local_ = makeLocalFilter(A_);
526 TEUCHOS_TEST_FOR_EXCEPTION(
527 A_local_.is_null(), std::logic_error,
528 "Ifpack2::RILUT::initialize: "
529 "makeLocalFilter returned null; it failed to compute A_local. "
530 "Please report this bug to the Ifpack2 developers.");
532 if (this->useKokkosKernelsParILUT_) {
533 this->KernelHandle_ = Teuchos::rcp(
new kk_handle_type());
534 KernelHandle_->create_par_ilut_handle();
535 auto par_ilut_handle = KernelHandle_->get_par_ilut_handle();
536 par_ilut_handle->set_residual_norm_delta_stop(par_ilut_options_.residual_norm_delta_stop);
537 par_ilut_handle->set_team_size(par_ilut_options_.team_size);
538 par_ilut_handle->set_vector_size(par_ilut_options_.vector_size);
539 par_ilut_handle->set_max_iter(par_ilut_options_.max_iter);
540 par_ilut_handle->set_fill_in_limit(par_ilut_options_.fill_in_limit);
541 par_ilut_handle->set_verbose(par_ilut_options_.verbose);
542 par_ilut_handle->set_async_update(
false);
545 Kokkos::Profiling::ScopedRegion region(
"Ifpack2::ILUT::initialize::par_ilut::get_or_build_A_local_crs");
546 A_local_crs_ = Ifpack2::Details::getCrsMatrix(A_local_);
547 if (A_local_crs_.is_null()) {
548 A_local_crs_nc_ = buildLocalCrsFromRowMatrix<MatrixType>(A_local_);
549 A_local_crs_ = A_local_crs_nc_;
552 auto A_local_crs_device = A_local_crs_->getLocalMatrixDevice();
555 typedef typename Kokkos::View<usize_type*, array_layout, device_type> ulno_row_view_t;
556 const int NumMyRows = A_local_crs_->getRowMap()->getLocalNumElements();
557 L_rowmap_ = ulno_row_view_t(
"L_row_map", NumMyRows + 1);
558 U_rowmap_ = ulno_row_view_t(
"U_row_map", NumMyRows + 1);
559 L_rowmap_orig_ = ulno_row_view_t(
"L_row_map_orig", NumMyRows + 1);
560 U_rowmap_orig_ = ulno_row_view_t(
"U_row_map_orig", NumMyRows + 1);
562 KokkosSparse::Experimental::par_ilut_symbolic(KernelHandle_.getRawPtr(),
563 A_local_crs_device.graph.row_map, A_local_crs_device.graph.entries,
567 Kokkos::deep_copy(L_rowmap_orig_, L_rowmap_);
568 Kokkos::deep_copy(U_rowmap_orig_, U_rowmap_);
571 IsInitialized_ =
true;
574 InitializeTime_ += (timer.wallTime() - startTime);
585 using Teuchos::Array;
586 using Teuchos::ArrayRCP;
587 using Teuchos::ArrayView;
591 using Teuchos::rcp_const_cast;
592 using Teuchos::reduceAll;
595 if (!isInitialized()) {
599 Teuchos::Time timer(
"ILUT::compute");
600 double startTime = timer.wallTime();
602 Teuchos::TimeMonitor timeMon(timer,
true);
604 if (!this->useKokkosKernelsParILUT_) {
636#ifdef IFPACK2_WRITE_ILUT_FACTORS
637 std::ofstream ofsL(
"L.ifpack2_ilut.mtx", std::ios::out);
638 std::ofstream ofsU(
"U.ifpack2_ilut.mtx", std::ios::out);
643 double local_nnz =
static_cast<double>(A_local_->getLocalNumEntries());
644 double fill = ((getLevelOfFill() - 1.0) * local_nnz) / (2 * myNumRows);
649 double fill_ceil = std::ceil(fill);
653 size_type fillL =
static_cast<size_type
>(fill_ceil);
654 size_type fillU =
static_cast<size_type
>(fill_ceil);
656 Array<scalar_type> InvDiagU(myNumRows, zero);
658 Array<Array<local_ordinal_type> > L_tmp_idx(myNumRows);
659 Array<Array<scalar_type> > L_tmpv(myNumRows);
660 Array<Array<local_ordinal_type> > U_tmp_idx(myNumRows);
661 Array<Array<scalar_type> > U_tmpv(myNumRows);
668 Array<int> pattern(max_col, UNUSED);
669 Array<scalar_type> cur_row(max_col, zero);
670 Array<magnitude_type> unorm(max_col);
672 Array<local_ordinal_type> L_cols_heap;
673 Array<local_ordinal_type> U_cols;
674 Array<local_ordinal_type> L_vals_heap;
675 Array<local_ordinal_type> U_vals_heap;
680 greater_indirect<scalar_type, local_ordinal_type> vals_comp(cur_row);
685 nonconst_local_inds_host_view_type ColIndicesARCP;
686 nonconst_values_host_view_type ColValuesARCP;
687 if (!A_local_->supportsRowViews()) {
688 const size_t maxnz = A_local_->getLocalMaxNumRowEntries();
689 Kokkos::resize(ColIndicesARCP, maxnz);
690 Kokkos::resize(ColValuesARCP, maxnz);
694 local_inds_host_view_type ColIndicesA;
695 values_host_view_type ColValuesA;
698 if (A_local_->supportsRowViews()) {
699 A_local_->getLocalRowView(row_i, ColIndicesA, ColValuesA);
700 RowNnz = ColIndicesA.size();
702 A_local_->getLocalRowCopy(row_i, ColIndicesARCP, ColValuesARCP, RowNnz);
703 ColIndicesA = Kokkos::subview(ColIndicesARCP, std::make_pair((
size_t)0, RowNnz));
704 ColValuesA = Kokkos::subview(ColValuesARCP, std::make_pair((
size_t)0, RowNnz));
709 U_cols.push_back(row_i);
710 cur_row[row_i] = zero;
711 pattern[row_i] = ORIG;
713 size_type L_cols_heaplen = 0;
714 rownorm = STM::zero();
715 for (
size_t i = 0; i < RowNnz; ++i) {
716 if (ColIndicesA[i] < myNumRows) {
717 if (ColIndicesA[i] < row_i) {
718 add_to_heap(ColIndicesA[i], L_cols_heap, L_cols_heaplen);
719 }
else if (ColIndicesA[i] > row_i) {
720 U_cols.push_back(ColIndicesA[i]);
723 cur_row[ColIndicesA[i]] = ColValuesA[i];
724 pattern[ColIndicesA[i]] = ORIG;
725 rownorm += scalar_mag(ColValuesA[i]);
734 cur_row[row_i] = as<scalar_type>(getAbsoluteThreshold() * IFPACK2_SGN(v)) + rthresh * v;
736 size_type orig_U_len = U_cols.size();
737 RowNnz = L_cols_heap.size() + orig_U_len;
738 rownorm = getDropTolerance() * rownorm / RowNnz;
741 size_type L_vals_heaplen = 0;
742 while (L_cols_heaplen > 0) {
745 scalar_type multiplier = cur_row[row_k] * InvDiagU[row_k];
746 cur_row[row_k] = multiplier;
748 if (mag_mult * unorm[row_k] < rownorm) {
749 pattern[row_k] = UNUSED;
753 if (pattern[row_k] != ORIG) {
754 if (L_vals_heaplen < fillL) {
755 add_to_heap(row_k, L_vals_heap, L_vals_heaplen, vals_comp);
756 }
else if (L_vals_heaplen == 0 ||
757 mag_mult < scalar_mag(cur_row[L_vals_heap.front()])) {
758 pattern[row_k] = UNUSED;
762 pattern[L_vals_heap.front()] = UNUSED;
764 add_to_heap(row_k, L_vals_heap, L_vals_heaplen, vals_comp);
770 ArrayView<local_ordinal_type> ColIndicesU = U_tmp_idx[row_k]();
771 ArrayView<scalar_type> ColValuesU = U_tmpv[row_k]();
772 size_type ColNnzU = ColIndicesU.size();
774 for (size_type j = 0; j < ColNnzU; ++j) {
775 if (ColIndicesU[j] > row_k) {
778 if (pattern[col_j] != UNUSED) {
779 cur_row[col_j] -= tmp;
780 }
else if (scalar_mag(tmp) > rownorm) {
781 cur_row[col_j] = -tmp;
782 pattern[col_j] = FILL;
784 U_cols.push_back(col_j);
798 for (size_type i = 0; i < (size_type)ColIndicesA.size(); ++i) {
799 if (ColIndicesA[i] < row_i) {
800 L_tmp_idx[row_i].push_back(ColIndicesA[i]);
801 L_tmpv[row_i].push_back(cur_row[ColIndicesA[i]]);
802 pattern[ColIndicesA[i]] = UNUSED;
807 for (size_type j = 0; j < L_vals_heaplen; ++j) {
808 L_tmp_idx[row_i].push_back(L_vals_heap[j]);
809 L_tmpv[row_i].push_back(cur_row[L_vals_heap[j]]);
810 pattern[L_vals_heap[j]] = UNUSED;
818#ifdef IFPACK2_WRITE_ILUT_FACTORS
819 for (size_type ii = 0; ii < L_tmp_idx[row_i].size(); ++ii) {
820 ofsL << row_i <<
" " << L_tmp_idx[row_i][ii] <<
" "
821 << L_tmpv[row_i][ii] << std::endl;
826 if (cur_row[row_i] == zero) {
827 std::cerr <<
"Ifpack2::ILUT::Compute: zero pivot encountered! "
828 <<
"Replacing with rownorm and continuing..."
829 <<
"(You may need to set the parameter "
830 <<
"'fact: absolute threshold'.)" << std::endl;
831 cur_row[row_i] = rownorm;
833 InvDiagU[row_i] = one / cur_row[row_i];
836 U_tmp_idx[row_i].push_back(row_i);
837 U_tmpv[row_i].push_back(cur_row[row_i]);
838 unorm[row_i] = scalar_mag(cur_row[row_i]);
839 pattern[row_i] = UNUSED;
845 size_type U_vals_heaplen = 0;
846 for (size_type j = 1; j < U_cols.size(); ++j) {
848 if (pattern[col] != ORIG) {
849 if (U_vals_heaplen < fillU) {
850 add_to_heap(col, U_vals_heap, U_vals_heaplen, vals_comp);
851 }
else if (U_vals_heaplen != 0 && scalar_mag(cur_row[col]) >
852 scalar_mag(cur_row[U_vals_heap.front()])) {
854 add_to_heap(col, U_vals_heap, U_vals_heaplen, vals_comp);
857 U_tmp_idx[row_i].push_back(col);
858 U_tmpv[row_i].push_back(cur_row[col]);
859 unorm[row_i] += scalar_mag(cur_row[col]);
861 pattern[col] = UNUSED;
864 for (size_type j = 0; j < U_vals_heaplen; ++j) {
865 U_tmp_idx[row_i].push_back(U_vals_heap[j]);
866 U_tmpv[row_i].push_back(cur_row[U_vals_heap[j]]);
867 unorm[row_i] += scalar_mag(cur_row[U_vals_heap[j]]);
870 unorm[row_i] /= (orig_U_len + U_vals_heaplen);
872#ifdef IFPACK2_WRITE_ILUT_FACTORS
873 for (
int ii = 0; ii < U_tmp_idx[row_i].size(); ++ii) {
874 ofsU << row_i <<
" " << U_tmp_idx[row_i][ii] <<
" "
875 << U_tmpv[row_i][ii] << std::endl;
886 Array<size_t> nnzPerRow(myNumRows);
892 L_solver_->setMatrix(Teuchos::null);
893 U_solver_->setMatrix(Teuchos::null);
896 nnzPerRow[row_i] = L_tmp_idx[row_i].size();
899 L_ = rcp(
new crs_matrix_type(A_local_->getRowMap(), A_local_->getColMap(),
903 L_->insertLocalValues(row_i, L_tmp_idx[row_i](), L_tmpv[row_i]());
909 nnzPerRow[row_i] = U_tmp_idx[row_i].size();
912 U_ = rcp(
new crs_matrix_type(A_local_->getRowMap(), A_local_->getColMap(),
916 U_->insertLocalValues(row_i, U_tmp_idx[row_i](), U_tmpv[row_i]());
921 L_solver_->setMatrix(L_);
922 L_solver_->initialize();
923 L_solver_->compute();
925 U_solver_->setMatrix(U_);
926 U_solver_->initialize();
927 U_solver_->compute();
931 Kokkos::Profiling::ScopedRegion region_total(
"Ifpack2::ILUT::compute::par_ilut");
935 if (this->isComputed()) {
936 Kokkos::resize(L_rowmap_, L_rowmap_orig_.size());
937 Kokkos::resize(U_rowmap_, U_rowmap_orig_.size());
938 Kokkos::deep_copy(L_rowmap_, L_rowmap_orig_);
939 Kokkos::deep_copy(U_rowmap_, U_rowmap_orig_);
942 TEUCHOS_TEST_FOR_EXCEPTION(A_local_crs_.is_null(), std::runtime_error,
943 "Ifpack2::ILUT::compute::par_ilut: A_local_crs_ is null after initialize().");
948 if (A_local_crs_nc_ != Teuchos::null) {
949 Kokkos::Profiling::ScopedRegion region(
"Ifpack2::ILUT::compute::par_ilut::refresh_cached_source_crs_values");
950 refreshCachedSourceCrsFromRowMatrix<MatrixType>(A_local_, A_local_crs_nc_);
954 auto lclMtx = A_local_crs_->getLocalMatrixDevice();
955 A_local_rowmap_ = lclMtx.graph.row_map;
956 A_local_entries_ = lclMtx.graph.entries;
957 A_local_values_ = lclMtx.values;
961 auto par_ilut_handle = KernelHandle_->get_par_ilut_handle();
962 auto nnzL = par_ilut_handle->get_nnzL();
963 static_graph_entries_t L_entries_ = static_graph_entries_t(
"L_entries", nnzL);
964 local_matrix_values_t L_values_ = local_matrix_values_t(
"L_values", nnzL);
966 auto nnzU = par_ilut_handle->get_nnzU();
967 static_graph_entries_t U_entries_ = static_graph_entries_t(
"U_entries", nnzU);
968 local_matrix_values_t U_values_ = local_matrix_values_t(
"U_values", nnzU);
971 Kokkos::Profiling::ScopedRegion region(
"Ifpack2::ILUT::compute::par_ilut::numeric");
972 KokkosSparse::Experimental::par_ilut_numeric(KernelHandle_.getRawPtr(),
973 A_local_rowmap_, A_local_entries_, A_local_values_,
974 L_rowmap_, L_entries_, L_values_, U_rowmap_, U_entries_, U_values_);
978 Kokkos::Profiling::ScopedRegion region(
"Ifpack2::ILUT::compute::par_ilut::build_factors");
979 auto L_kokkosCrsGraph = local_graph_device_type(L_entries_, L_rowmap_);
980 auto U_kokkosCrsGraph = local_graph_device_type(U_entries_, U_rowmap_);
982 local_matrix_device_type L_localCrsMatrix_device;
983 L_localCrsMatrix_device = local_matrix_device_type(
"L_Factor_localmatrix",
984 A_local_->getLocalNumRows(),
989 A_local_crs_->getRowMap(),
990 A_local_crs_->getColMap(),
991 A_local_crs_->getDomainMap(),
992 A_local_crs_->getRangeMap(),
993 A_local_crs_->getGraph()->getImporter(),
994 A_local_crs_->getGraph()->getExporter()));
996 local_matrix_device_type U_localCrsMatrix_device;
997 U_localCrsMatrix_device = local_matrix_device_type(
"U_Factor_localmatrix",
998 A_local_->getLocalNumRows(),
1003 A_local_crs_->getRowMap(),
1004 A_local_crs_->getColMap(),
1005 A_local_crs_->getDomainMap(),
1006 A_local_crs_->getRangeMap(),
1007 A_local_crs_->getGraph()->getImporter(),
1008 A_local_crs_->getGraph()->getExporter()));
1012 Kokkos::Profiling::ScopedRegion region(
"Ifpack2::ILUT::compute::par_ilut::solver_setup");
1013 L_solver_->setMatrix(L_);
1014 L_solver_->compute();
1015 U_solver_->setMatrix(U_);
1016 U_solver_->compute();
1021 ComputeTime_ += (timer.wallTime() - startTime);