10 #ifndef IFPACK2_MDF_DEF_HPP
11 #define IFPACK2_MDF_DEF_HPP
13 #include "Ifpack2_LocalFilter.hpp"
15 #include "Tpetra_CrsMatrix.hpp"
16 #include "Teuchos_StandardParameterEntryValidators.hpp"
17 #include "Ifpack2_LocalSparseTriangularSolver.hpp"
18 #include "Ifpack2_Details_getParamTryingTypes.hpp"
19 #include "Kokkos_Core.hpp"
20 #include "Kokkos_Sort.hpp"
21 #include "KokkosKernels_Sorting.hpp"
23 #include <type_traits>
31 template <
class dev_view_t>
32 auto copy_view(
const dev_view_t& vals) {
33 using Kokkos::view_alloc;
34 using Kokkos::WithoutInitializing;
35 typename dev_view_t::non_const_type newvals(view_alloc(vals.label(), WithoutInitializing), vals.extent(0));
36 Kokkos::deep_copy(newvals, vals);
40 template <
class array_t,
class dev_view_t>
41 void copy_dev_view_to_host_array(array_t& array,
const dev_view_t& dev_view) {
42 using host_view_t =
typename dev_view_t::HostMirror;
45 const auto ext = dev_view.extent(0);
48 ext !=
size_t(array.size()), std::logic_error,
49 "Ifpack2::MDF::copy_dev_view_to_host_array: "
50 "Size of permuations on host and device do not match. "
51 "Please report this bug to the Ifpack2 developers.");
54 Kokkos::deep_copy(host_view_t(array.get(), ext), dev_view);
57 template <
class scalar_type,
class local_ordinal_type,
class global_ordinal_type,
class node_type>
58 void applyReorderingPermutations(
59 const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
60 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
63 "Ifpack2::MDF::applyReorderingPermuations ERROR: X.getNumVectors() != Y.getNumVectors().");
68 for (
size_t k = 0; k < X.getNumVectors(); k++)
69 for (local_ordinal_type i = 0; (size_t)i < X.getLocalLength(); i++)
70 y_ptr[k][perm[i]] = x_ptr[k][i];
73 template <
class scalar_type,
class local_ordinal_type,
class global_ordinal_type,
class node_type>
74 auto get_local_crs_row_matrix(
75 Teuchos::RCP<
const Tpetra::RowMatrix<scalar_type, local_ordinal_type, global_ordinal_type, node_type>> A_local) {
79 using Teuchos::rcp_const_cast;
80 using Teuchos::rcp_dynamic_cast;
82 using crs_matrix_type = Tpetra::CrsMatrix<scalar_type, local_ordinal_type, global_ordinal_type, node_type>;
84 using nonconst_local_inds_host_view_type =
typename crs_matrix_type::nonconst_local_inds_host_view_type;
85 using nonconst_values_host_view_type =
typename crs_matrix_type::nonconst_values_host_view_type;
87 RCP<const crs_matrix_type> A_local_crs = rcp_dynamic_cast<
const crs_matrix_type>(A_local);
88 if (A_local_crs.is_null()) {
89 local_ordinal_type numRows = A_local->getLocalNumRows();
90 Array<size_t> entriesPerRow(numRows);
91 for (local_ordinal_type i = 0; i < numRows; i++) {
92 entriesPerRow[i] = A_local->getNumEntriesInLocalRow(i);
94 RCP<crs_matrix_type> A_local_crs_nc =
95 rcp(
new crs_matrix_type(A_local->getRowMap(),
99 nonconst_local_inds_host_view_type indices(
"indices", A_local->getLocalMaxNumRowEntries());
100 nonconst_values_host_view_type values(
"values", A_local->getLocalMaxNumRowEntries());
101 for (local_ordinal_type i = 0; i < numRows; i++) {
102 size_t numEntries = 0;
103 A_local->getLocalRowCopy(i, indices, values, numEntries);
104 A_local_crs_nc->insertLocalValues(i, numEntries, reinterpret_cast<scalar_type*>(values.data()), indices.data());
106 A_local_crs_nc->fillComplete(A_local->getDomainMap(), A_local->getRangeMap());
107 A_local_crs = rcp_const_cast<
const crs_matrix_type>(A_local_crs_nc);
117 template <
class MatrixType>
123 , isAllocated_(false)
124 , isInitialized_(false)
129 , initializeTime_(0.0)
133 allocatePermutations();
136 template <
class MatrixType>
142 , isAllocated_(false)
143 , isInitialized_(false)
148 , initializeTime_(0.0)
152 allocatePermutations();
155 template <
class MatrixType>
160 if (force || permutations_.is_null() || A_->getLocalNumRows() != size_t(permutations_.size())) {
161 permutations_ = Teuchos::null;
162 reversePermutations_ = Teuchos::null;
163 permutations_ = permutations_type(A_->getLocalNumRows());
164 reversePermutations_ = permutations_type(A_->getLocalNumRows());
168 template <
class MatrixType>
169 void MDF<MatrixType>::allocateSolvers() {
170 L_solver_ = Teuchos::null;
171 U_solver_ = Teuchos::null;
172 L_solver_ =
Teuchos::rcp(
new LocalSparseTriangularSolver<row_matrix_type>());
173 L_solver_->setObjectLabel(
"lower");
174 U_solver_ =
Teuchos::rcp(
new LocalSparseTriangularSolver<row_matrix_type>());
175 U_solver_->setObjectLabel(
"upper");
178 template <
class MatrixType>
185 isAllocated_ =
false;
186 isInitialized_ =
false;
188 A_local_ = Teuchos::null;
189 MDF_handle_ = Teuchos::null;
196 if (!L_solver_.is_null()) {
197 L_solver_->setMatrix(Teuchos::null);
199 if (!U_solver_.is_null()) {
200 U_solver_->setMatrix(Teuchos::null);
207 allocatePermutations(
true);
211 template <
class MatrixType>
215 L_.is_null(), std::runtime_error,
216 "Ifpack2::MDF::getL: The L factor "
217 "is null. Please call initialize() and compute() "
218 "before calling this method. If the input matrix has not yet been set, "
219 "you must first call setMatrix() with a nonnull input matrix before you "
220 "may call initialize() or compute().");
224 template <
class MatrixType>
228 permutations_.is_null(), std::runtime_error,
229 "Ifpack2::MDF::getPermutations: "
230 "The permulations are null. Please call initialize() and compute() "
231 "before calling this method. If the input matrix has not yet been set, "
232 "you must first call setMatrix() with a nonnull input matrix before you "
233 "may call initialize() or compute().");
236 template <
class MatrixType>
240 reversePermutations_.is_null(), std::runtime_error,
241 "Ifpack2::MDF::getReversePermutations: "
242 "The permulations are null. Please call initialize() and compute() "
243 "before calling this method. If the input matrix has not yet been set, "
244 "you must first call setMatrix() with a nonnull input matrix before you "
245 "may call initialize() or compute().");
249 template <
class MatrixType>
253 U_.is_null(), std::runtime_error,
254 "Ifpack2::MDF::getU: The U factor "
255 "is null. Please call initialize() and compute() "
256 "before calling this method. If the input matrix has not yet been set, "
257 "you must first call setMatrix() with a nonnull input matrix before you "
258 "may call initialize() or compute().");
262 template <
class MatrixType>
265 A_.
is_null(), std::runtime_error,
266 "Ifpack2::MDF::getNodeSmootherComplexity: "
267 "The input matrix A is null. Please call setMatrix() with a nonnull "
268 "input matrix, then call compute(), before calling this method.");
270 if (!L_.is_null() && !U_.is_null())
271 return A_->getLocalNumEntries() + L_->getLocalNumEntries() + U_->getLocalNumEntries();
276 template <
class MatrixType>
282 A_.
is_null(), std::runtime_error,
283 "Ifpack2::MDF::getDomainMap: "
284 "The matrix is null. Please call setMatrix() with a nonnull input "
285 "before calling this method.");
289 L_.is_null(), std::runtime_error,
290 "Ifpack2::MDF::getDomainMap: "
291 "The computed graph is null. Please call initialize() and compute() before calling "
293 return L_->getDomainMap();
296 template <
class MatrixType>
302 A_.
is_null(), std::runtime_error,
303 "Ifpack2::MDF::getRangeMap: "
304 "The matrix is null. Please call setMatrix() with a nonnull input "
305 "before calling this method.");
309 L_.is_null(), std::runtime_error,
310 "Ifpack2::MDF::getRangeMap: "
311 "The computed graph is null. Please call initialize() abd compute() before calling "
313 return L_->getRangeMap();
316 template <
class MatrixType>
319 using Details::getParamTryingTypes;
323 const char prefix[] =
"Ifpack2::MDF: ";
327 double overalloc = 2.;
339 const std::string paramName(
"fact: mdf level-of-fill");
340 getParamTryingTypes<int, int, global_ordinal_type, double, float>(fillLevel, params, paramName, prefix);
342 TEUCHOS_TEST_FOR_EXCEPTION(fillLevel != 0, std::runtime_error, prefix <<
"MDF with level of fill != 0 is not yet implemented.");
345 const std::string paramName(
"Verbosity");
346 getParamTryingTypes<int, int, global_ordinal_type, double, float>(verbosity, params, paramName, prefix);
349 const std::string paramName(
"fact: mdf overalloc");
350 getParamTryingTypes<double, double>(overalloc, params, paramName, prefix);
354 L_solver_->setParameters(params);
355 U_solver_->setParameters(params);
361 LevelOfFill_ = fillLevel;
362 Overalloc_ = overalloc;
363 Verbosity_ = verbosity;
366 template <
class MatrixType>
372 template <
class MatrixType>
378 template <
class MatrixType>
383 using Teuchos::rcp_dynamic_cast;
384 using Teuchos::rcp_implicit_cast;
389 if (A->getRowMap()->getComm()->getSize() == 1 ||
390 A->getRowMap()->isSameAs(*(A->getColMap()))) {
397 RCP<const LocalFilter<row_matrix_type>> A_lf_r =
398 rcp_dynamic_cast<
const LocalFilter<row_matrix_type>>(A);
399 if (!A_lf_r.is_null()) {
400 return rcp_implicit_cast<
const row_matrix_type>(A_lf_r);
405 return rcp(
new LocalFilter<row_matrix_type>(A));
409 template <
class MatrixType>
415 using Teuchos::rcp_const_cast;
416 using Teuchos::rcp_dynamic_cast;
417 using Teuchos::rcp_implicit_cast;
418 const char prefix[] =
"Ifpack2::MDF::initialize: ";
421 "call setMatrix() with a nonnull input before calling this method.");
423 "fill complete. You may not invoke initialize() or compute() with this "
424 "matrix until the matrix is fill complete. If your matrix is a "
425 "Tpetra::CrsMatrix, please call fillComplete on it (with the domain and "
426 "range Maps, if appropriate) before calling this method.");
429 double startTime = timer.wallTime();
440 isInitialized_ =
false;
441 isAllocated_ =
false;
443 MDF_handle_ = Teuchos::null;
445 A_local_ = makeLocalFilter(A_);
447 A_local_.is_null(), std::logic_error,
448 "Ifpack2::MDF::initialize: "
449 "makeLocalFilter returned null; it failed to compute A_local. "
450 "Please report this bug to the Ifpack2 developers.");
458 RCP<const crs_matrix_type> A_local_crs = Details::MDFImpl::get_local_crs_row_matrix(A_local_);
460 auto A_local_device = A_local_crs->getLocalMatrixDevice();
461 MDF_handle_ =
rcp(
new MDF_handle_device_type(A_local_device));
462 MDF_handle_->set_verbosity(Verbosity_);
464 KokkosSparse::Experimental::mdf_symbolic(A_local_device, *MDF_handle_);
469 checkOrderingConsistency(*A_local_);
472 isInitialized_ =
true;
474 initializeTime_ += (timer.wallTime() - startTime);
477 template <
class MatrixType>
485 bool gidsAreConsistentlyOrdered =
true;
486 global_ordinal_type indexOfInconsistentGID = 0;
487 for (global_ordinal_type i = 0; i < rowGIDs.
size(); ++i) {
488 if (rowGIDs[i] != colGIDs[i]) {
489 gidsAreConsistentlyOrdered =
false;
490 indexOfInconsistentGID = i;
495 "The ordering of the local GIDs in the row and column maps is not the same"
497 <<
"at index " << indexOfInconsistentGID
498 <<
". Consistency is required, as all calculations are done with"
500 <<
"local indexing.");
503 template <
class MatrixType>
509 using Teuchos::rcp_const_cast;
510 using Teuchos::rcp_dynamic_cast;
511 const char prefix[] =
"Ifpack2::MDF::compute: ";
517 "call setMatrix() with a nonnull input before calling this method.");
519 "fill complete. You may not invoke initialize() or compute() with this "
520 "matrix until the matrix is fill complete. If your matrix is a "
521 "Tpetra::CrsMatrix, please call fillComplete on it (with the domain and "
522 "range Maps, if appropriate) before calling this method.");
524 if (!isInitialized()) {
532 double startTime = timer.
wallTime();
537 RCP<const crs_matrix_type> A_local_crs = Details::MDFImpl::get_local_crs_row_matrix(A_local_);
540 auto A_local_device = A_local_crs->getLocalMatrixDevice();
542 KokkosSparse::Experimental::mdf_numeric(A_local_device, *MDF_handle_);
546 Details::MDFImpl::copy_dev_view_to_host_array(reversePermutations_, MDF_handle_->permutation);
547 Details::MDFImpl::copy_dev_view_to_host_array(permutations_, MDF_handle_->permutation_inv);
552 auto L_mdf = MDF_handle_->getL();
554 A_local_->getRowMap(),
555 A_local_->getColMap(),
556 Details::MDFImpl::copy_view(L_mdf.graph.row_map),
557 Details::MDFImpl::copy_view(L_mdf.graph.entries),
558 Details::MDFImpl::copy_view(L_mdf.values)));
561 auto U_mdf = MDF_handle_->getU();
563 A_local_->getRowMap(),
564 A_local_->getColMap(),
565 Details::MDFImpl::copy_view(U_mdf.graph.row_map),
566 Details::MDFImpl::copy_view(U_mdf.graph.entries),
567 Details::MDFImpl::copy_view(U_mdf.values)));
571 L_solver_->setMatrix(L_);
572 L_solver_->initialize();
573 L_solver_->compute();
574 U_solver_->setMatrix(U_);
575 U_solver_->initialize();
576 U_solver_->compute();
580 computeTime_ += (timer.
wallTime() - startTime);
583 template <
class MatrixType>
585 apply_impl(
const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
586 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
589 scalar_type beta)
const {
590 const scalar_type one = STS::one();
591 const scalar_type zero = STS::zero();
593 if (alpha == one && beta == zero) {
594 MV tmp(Y.getMap(), Y.getNumVectors());
595 Details::MDFImpl::applyReorderingPermutations(X, tmp, permutations_);
598 L_solver_->apply(tmp, Y, mode);
599 U_solver_->apply(Y, tmp, mode);
602 U_solver_->apply(tmp, Y, mode);
603 L_solver_->apply(Y, tmp, mode);
605 Details::MDFImpl::applyReorderingPermutations(tmp, Y, reversePermutations_);
617 MV Y_tmp(Y.getMap(), Y.getNumVectors());
618 apply_impl(X, Y_tmp, mode);
619 Y.update(alpha, Y_tmp, beta);
624 template <
class MatrixType>
626 apply(
const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
627 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
632 using Teuchos::rcpFromRef;
635 A_.
is_null(), std::runtime_error,
636 "Ifpack2::MDF::apply: The matrix is "
637 "null. Please call setMatrix() with a nonnull input, then initialize() "
638 "and compute(), before calling this method.");
640 !isComputed(), std::runtime_error,
641 "Ifpack2::MDF::apply: If you have not yet called compute(), "
642 "you must call compute() before calling this method.");
643 TEUCHOS_TEST_FOR_EXCEPTION(
644 X.getNumVectors() != Y.getNumVectors(), std::invalid_argument,
645 "Ifpack2::MDF::apply: X and Y do not have the same number of columns. "
646 "X.getNumVectors() = "
648 <<
" != Y.getNumVectors() = " << Y.getNumVectors() <<
".");
649 TEUCHOS_TEST_FOR_EXCEPTION(
651 "Ifpack2::MDF::apply: mode = Teuchos::CONJ_TRANS is not implemented for "
652 "complex Scalar type. Please talk to the Ifpack2 developers to get this "
653 "fixed. There is a FIXME in this file about this very issue.");
654 #ifdef HAVE_IFPACK2_DEBUG
659 for (
size_t j = 0; j < X.getNumVectors(); ++j) {
660 if (STM::isnaninf(norms[j])) {
665 TEUCHOS_TEST_FOR_EXCEPTION(!good, std::runtime_error,
"Ifpack2::MDF::apply: The 1-norm of the input X is NaN or Inf.");
667 #endif // HAVE_IFPACK2_DEBUG
670 double startTime = timer.
wallTime();
673 apply_impl(X, Y, mode, alpha, beta);
676 #ifdef HAVE_IFPACK2_DEBUG
681 for (
size_t j = 0; j < Y.getNumVectors(); ++j) {
682 if (STM::isnaninf(norms[j])) {
687 TEUCHOS_TEST_FOR_EXCEPTION(!good, std::runtime_error,
"Ifpack2::MDF::apply: The 1-norm of the output Y is NaN or Inf.");
689 #endif // HAVE_IFPACK2_DEBUG
692 applyTime_ += (timer.
wallTime() - startTime);
695 template <
class MatrixType>
697 std::ostringstream os;
702 os <<
"\"Ifpack2::MDF\": {";
703 os <<
"Initialized: " << (isInitialized() ?
"true" :
"false") <<
", "
704 <<
"Computed: " << (isComputed() ?
"true" :
"false") <<
", ";
706 os <<
"Level-of-fill: " << getLevelOfFill() <<
", ";
709 os <<
"Matrix: null";
711 os <<
"Global matrix dimensions: ["
712 << A_->getGlobalNumRows() <<
", " << A_->getGlobalNumCols() <<
"]"
713 <<
", Global nnz: " << A_->getGlobalNumEntries();
716 if (!L_solver_.is_null()) os <<
", " << L_solver_->description();
717 if (!U_solver_.is_null()) os <<
", " << U_solver_->description();
725 #define IFPACK2_MDF_INSTANT(S, LO, GO, N) \
726 template class Ifpack2::MDF<Tpetra::RowMatrix<S, LO, GO, N>>;
Tpetra::CrsMatrix< scalar_type, local_ordinal_type, global_ordinal_type, node_type > crs_matrix_type
Tpetra::CrsMatrix specialization used by this class for representing L and U.
Definition: Ifpack2_MDF_decl.hpp:87
Ifpack2::ScalingType enumerable type.
void compute()
Compute the (numeric) incomplete factorization.
Definition: Ifpack2_MDF_def.hpp:504
MDF (incomplete LU factorization with minimum discarded fill reordering) of a Tpetra sparse matrix...
Definition: Ifpack2_MDF_decl.hpp:50
permutations_type & getReversePermutations() const
Return the reverse permutations of the MDF factorization.
Definition: Ifpack2_MDF_def.hpp:238
MatrixType::node_type node_type
The Node type used by the input MatrixType.
Definition: Ifpack2_MDF_decl.hpp:69
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
std::string description() const
A one-line description of this object.
Definition: Ifpack2_MDF_def.hpp:696
Teuchos::RCP< const Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > > getRangeMap() const
Returns the Tpetra::Map object associated with the range of this operator.
Definition: Ifpack2_MDF_def.hpp:300
MatrixType::global_ordinal_type global_ordinal_type
The type of global indices in the input MatrixType.
Definition: Ifpack2_MDF_decl.hpp:66
Teuchos::RCP< const crs_matrix_type > getCrsMatrix() const
Return the input matrix A as a Tpetra::CrsMatrix, if possible; else throws.
Definition: Ifpack2_MDF_def.hpp:374
size_t getNodeSmootherComplexity() const
Get a rough estimate of cost per iteration.
Definition: Ifpack2_MDF_def.hpp:263
permutations_type & getPermutations() const
Return the permutations of the MDF factorization.
Definition: Ifpack2_MDF_def.hpp:226
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual void setMatrix(const Teuchos::RCP< const row_matrix_type > &A)
Change the matrix to be preconditioned.
Definition: Ifpack2_MDF_def.hpp:179
void setParameters(const Teuchos::ParameterList ¶ms)
Definition: Ifpack2_MDF_def.hpp:318
const crs_matrix_type & getL() const
Return the L factor of the MDF factorization.
Definition: Ifpack2_MDF_def.hpp:213
Teuchos::RCP< const Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > > getDomainMap() const
Returns the Tpetra::Map object associated with the domain of this operator.
Definition: Ifpack2_MDF_def.hpp:280
Tpetra::RowMatrix< scalar_type, local_ordinal_type, global_ordinal_type, node_type > row_matrix_type
Tpetra::RowMatrix specialization used by this class.
Definition: Ifpack2_MDF_decl.hpp:85
MatrixType::scalar_type scalar_type
The type of the entries of the input MatrixType.
Definition: Ifpack2_MDF_decl.hpp:60
Teuchos::RCP< const row_matrix_type > getMatrix() const
Get the input matrix.
Definition: Ifpack2_MDF_def.hpp:368
const crs_matrix_type & getU() const
Return the U factor of the MDF factorization.
Definition: Ifpack2_MDF_def.hpp:251
void initialize()
Initialize by computing the symbolic incomplete factorization.
Definition: Ifpack2_MDF_def.hpp:410
void apply(const Tpetra::MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > &X, Tpetra::MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > &Y, Teuchos::ETransp mode=Teuchos::NO_TRANS, scalar_type alpha=Teuchos::ScalarTraits< scalar_type >::one(), scalar_type beta=Teuchos::ScalarTraits< scalar_type >::zero()) const
Apply the (inverse of the) incomplete factorization to X, resulting in Y.
Definition: Ifpack2_MDF_def.hpp:626