Ifpack2 Templated Preconditioning Package Version 1.0
Loading...
Searching...
No Matches
Ifpack2_MDF_def.hpp
1// @HEADER
2// *****************************************************************************
3// Ifpack2: Templated Object-Oriented Algebraic Preconditioner Package
4//
5// Copyright 2009 NTESS and the Ifpack2 contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef IFPACK2_MDF_DEF_HPP
11#define IFPACK2_MDF_DEF_HPP
12
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"
20#include "Kokkos_Core.hpp"
21#include "Kokkos_Sort.hpp"
22#include "KokkosSparse_mdf.hpp"
23#include "KokkosKernels_Sorting.hpp"
24#include <exception>
25#include <type_traits>
26
27namespace Ifpack2 {
28
29namespace Details {
30
31namespace MDFImpl {
32
33template <class dev_view_t>
34auto copy_view(const dev_view_t& vals) {
35 using Kokkos::view_alloc;
36 using Kokkos::WithoutInitializing;
37 typename dev_view_t::non_const_type newvals(view_alloc(vals.label(), WithoutInitializing), vals.extent(0));
38 Kokkos::deep_copy(newvals, vals);
39 return newvals;
40}
41
42template <class array_t, class dev_view_t>
43void copy_dev_view_to_host_array(array_t& array, const dev_view_t& dev_view) {
44 using host_view_t = typename dev_view_t::host_mirror_type;
45
46 // Clear out existing and allocate
47 const auto ext = dev_view.extent(0);
48
49 TEUCHOS_TEST_FOR_EXCEPTION(
50 ext != size_t(array.size()), std::logic_error,
51 "Ifpack2::MDF::copy_dev_view_to_host_array: "
52 "Size of permuations on host and device do not match. "
53 "Please report this bug to the Ifpack2 developers.");
54
55 // Wrap array data in view and copy
56 Kokkos::deep_copy(host_view_t(array.get(), ext), dev_view);
57}
58
59template <class scalar_type, class local_ordinal_type, class global_ordinal_type, class node_type>
60void applyReorderingPermutations(
61 const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
62 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
63 const Teuchos::ArrayRCP<local_ordinal_type>& perm) {
64 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != Y.getNumVectors(), std::runtime_error,
65 "Ifpack2::MDF::applyReorderingPermuations ERROR: X.getNumVectors() != Y.getNumVectors().");
66
67 Teuchos::ArrayRCP<Teuchos::ArrayRCP<const scalar_type>> x_ptr = X.get2dView();
68 Teuchos::ArrayRCP<Teuchos::ArrayRCP<scalar_type>> y_ptr = Y.get2dViewNonConst();
69
70 for (size_t k = 0; k < X.getNumVectors(); k++)
71 for (local_ordinal_type i = 0; (size_t)i < X.getLocalLength(); i++)
72 y_ptr[k][perm[i]] = x_ptr[k][i];
73}
74
75template <class scalar_type, class local_ordinal_type, class global_ordinal_type, class node_type>
76auto get_local_crs_row_matrix(
77 Teuchos::RCP<const Tpetra::RowMatrix<scalar_type, local_ordinal_type, global_ordinal_type, node_type>> A_local) {
78 using Teuchos::Array;
79 using Teuchos::RCP;
80 using Teuchos::rcp;
81 using Teuchos::rcp_const_cast;
82 using Teuchos::rcp_dynamic_cast;
83
84 using crs_matrix_type = Tpetra::CrsMatrix<scalar_type, local_ordinal_type, global_ordinal_type, node_type>;
85
86 using nonconst_local_inds_host_view_type = typename crs_matrix_type::nonconst_local_inds_host_view_type;
87 using nonconst_values_host_view_type = typename crs_matrix_type::nonconst_values_host_view_type;
88
89 RCP<const crs_matrix_type> A_local_crs = rcp_dynamic_cast<const crs_matrix_type>(A_local);
90 if (A_local_crs.is_null()) {
91 local_ordinal_type numRows = A_local->getLocalNumRows();
92 Array<size_t> entriesPerRow(numRows);
93 for (local_ordinal_type i = 0; i < numRows; i++) {
94 entriesPerRow[i] = A_local->getNumEntriesInLocalRow(i);
95 }
96 RCP<crs_matrix_type> A_local_crs_nc =
97 rcp(new crs_matrix_type(A_local->getRowMap(),
98 A_local->getColMap(),
99 entriesPerRow()));
100 // copy entries into A_local_crs
101 nonconst_local_inds_host_view_type indices("indices", A_local->getLocalMaxNumRowEntries());
102 nonconst_values_host_view_type values("values", A_local->getLocalMaxNumRowEntries());
103 for (local_ordinal_type i = 0; i < numRows; i++) {
104 size_t numEntries = 0;
105 A_local->getLocalRowCopy(i, indices, values, numEntries);
106 A_local_crs_nc->insertLocalValues(i, numEntries, reinterpret_cast<scalar_type*>(values.data()), indices.data());
107 }
108 A_local_crs_nc->fillComplete(A_local->getDomainMap(), A_local->getRangeMap());
109 A_local_crs = rcp_const_cast<const crs_matrix_type>(A_local_crs_nc);
110 }
111
112 return A_local_crs;
113}
114
115} // namespace MDFImpl
116
117} // namespace Details
118
119template <class MatrixType>
120MDF<MatrixType>::MDF(const Teuchos::RCP<const row_matrix_type>& Matrix_in)
121 : A_(Matrix_in)
122 , Verbosity_(0)
123 , LevelOfFill_(0)
124 , Overalloc_(2.)
125 , isAllocated_(false)
126 , isInitialized_(false)
127 , isComputed_(false)
128 , numInitialize_(0)
129 , numCompute_(0)
130 , numApply_(0)
131 , initializeTime_(0.0)
132 , computeTime_(0.0)
133 , applyTime_(0.0) {
134 allocateSolvers();
135 allocatePermutations();
136}
137
138template <class MatrixType>
139MDF<MatrixType>::MDF(const Teuchos::RCP<const crs_matrix_type>& Matrix_in)
140 : A_(Matrix_in)
141 , Verbosity_(0)
142 , LevelOfFill_(0)
143 , Overalloc_(2.)
144 , isAllocated_(false)
145 , isInitialized_(false)
146 , isComputed_(false)
147 , numInitialize_(0)
148 , numCompute_(0)
149 , numApply_(0)
150 , initializeTime_(0.0)
151 , computeTime_(0.0)
152 , applyTime_(0.0) {
153 allocateSolvers();
154 allocatePermutations();
155}
156
157template <class MatrixType>
159 if (A_.is_null()) return;
160
161 // Allocate arrays as soon as size as known so their pointer is availabe
162 if (force || permutations_.is_null() || A_->getLocalNumRows() != size_t(permutations_.size())) {
163 permutations_ = Teuchos::null;
164 reversePermutations_ = Teuchos::null;
165 permutations_ = permutations_type(A_->getLocalNumRows());
166 reversePermutations_ = permutations_type(A_->getLocalNumRows());
167 }
168}
169
170template <class MatrixType>
171void MDF<MatrixType>::allocateSolvers() {
172 L_solver_ = Teuchos::null;
173 U_solver_ = Teuchos::null;
174 L_solver_ = Teuchos::rcp(new LocalSparseTriangularSolver<row_matrix_type>());
175 L_solver_->setObjectLabel("lower");
176 U_solver_ = Teuchos::rcp(new LocalSparseTriangularSolver<row_matrix_type>());
177 U_solver_->setObjectLabel("upper");
178}
179
180template <class MatrixType>
181void MDF<MatrixType>::setMatrix(const Teuchos::RCP<const row_matrix_type>& A) {
182 // It's legal for A to be null; in that case, you may not call
183 // initialize() until calling setMatrix() with a nonnull input.
184 // Regardless, setting the matrix invalidates any previous
185 // factorization.
186 if (A.getRawPtr() != A_.getRawPtr()) {
187 isAllocated_ = false;
188 isInitialized_ = false;
189 isComputed_ = false;
190 A_local_ = Teuchos::null;
191 MDF_handle_ = Teuchos::null;
192
193 // The sparse triangular solvers get a triangular factor as their
194 // input matrix. The triangular factors L_ and U_ are getting
195 // reset, so we reset the solvers' matrices to null. Do that
196 // before setting L_ and U_ to null, so that latter step actually
197 // frees the factors.
198 if (!L_solver_.is_null()) {
199 L_solver_->setMatrix(Teuchos::null);
200 }
201 if (!U_solver_.is_null()) {
202 U_solver_->setMatrix(Teuchos::null);
203 }
204
205 L_ = Teuchos::null;
206 U_ = Teuchos::null;
207 A_ = A;
208
209 allocatePermutations(true);
210 }
211}
212
213template <class MatrixType>
216 TEUCHOS_TEST_FOR_EXCEPTION(
217 L_.is_null(), std::runtime_error,
218 "Ifpack2::MDF::getL: The L factor "
219 "is null. Please call initialize() and compute() "
220 "before calling this method. If the input matrix has not yet been set, "
221 "you must first call setMatrix() with a nonnull input matrix before you "
222 "may call initialize() or compute().");
223 return *L_;
224}
225
226template <class MatrixType>
227typename MDF<MatrixType>::permutations_type&
229 TEUCHOS_TEST_FOR_EXCEPTION(
230 permutations_.is_null(), std::runtime_error,
231 "Ifpack2::MDF::getPermutations: "
232 "The permulations are null. Please call initialize() and compute() "
233 "before calling this method. If the input matrix has not yet been set, "
234 "you must first call setMatrix() with a nonnull input matrix before you "
235 "may call initialize() or compute().");
236 return const_cast<permutations_type&>(permutations_);
237}
238template <class MatrixType>
239typename MDF<MatrixType>::permutations_type&
241 TEUCHOS_TEST_FOR_EXCEPTION(
242 reversePermutations_.is_null(), std::runtime_error,
243 "Ifpack2::MDF::getReversePermutations: "
244 "The permulations are null. Please call initialize() and compute() "
245 "before calling this method. If the input matrix has not yet been set, "
246 "you must first call setMatrix() with a nonnull input matrix before you "
247 "may call initialize() or compute().");
248 return const_cast<permutations_type&>(reversePermutations_);
249}
250
251template <class MatrixType>
254 TEUCHOS_TEST_FOR_EXCEPTION(
255 U_.is_null(), std::runtime_error,
256 "Ifpack2::MDF::getU: The U factor "
257 "is null. Please call initialize() and compute() "
258 "before calling this method. If the input matrix has not yet been set, "
259 "you must first call setMatrix() with a nonnull input matrix before you "
260 "may call initialize() or compute().");
261 return *U_;
262}
263
264template <class MatrixType>
266 TEUCHOS_TEST_FOR_EXCEPTION(
267 A_.is_null(), std::runtime_error,
268 "Ifpack2::MDF::getNodeSmootherComplexity: "
269 "The input matrix A is null. Please call setMatrix() with a nonnull "
270 "input matrix, then call compute(), before calling this method.");
271 // MDF methods cost roughly one apply + the nnz in the upper+lower triangles
272 if (!L_.is_null() && !U_.is_null())
273 return A_->getLocalNumEntries() + L_->getLocalNumEntries() + U_->getLocalNumEntries();
274 else
275 return 0;
276}
277
278template <class MatrixType>
279Teuchos::RCP<const Tpetra::Map<typename MDF<MatrixType>::local_ordinal_type,
283 TEUCHOS_TEST_FOR_EXCEPTION(
284 A_.is_null(), std::runtime_error,
285 "Ifpack2::MDF::getDomainMap: "
286 "The matrix is null. Please call setMatrix() with a nonnull input "
287 "before calling this method.");
288
289 // FIXME (mfh 25 Jan 2014) Shouldn't this just come from A_?
290 TEUCHOS_TEST_FOR_EXCEPTION(
291 L_.is_null(), std::runtime_error,
292 "Ifpack2::MDF::getDomainMap: "
293 "The computed graph is null. Please call initialize() and compute() before calling "
294 "this method.");
295 return L_->getDomainMap();
296}
297
298template <class MatrixType>
299Teuchos::RCP<const Tpetra::Map<typename MDF<MatrixType>::local_ordinal_type,
303 TEUCHOS_TEST_FOR_EXCEPTION(
304 A_.is_null(), std::runtime_error,
305 "Ifpack2::MDF::getRangeMap: "
306 "The matrix is null. Please call setMatrix() with a nonnull input "
307 "before calling this method.");
308
309 // FIXME (mfh 25 Jan 2014) Shouldn't this just come from A_?
310 TEUCHOS_TEST_FOR_EXCEPTION(
311 L_.is_null(), std::runtime_error,
312 "Ifpack2::MDF::getRangeMap: "
313 "The computed graph is null. Please call initialize() abd compute() before calling "
314 "this method.");
315 return L_->getRangeMap();
316}
317
318template <class MatrixType>
320 setParameters(const Teuchos::ParameterList& params) {
321 using Details::getParamTryingTypes;
322 using Teuchos::Array;
323 using Teuchos::ParameterList;
324 using Teuchos::RCP;
325 const char prefix[] = "Ifpack2::MDF: ";
326
327 // Default values of the various parameters.
328 int fillLevel = 0;
329 double overalloc = 2.;
330 int verbosity = 0;
331
332 // "fact: mdf level-of-fill" parsing is more complicated, because
333 // we want to allow as many types as make sense. int is the native
334 // type, but we also want to accept double (for backwards
335 // compatibilty with ILUT). You can't cast arbitrary magnitude_type
336 // (e.g., Sacado::MP::Vector) to int, so we use float instead, to
337 // get coverage of the most common magnitude_type cases. Weirdly,
338 // there's an Ifpack2 test that sets the fill level as a
339 // global_ordinal_type.
340 {
341 const std::string paramName("fact: mdf level-of-fill");
342 getParamTryingTypes<int, int, global_ordinal_type, double, float>(fillLevel, params, paramName, prefix);
343
344 TEUCHOS_TEST_FOR_EXCEPTION(fillLevel != 0, std::runtime_error, prefix << "MDF with level of fill != 0 is not yet implemented.");
345 }
346 {
347 const std::string paramName("Verbosity");
348 getParamTryingTypes<int, int, global_ordinal_type, double, float>(verbosity, params, paramName, prefix);
349 }
350 {
351 const std::string paramName("fact: mdf overalloc");
352 getParamTryingTypes<double, double>(overalloc, params, paramName, prefix);
353 }
354
355 // Forward to trisolvers.
356 L_solver_->setParameters(params);
357 U_solver_->setParameters(params);
358
359 // "Commit" the values only after validating all of them. This
360 // ensures that there are no side effects if this routine throws an
361 // exception.
362
363 LevelOfFill_ = fillLevel;
364 Overalloc_ = overalloc;
365 Verbosity_ = verbosity;
366}
367
368template <class MatrixType>
369Teuchos::RCP<const typename MDF<MatrixType>::row_matrix_type>
371 return Teuchos::rcp_implicit_cast<const row_matrix_type>(A_);
372}
373
374template <class MatrixType>
375Teuchos::RCP<const typename MDF<MatrixType>::crs_matrix_type>
377 return Teuchos::rcp_dynamic_cast<const crs_matrix_type>(A_, true);
378}
379
380template <class MatrixType>
381Teuchos::RCP<const typename MDF<MatrixType>::row_matrix_type>
382MDF<MatrixType>::makeLocalFilter(const Teuchos::RCP<const row_matrix_type>& A) {
383 using Teuchos::RCP;
384 using Teuchos::rcp;
385 using Teuchos::rcp_dynamic_cast;
386 using Teuchos::rcp_implicit_cast;
387
388 // If A_'s communicator only has one process, or if its column and
389 // row Maps are the same, then it is already local, so use it
390 // directly.
391 if (A->getRowMap()->getComm()->getSize() == 1 ||
392 A->getRowMap()->isSameAs(*(A->getColMap()))) {
393 return A;
394 }
395
396 // If A_ is already a LocalFilter, then use it directly. This
397 // should be the case if MDF is being used through
398 // AdditiveSchwarz, for example.
399 RCP<const LocalFilter<row_matrix_type>> A_lf_r =
400 rcp_dynamic_cast<const LocalFilter<row_matrix_type>>(A);
401 if (!A_lf_r.is_null()) {
402 return rcp_implicit_cast<const row_matrix_type>(A_lf_r);
403 } else {
404 // A_'s communicator has more than one process, its row Map and
405 // its column Map differ, and A_ is not a LocalFilter. Thus, we
406 // have to wrap it in a LocalFilter.
407 return rcp(new LocalFilter<row_matrix_type>(A));
408 }
409}
410
411template <class MatrixType>
413 using Teuchos::Array;
414 using Teuchos::ArrayView;
415 using Teuchos::RCP;
416 using Teuchos::rcp;
417 using Teuchos::rcp_const_cast;
418 using Teuchos::rcp_dynamic_cast;
419 using Teuchos::rcp_implicit_cast;
420 const char prefix[] = "Ifpack2::MDF::initialize: ";
421
422 TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error, prefix << "The matrix is null. Please "
423 "call setMatrix() with a nonnull input before calling this method.");
424 TEUCHOS_TEST_FOR_EXCEPTION(!A_->isFillComplete(), std::runtime_error, prefix << "The matrix is not "
425 "fill complete. You may not invoke initialize() or compute() with this "
426 "matrix until the matrix is fill complete. If your matrix is a "
427 "Tpetra::CrsMatrix, please call fillComplete on it (with the domain and "
428 "range Maps, if appropriate) before calling this method.");
429
430 Teuchos::Time timer("MDF::initialize");
431 double startTime = timer.wallTime();
432 { // Start timing
433 Teuchos::TimeMonitor timeMon(timer);
434
435 // Calling initialize() means that the user asserts that the graph
436 // of the sparse matrix may have changed. We must not just reuse
437 // the previous graph in that case.
438 //
439 // Regarding setting isAllocated_ to false: Eventually, we may want
440 // some kind of clever memory reuse strategy, but it's always
441 // correct just to blow everything away and start over.
442 isInitialized_ = false;
443 isAllocated_ = false;
444 isComputed_ = false;
445 MDF_handle_ = Teuchos::null;
446
447 A_local_ = makeLocalFilter(A_);
448 TEUCHOS_TEST_FOR_EXCEPTION(
449 A_local_.is_null(), std::logic_error,
450 "Ifpack2::MDF::initialize: "
451 "makeLocalFilter returned null; it failed to compute A_local. "
452 "Please report this bug to the Ifpack2 developers.");
453
454 // FIXME (mfh 24 Jan 2014, 26 Mar 2014) It would be more efficient
455 // to rewrite MDF so that it works with any RowMatrix input, not
456 // just CrsMatrix. (That would require rewriting mdfGraph to
457 // handle a Tpetra::RowGraph.) However, to make it work for now,
458 // we just copy the input matrix if it's not a CrsMatrix.
459 {
460 RCP<const crs_matrix_type> A_local_crs = Details::MDFImpl::get_local_crs_row_matrix(A_local_);
461
462 auto A_local_device = A_local_crs->getLocalMatrixDevice();
463 MDF_handle_ = rcp(new MDF_handle_device_type(A_local_device));
464 MDF_handle_->set_verbosity(Verbosity_);
465
466 KokkosSparse::Experimental::mdf_symbolic(A_local_device, *MDF_handle_);
467
468 isAllocated_ = true;
469 }
470
471 checkOrderingConsistency(*A_local_);
472 } // Stop timing
473
474 isInitialized_ = true;
475 ++numInitialize_;
476 initializeTime_ += (timer.wallTime() - startTime);
477}
478
479template <class MatrixType>
481 checkOrderingConsistency(const row_matrix_type& A) {
482 // First check that the local row map ordering is the same as the local portion of the column map.
483 // The extraction of the strictly lower/upper parts of A, as well as the factorization,
484 // implicitly assume that this is the case.
485 Teuchos::ArrayView<const global_ordinal_type> rowGIDs = A.getRowMap()->getLocalElementList();
486 Teuchos::ArrayView<const global_ordinal_type> colGIDs = A.getColMap()->getLocalElementList();
487 bool gidsAreConsistentlyOrdered = true;
488 global_ordinal_type indexOfInconsistentGID = 0;
489 for (global_ordinal_type i = 0; i < rowGIDs.size(); ++i) {
490 if (rowGIDs[i] != colGIDs[i]) {
491 gidsAreConsistentlyOrdered = false;
492 indexOfInconsistentGID = i;
493 break;
494 }
495 }
496 TEUCHOS_TEST_FOR_EXCEPTION(gidsAreConsistentlyOrdered == false, std::runtime_error,
497 "The ordering of the local GIDs in the row and column maps is not the same"
498 << std::endl
499 << "at index " << indexOfInconsistentGID
500 << ". Consistency is required, as all calculations are done with"
501 << std::endl
502 << "local indexing.");
503}
504
505template <class MatrixType>
507 using Teuchos::Array;
508 using Teuchos::ArrayView;
509 using Teuchos::RCP;
510 using Teuchos::rcp;
511 using Teuchos::rcp_const_cast;
512 using Teuchos::rcp_dynamic_cast;
513 const char prefix[] = "Ifpack2::MDF::compute: ";
514
515 // initialize() checks this too, but it's easier for users if the
516 // error shows them the name of the method that they actually
517 // called, rather than the name of some internally called method.
518 TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error, prefix << "The matrix is null. Please "
519 "call setMatrix() with a nonnull input before calling this method.");
520 TEUCHOS_TEST_FOR_EXCEPTION(!A_->isFillComplete(), std::runtime_error, prefix << "The matrix is not "
521 "fill complete. You may not invoke initialize() or compute() with this "
522 "matrix until the matrix is fill complete. If your matrix is a "
523 "Tpetra::CrsMatrix, please call fillComplete on it (with the domain and "
524 "range Maps, if appropriate) before calling this method.");
525
526 if (!isInitialized()) {
527 initialize(); // Don't count this in the compute() time
528 }
529
530 Teuchos::Time timer("MDF::compute");
531
532 // Start timing
533 Teuchos::TimeMonitor timeMon(timer);
534 double startTime = timer.wallTime();
535
536 isComputed_ = false;
537
538 { // Make sure values in A is picked up even in case of pattern reuse
539 RCP<const crs_matrix_type> A_local_crs = Details::MDFImpl::get_local_crs_row_matrix(A_local_);
540
541 // Compute the ordering and factorize
542 auto A_local_device = A_local_crs->getLocalMatrixDevice();
543
544 KokkosSparse::Experimental::mdf_numeric(A_local_device, *MDF_handle_);
545 }
546
547 // Ordering convention for MDF impl and here are reversed. Do reverse here to avoid confusion
548 Details::MDFImpl::copy_dev_view_to_host_array(reversePermutations_, MDF_handle_->permutation);
549 Details::MDFImpl::copy_dev_view_to_host_array(permutations_, MDF_handle_->permutation_inv);
550
551 // TMR: Need to COPY the values held by the MDF handle because the CRS matrix needs to
552 // exclusively own them and the MDF_handles use_count contribution throws that off
553 {
554 auto L_mdf = MDF_handle_->getL();
555 L_ = rcp(new crs_matrix_type(
556 A_local_->getRowMap(),
557 A_local_->getColMap(),
558 Details::MDFImpl::copy_view(L_mdf.graph.row_map),
559 Details::MDFImpl::copy_view(L_mdf.graph.entries),
560 Details::MDFImpl::copy_view(L_mdf.values)));
561 }
562 {
563 auto U_mdf = MDF_handle_->getU();
564 U_ = rcp(new crs_matrix_type(
565 A_local_->getRowMap(),
566 A_local_->getColMap(),
567 Details::MDFImpl::copy_view(U_mdf.graph.row_map),
568 Details::MDFImpl::copy_view(U_mdf.graph.entries),
569 Details::MDFImpl::copy_view(U_mdf.values)));
570 }
571 L_->fillComplete();
572 U_->fillComplete();
573 L_solver_->setMatrix(L_);
574 L_solver_->initialize();
575 L_solver_->compute();
576 U_solver_->setMatrix(U_);
577 U_solver_->initialize();
578 U_solver_->compute();
579
580 isComputed_ = true;
581 ++numCompute_;
582 computeTime_ += (timer.wallTime() - startTime);
583}
584
585template <class MatrixType>
587 apply_impl(const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
588 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
589 Teuchos::ETransp mode,
590 scalar_type alpha,
591 scalar_type beta) const {
592 const scalar_type one = STS::one();
593 const scalar_type zero = STS::zero();
594
595 if (alpha == one && beta == zero) {
596 MV tmp(Y.getMap(), Y.getNumVectors());
597 Details::MDFImpl::applyReorderingPermutations(X, tmp, permutations_);
598 if (mode == Teuchos::NO_TRANS) { // Solve L (D (U Y)) = X for Y.
599 // Start by solving L Y = X for Y.
600 L_solver_->apply(tmp, Y, mode);
601 U_solver_->apply(Y, tmp, mode); // Solve U Y = Y.
602 } else { // Solve U^P (D^P (L^P Y)) = X for Y (where P is * or T).
603 // Start by solving U^P Y = X for Y.
604 U_solver_->apply(tmp, Y, mode);
605 L_solver_->apply(Y, tmp, mode); // Solve L^P Y = Y.
606 }
607 Details::MDFImpl::applyReorderingPermutations(tmp, Y, reversePermutations_);
608 } else { // alpha != 1 or beta != 0
609 if (alpha == zero) {
610 // The special case for beta == 0 ensures that if Y contains Inf
611 // or NaN values, we replace them with 0 (following BLAS
612 // convention), rather than multiplying them by 0 to get NaN.
613 if (beta == zero) {
614 Y.putScalar(zero);
615 } else {
616 Y.scale(beta);
617 }
618 } else { // alpha != zero
619 MV Y_tmp(Y.getMap(), Y.getNumVectors());
620 apply_impl(X, Y_tmp, mode);
621 Y.update(alpha, Y_tmp, beta);
622 }
623 }
624}
625
626template <class MatrixType>
628 apply(const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
629 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
630 Teuchos::ETransp mode,
631 scalar_type alpha,
632 scalar_type beta) const {
633 using Teuchos::RCP;
634 using Teuchos::rcpFromRef;
635
636 TEUCHOS_TEST_FOR_EXCEPTION(
637 A_.is_null(), std::runtime_error,
638 "Ifpack2::MDF::apply: The matrix is "
639 "null. Please call setMatrix() with a nonnull input, then initialize() "
640 "and compute(), before calling this method.");
641 TEUCHOS_TEST_FOR_EXCEPTION(
642 !isComputed(), std::runtime_error,
643 "Ifpack2::MDF::apply: If you have not yet called compute(), "
644 "you must call compute() before calling this method.");
645 TEUCHOS_TEST_FOR_EXCEPTION(
646 X.getNumVectors() != Y.getNumVectors(), std::invalid_argument,
647 "Ifpack2::MDF::apply: X and Y do not have the same number of columns. "
648 "X.getNumVectors() = "
649 << X.getNumVectors()
650 << " != Y.getNumVectors() = " << Y.getNumVectors() << ".");
651 TEUCHOS_TEST_FOR_EXCEPTION(
652 STS::isComplex && mode == Teuchos::CONJ_TRANS, std::logic_error,
653 "Ifpack2::MDF::apply: mode = Teuchos::CONJ_TRANS is not implemented for "
654 "complex Scalar type. Please talk to the Ifpack2 developers to get this "
655 "fixed. There is a FIXME in this file about this very issue.");
657 Teuchos::Array<magnitude_type> norms(X.getNumVectors());
658 X.norm1(norms());
659 bool good = true;
660 for (size_t j = 0; j < X.getNumVectors(); ++j) {
661 if (STM::isnaninf(norms[j])) {
662 good = false;
663 break;
664 }
665 }
666 TEUCHOS_TEST_FOR_EXCEPTION(!good, std::runtime_error, "Ifpack2::MDF::apply: The 1-norm of the input X is NaN or Inf.");
667 }
668
669 Teuchos::Time timer("MDF::apply");
670 double startTime = timer.wallTime();
671 { // Start timing
672 Teuchos::TimeMonitor timeMon(timer);
673 apply_impl(X, Y, mode, alpha, beta);
674 } // end timing
675
677 Teuchos::Array<magnitude_type> norms(Y.getNumVectors());
678 Y.norm1(norms());
679 bool good = true;
680 for (size_t j = 0; j < Y.getNumVectors(); ++j) {
681 if (STM::isnaninf(norms[j])) {
682 good = false;
683 break;
684 }
685 }
686 TEUCHOS_TEST_FOR_EXCEPTION(!good, std::runtime_error, "Ifpack2::MDF::apply: The 1-norm of the output Y is NaN or Inf.");
687 }
688
689 ++numApply_;
690 applyTime_ += (timer.wallTime() - startTime);
691}
692
693template <class MatrixType>
694std::string MDF<MatrixType>::description() const {
695 std::ostringstream os;
696
697 // Output is a valid YAML dictionary in flow style. If you don't
698 // like everything on a single line, you should call describe()
699 // instead.
700 os << "\"Ifpack2::MDF\": {";
701 os << "Initialized: " << (isInitialized() ? "true" : "false") << ", "
702 << "Computed: " << (isComputed() ? "true" : "false") << ", ";
703
704 os << "Level-of-fill: " << getLevelOfFill() << ", ";
705
706 if (A_.is_null()) {
707 os << "Matrix: null";
708 } else {
709 os << "Global matrix dimensions: ["
710 << A_->getGlobalNumRows() << ", " << A_->getGlobalNumCols() << "]"
711 << ", Global nnz: " << A_->getGlobalNumEntries();
712 }
713
714 if (!L_solver_.is_null()) os << ", " << L_solver_->description();
715 if (!U_solver_.is_null()) os << ", " << U_solver_->description();
716
717 os << "}";
718 return os.str();
719}
720
721} // namespace Ifpack2
722
723#define IFPACK2_MDF_INSTANT(S, LO, GO, N) \
724 template class Ifpack2::MDF<Tpetra::RowMatrix<S, LO, GO, N>>;
725
726#endif /* IFPACK2_MDF_DEF_HPP */
Declaration of Ifpack2::Details::Behavior, a class that describes Ifpack2's run-time behavior.
Ifpack2::ScalingType enumerable type.
static bool debug()
Whether Ifpack2 is in debug mode.
Definition Ifpack2_Details_Behavior.cpp:31
MDF (incomplete LU factorization with minimum discarded fill reordering) of a Tpetra sparse matrix.
Definition Ifpack2_MDF_decl.hpp:57
void setParameters(const Teuchos::ParameterList &params)
Definition Ifpack2_MDF_def.hpp:320
const crs_matrix_type & getL() const
Return the L factor of the MDF factorization.
Definition Ifpack2_MDF_def.hpp:215
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:628
permutations_type & getReversePermutations() const
Return the reverse permutations of the MDF factorization.
Definition Ifpack2_MDF_def.hpp:240
const crs_matrix_type & getU() const
Return the U factor of the MDF factorization.
Definition Ifpack2_MDF_def.hpp:253
void compute()
Compute the (numeric) incomplete factorization.
Definition Ifpack2_MDF_def.hpp:506
void initialize()
Initialize by computing the symbolic incomplete factorization.
Definition Ifpack2_MDF_def.hpp:412
std::string description() const
A one-line description of this object.
Definition Ifpack2_MDF_def.hpp:694
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:302
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:94
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:282
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:376
MatrixType::node_type node_type
The Node type used by the input MatrixType.
Definition Ifpack2_MDF_decl.hpp:69
MatrixType::global_ordinal_type global_ordinal_type
The type of global indices in the input MatrixType.
Definition Ifpack2_MDF_decl.hpp:66
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:370
virtual void setMatrix(const Teuchos::RCP< const row_matrix_type > &A)
Change the matrix to be preconditioned.
Definition Ifpack2_MDF_def.hpp:181
size_t getNodeSmootherComplexity() const
Get a rough estimate of cost per iteration.
Definition Ifpack2_MDF_def.hpp:265
permutations_type & getPermutations() const
Return the permutations of the MDF factorization.
Definition Ifpack2_MDF_def.hpp:228
Ifpack2 implementation details.
Preconditioners and smoothers for Tpetra sparse matrices.
Definition Ifpack2_AdditiveSchwarz_decl.hpp:40