Ifpack2 Templated Preconditioning Package Version 1.0
Loading...
Searching...
No Matches
Ifpack2_ILUT_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_ILUT_DEF_HPP
11#define IFPACK2_ILUT_DEF_HPP
12
13#include <type_traits>
14#include "Teuchos_TypeNameTraits.hpp"
15#include "Teuchos_StandardParameterEntryValidators.hpp"
16#include "Teuchos_Time.hpp"
17#include "Tpetra_CrsMatrix.hpp"
18#include "KokkosSparse_par_ilut.hpp"
19#include "Kokkos_Profiling_ScopedRegion.hpp"
20
21#include "Ifpack2_Heap.hpp"
22#include "Ifpack2_LocalFilter.hpp"
23#include "Ifpack2_LocalSparseTriangularSolver.hpp"
24#include "Ifpack2_Parameters.hpp"
25#include "Ifpack2_Details_getParamTryingTypes.hpp"
26#include "Ifpack2_Details_getCrsMatrix.hpp"
27
28namespace Ifpack2 {
29
30namespace {
31
32struct IlutImplType {
33 enum Enum {
34 Serial,
35 PAR_ILUT
36 };
37
38 static void loadPLTypeOption(Teuchos::Array<std::string>& type_strs, Teuchos::Array<Enum>& type_enums) {
39 type_strs.resize(2);
40 type_strs[0] = "serial";
41 type_strs[1] = "par_ilut";
42 type_enums.resize(2);
43 type_enums[0] = Serial;
44 type_enums[1] = PAR_ILUT;
45 }
46};
47
72template <class ScalarType>
73inline typename Teuchos::ScalarTraits<ScalarType>::magnitudeType
74ilutDefaultDropTolerance() {
75 typedef Teuchos::ScalarTraits<ScalarType> STS;
76 typedef typename STS::magnitudeType magnitude_type;
77 typedef Teuchos::ScalarTraits<magnitude_type> STM;
78
79 // 1/2. Hopefully this can be represented in magnitude_type.
80 const magnitude_type oneHalf = STM::one() / (STM::one() + STM::one());
81
82 // The min ensures that in case magnitude_type has very low
83 // precision, we'll at least get some value strictly less than
84 // one.
85 return std::min(static_cast<magnitude_type>(1000) * STS::magnitude(STS::eps()), oneHalf);
86}
87
88// Full specialization for ScalarType = double.
89// This specialization preserves ILUT's previous default behavior.
90template <>
91inline Teuchos::ScalarTraits<double>::magnitudeType
92ilutDefaultDropTolerance<double>() {
93 return 1e-12;
94}
95
96template <class MatrixType>
97static Teuchos::RCP<typename ILUT<MatrixType>::crs_matrix_type>
98buildLocalCrsFromRowMatrix(const Teuchos::RCP<const typename ILUT<MatrixType>::row_matrix_type>& A_local) {
99 using ilut_type = ILUT<MatrixType>;
100 using crs_matrix_type = typename ilut_type::crs_matrix_type;
101 using local_ordinal_type = typename ilut_type::local_ordinal_type;
102 using scalar_type = typename ilut_type::scalar_type;
103 using nonconst_local_inds_host_view_type = typename ilut_type::nonconst_local_inds_host_view_type;
104 using nonconst_values_host_view_type = typename ilut_type::nonconst_values_host_view_type;
105 using Teuchos::Array;
106 using Teuchos::RCP;
107 using Teuchos::rcp;
108
109 local_ordinal_type numRows = A_local->getLocalNumRows();
110 Array<size_t> entriesPerRow(numRows);
111 for (local_ordinal_type i = 0; i < numRows; i++) {
112 entriesPerRow[i] = A_local->getNumEntriesInLocalRow(i);
113 }
114
115 RCP<crs_matrix_type> A_local_crs_nc =
116 rcp(new crs_matrix_type(A_local->getRowMap(),
117 A_local->getColMap(),
118 entriesPerRow()));
119
120 nonconst_local_inds_host_view_type indices("indices", A_local->getLocalMaxNumRowEntries());
121 nonconst_values_host_view_type values("values", A_local->getLocalMaxNumRowEntries());
122
123 for (local_ordinal_type i = 0; i < numRows; i++) {
124 size_t numEntries = 0;
125 A_local->getLocalRowCopy(i, indices, values, numEntries);
126 A_local_crs_nc->insertLocalValues(i, static_cast<local_ordinal_type>(numEntries),
127 reinterpret_cast<scalar_type*>(values.data()),
128 indices.data());
129 }
130
131 A_local_crs_nc->fillComplete(A_local->getDomainMap(), A_local->getRangeMap());
132 return A_local_crs_nc;
133}
134
135template <class MatrixType>
136static void refreshCachedSourceCrsFromRowMatrix(
137 const Teuchos::RCP<const typename ILUT<MatrixType>::row_matrix_type>& A_local,
138 const Teuchos::RCP<typename ILUT<MatrixType>::crs_matrix_type>& source_crs_nc) {
139 using ilut_type = ILUT<MatrixType>;
140 using local_ordinal_type = typename ilut_type::local_ordinal_type;
141 using scalar_type = typename ilut_type::scalar_type;
142 using nonconst_local_inds_host_view_type = typename ilut_type::nonconst_local_inds_host_view_type;
143 using nonconst_values_host_view_type = typename ilut_type::nonconst_values_host_view_type;
144
145 source_crs_nc->resumeFill();
146
147 const local_ordinal_type numRows = A_local->getLocalNumRows();
148 nonconst_local_inds_host_view_type indices("indices", A_local->getLocalMaxNumRowEntries());
149 nonconst_values_host_view_type values("values", A_local->getLocalMaxNumRowEntries());
150
151 for (local_ordinal_type i = 0; i < numRows; i++) {
152 size_t numEntries = 0;
153 A_local->getLocalRowCopy(i, indices, values, numEntries);
154 source_crs_nc->replaceLocalValues(i, static_cast<local_ordinal_type>(numEntries),
155 reinterpret_cast<scalar_type*>(values.data()),
156 indices.data());
157 }
158
159 source_crs_nc->fillComplete(A_local->getDomainMap(), A_local->getRangeMap());
160}
161
162} // namespace
163
164template <class MatrixType>
165ILUT<MatrixType>::ILUT(const Teuchos::RCP<const row_matrix_type>& A)
166 : A_(A)
167 , Athresh_(Teuchos::ScalarTraits<magnitude_type>::zero())
168 , Rthresh_(Teuchos::ScalarTraits<magnitude_type>::one())
169 , RelaxValue_(Teuchos::ScalarTraits<magnitude_type>::zero())
170 , LevelOfFill_(1.0)
171 , DropTolerance_(ilutDefaultDropTolerance<scalar_type>())
172 , par_ilut_options_{1, 0., -1, -1, 0.75, false}
173 , InitializeTime_(0.0)
174 , ComputeTime_(0.0)
175 , ApplyTime_(0.0)
176 , NumInitialize_(0)
177 , NumCompute_(0)
178 , NumApply_(0)
179 , IsInitialized_(false)
180 , IsComputed_(false)
181 , useKokkosKernelsParILUT_(false)
182
183{
184 allocateSolvers();
185}
186
187template <class MatrixType>
189 L_solver_ = Teuchos::rcp(new LocalSparseTriangularSolver<row_matrix_type>());
190 L_solver_->setObjectLabel("lower");
191 U_solver_ = Teuchos::rcp(new LocalSparseTriangularSolver<row_matrix_type>());
192 U_solver_->setObjectLabel("upper");
193}
194
195template <class MatrixType>
196void ILUT<MatrixType>::setParameters(const Teuchos::ParameterList& params) {
197 using Ifpack2::Details::getParamTryingTypes;
198 const char prefix[] = "Ifpack2::ILUT: ";
199
200 // Don't actually change the instance variables until we've checked
201 // all parameters. This ensures that setParameters satisfies the
202 // strong exception guarantee (i.e., is transactional).
203
204 // Parsing implementation type
205 IlutImplType::Enum ilutimplType = IlutImplType::Serial;
206 do {
207 static const char typeName[] = "fact: type";
208
209 if (!params.isType<std::string>(typeName)) break;
210
211 // Map std::string <-> IlutImplType::Enum.
212 Teuchos::Array<std::string> ilutimplTypeStrs;
213 Teuchos::Array<IlutImplType::Enum> ilutimplTypeEnums;
214 IlutImplType::loadPLTypeOption(ilutimplTypeStrs, ilutimplTypeEnums);
215 Teuchos::StringToIntegralParameterEntryValidator<IlutImplType::Enum>
216 s2i(ilutimplTypeStrs(), ilutimplTypeEnums(), typeName, false);
217
218 ilutimplType = s2i.getIntegralValue(params.get<std::string>(typeName));
219 } while (0);
220
221 if (ilutimplType == IlutImplType::PAR_ILUT) {
222 this->useKokkosKernelsParILUT_ = true;
223 } else {
224 this->useKokkosKernelsParILUT_ = false;
225 }
226
227 // Fill level in ILUT is a double, not a magnitude_type, because it
228 // depends on LO and GO, not on Scalar. Also, you can't cast
229 // arbitrary magnitude_type (e.g., Sacado::MP::Vector) to double.
230 double fillLevel = LevelOfFill_;
231 {
232 const std::string paramName("fact: ilut level-of-fill");
233 TEUCHOS_TEST_FOR_EXCEPTION(
234 (params.isParameter(paramName) && this->useKokkosKernelsParILUT_), std::runtime_error,
235 "Ifpack2::ILUT: Parameter " << paramName << " is meaningless for algorithm par_ilut.");
236 getParamTryingTypes<double, double, float>(fillLevel, params, paramName, prefix);
237 TEUCHOS_TEST_FOR_EXCEPTION(fillLevel < 1.0, std::runtime_error,
238 "Ifpack2::ILUT: The \"" << paramName << "\" parameter must be >= "
239 "1.0, but you set it to "
240 << fillLevel << ". For ILUT, the fill level "
241 "means something different than it does for ILU(k). ILU(0) produces "
242 "factors with the same sparsity structure as the input matrix A. For "
243 "ILUT, level-of-fill = 1.0 will produce factors with nonzeros matching "
244 "the sparsity structure of A. level-of-fill > 1.0 allows for additional "
245 "fill-in.");
246 }
247
248 magnitude_type absThresh = Athresh_;
249 {
250 const std::string paramName("fact: absolute threshold");
251 getParamTryingTypes<magnitude_type, magnitude_type, double>(absThresh, params, paramName, prefix);
252 }
253
254 magnitude_type relThresh = Rthresh_;
255 {
256 const std::string paramName("fact: relative threshold");
257 getParamTryingTypes<magnitude_type, magnitude_type, double>(relThresh, params, paramName, prefix);
258 }
259
260 magnitude_type relaxValue = RelaxValue_;
261 {
262 const std::string paramName("fact: relax value");
263 getParamTryingTypes<magnitude_type, magnitude_type, double>(relaxValue, params, paramName, prefix);
264 }
265
266 magnitude_type dropTol = DropTolerance_;
267 {
268 const std::string paramName("fact: drop tolerance");
269 getParamTryingTypes<magnitude_type, magnitude_type, double>(dropTol, params, paramName, prefix);
270 }
271
272 int par_ilut_max_iter = 20;
273 magnitude_type par_ilut_residual_norm_delta_stop = 1e-2;
274 int par_ilut_team_size = 0;
275 int par_ilut_vector_size = 0;
276 float par_ilut_fill_in_limit = 0.75;
277 bool par_ilut_verbose = false;
278 if (this->useKokkosKernelsParILUT_) {
279 par_ilut_max_iter = par_ilut_options_.max_iter;
280 par_ilut_residual_norm_delta_stop = par_ilut_options_.residual_norm_delta_stop;
281 par_ilut_team_size = par_ilut_options_.team_size;
282 par_ilut_vector_size = par_ilut_options_.vector_size;
283 par_ilut_fill_in_limit = par_ilut_options_.fill_in_limit;
284 par_ilut_verbose = par_ilut_options_.verbose;
285
286 std::string par_ilut_plist_name("parallel ILUT options");
287 if (params.isSublist(par_ilut_plist_name)) {
288 Teuchos::ParameterList const& par_ilut_plist = params.sublist(par_ilut_plist_name);
289
290 std::string paramName("maximum iterations");
291 getParamTryingTypes<int, int>(par_ilut_max_iter, par_ilut_plist, paramName, prefix);
292
293 paramName = "residual norm delta stop";
294 getParamTryingTypes<magnitude_type, magnitude_type, double>(par_ilut_residual_norm_delta_stop, par_ilut_plist, paramName, prefix);
295
296 paramName = "team size";
297 getParamTryingTypes<int, int>(par_ilut_team_size, par_ilut_plist, paramName, prefix);
298
299 paramName = "vector size";
300 getParamTryingTypes<int, int>(par_ilut_vector_size, par_ilut_plist, paramName, prefix);
301
302 paramName = "fill in limit";
303 getParamTryingTypes<float, float, double>(par_ilut_fill_in_limit, par_ilut_plist, paramName, prefix);
304
305 paramName = "verbose";
306 getParamTryingTypes<bool, bool>(par_ilut_verbose, par_ilut_plist, paramName, prefix);
307
308 } // if (params.isSublist(par_ilut_plist_name))
309
310 par_ilut_options_.max_iter = par_ilut_max_iter;
311 par_ilut_options_.residual_norm_delta_stop = par_ilut_residual_norm_delta_stop;
312 par_ilut_options_.team_size = par_ilut_team_size;
313 par_ilut_options_.vector_size = par_ilut_vector_size;
314 par_ilut_options_.fill_in_limit = par_ilut_fill_in_limit;
315 par_ilut_options_.verbose = par_ilut_verbose;
316
317 } // if (this->useKokkosKernelsParILUT_)
318
319 // Forward to trisolvers.
320 L_solver_->setParameters(params);
321 U_solver_->setParameters(params);
322
323 LevelOfFill_ = fillLevel;
324 Athresh_ = absThresh;
325 Rthresh_ = relThresh;
326 RelaxValue_ = relaxValue;
327 DropTolerance_ = dropTol;
328}
329
330template <class MatrixType>
331Teuchos::RCP<const Teuchos::Comm<int> >
333 TEUCHOS_TEST_FOR_EXCEPTION(
334 A_.is_null(), std::runtime_error,
335 "Ifpack2::ILUT::getComm: "
336 "The matrix is null. Please call setMatrix() with a nonnull input "
337 "before calling this method.");
338 return A_->getComm();
339}
340
341template <class MatrixType>
342Teuchos::RCP<const typename ILUT<MatrixType>::row_matrix_type>
344 return A_;
345}
346
347template <class MatrixType>
348Teuchos::RCP<const typename ILUT<MatrixType>::map_type>
350 TEUCHOS_TEST_FOR_EXCEPTION(
351 A_.is_null(), std::runtime_error,
352 "Ifpack2::ILUT::getDomainMap: "
353 "The matrix is null. Please call setMatrix() with a nonnull input "
354 "before calling this method.");
355 return A_->getDomainMap();
356}
357
358template <class MatrixType>
359Teuchos::RCP<const typename ILUT<MatrixType>::map_type>
361 TEUCHOS_TEST_FOR_EXCEPTION(
362 A_.is_null(), std::runtime_error,
363 "Ifpack2::ILUT::getRangeMap: "
364 "The matrix is null. Please call setMatrix() with a nonnull input "
365 "before calling this method.");
366 return A_->getRangeMap();
367}
368
369template <class MatrixType>
371 return true;
372}
373
374template <class MatrixType>
376 return NumInitialize_;
377}
378
379template <class MatrixType>
381 return NumCompute_;
382}
383
384template <class MatrixType>
386 return NumApply_;
387}
388
389template <class MatrixType>
391 return InitializeTime_;
392}
393
394template <class MatrixType>
396 return ComputeTime_;
397}
398
399template <class MatrixType>
401 return ApplyTime_;
402}
403
404template <class MatrixType>
406 TEUCHOS_TEST_FOR_EXCEPTION(
407 A_.is_null(), std::runtime_error,
408 "Ifpack2::ILUT::getNodeSmootherComplexity: "
409 "The input matrix A is null. Please call setMatrix() with a nonnull "
410 "input matrix, then call compute(), before calling this method.");
411 // ILUT methods cost roughly one apply + the nnz in the upper+lower triangles
412 return A_->getLocalNumEntries() + getLocalNumEntries();
413}
414
415template <class MatrixType>
417 return L_->getGlobalNumEntries() + U_->getGlobalNumEntries();
418}
419
420template <class MatrixType>
422 return L_->getLocalNumEntries() + U_->getLocalNumEntries();
423}
424
425template <class MatrixType>
426void ILUT<MatrixType>::setMatrix(const Teuchos::RCP<const row_matrix_type>& A) {
427 if (A.getRawPtr() != A_.getRawPtr()) {
428 // Check in serial or one-process mode if the matrix is square.
429 TEUCHOS_TEST_FOR_EXCEPTION(
430 !A.is_null() && A->getComm()->getSize() == 1 &&
431 A->getLocalNumRows() != A->getLocalNumCols(),
432 std::runtime_error,
433 "Ifpack2::ILUT::setMatrix: If A's communicator only "
434 "contains one process, then A must be square. Instead, you provided a "
435 "matrix A with "
436 << A->getLocalNumRows() << " rows and "
437 << A->getLocalNumCols() << " columns.");
438
439 // It's legal for A to be null; in that case, you may not call
440 // initialize() until calling setMatrix() with a nonnull input.
441 // Regardless, setting the matrix invalidates any previous
442 // factorization.
443 IsInitialized_ = false;
444 IsComputed_ = false;
445 A_local_ = Teuchos::null;
446 A_local_crs_ = Teuchos::null;
447 A_local_crs_nc_ = Teuchos::null;
448
449 // The sparse triangular solvers get a triangular factor as their
450 // input matrix. The triangular factors L_ and U_ are getting
451 // reset, so we reset the solvers' matrices to null. Do that
452 // before setting L_ and U_ to null, so that latter step actually
453 // frees the factors.
454 if (!L_solver_.is_null()) {
455 L_solver_->setMatrix(Teuchos::null);
456 }
457 if (!U_solver_.is_null()) {
458 U_solver_->setMatrix(Teuchos::null);
459 }
460
461 L_ = Teuchos::null;
462 U_ = Teuchos::null;
463 A_ = A;
464 }
465}
466
467template <class MatrixType>
468Teuchos::RCP<const typename ILUT<MatrixType>::row_matrix_type>
469ILUT<MatrixType>::makeLocalFilter(const Teuchos::RCP<const row_matrix_type>& A) {
470 using Teuchos::RCP;
471 using Teuchos::rcp;
472 using Teuchos::rcp_dynamic_cast;
473 using Teuchos::rcp_implicit_cast;
474
475 // If A_'s communicator only has one process, or if its column and
476 // row Maps are the same, then it is already local, so use it
477 // directly.
478 if (A->getRowMap()->getComm()->getSize() == 1 ||
479 A->getRowMap()->isSameAs(*(A->getColMap()))) {
480 return A;
481 }
482
483 // If A_ is already a LocalFilter, then use it directly. This
484 // should be the case if RILUT is being used through
485 // AdditiveSchwarz, for example.
486 RCP<const LocalFilter<row_matrix_type> > A_lf_r =
487 rcp_dynamic_cast<const LocalFilter<row_matrix_type> >(A);
488 if (!A_lf_r.is_null()) {
489 return rcp_implicit_cast<const row_matrix_type>(A_lf_r);
490 } else {
491 // A_'s communicator has more than one process, its row Map and
492 // its column Map differ, and A_ is not a LocalFilter. Thus, we
493 // have to wrap it in a LocalFilter.
494 return rcp(new LocalFilter<row_matrix_type>(A));
495 }
496}
497
498template <class MatrixType>
500 using Teuchos::Array;
501 using Teuchos::RCP;
502 using Teuchos::rcp_const_cast;
503 Teuchos::Time timer("ILUT::initialize");
504 double startTime = timer.wallTime();
505 {
506 Teuchos::TimeMonitor timeMon(timer);
507
508 // Check that the matrix is nonnull.
509 TEUCHOS_TEST_FOR_EXCEPTION(
510 A_.is_null(), std::runtime_error,
511 "Ifpack2::ILUT::initialize: "
512 "The matrix to precondition is null. Please call setMatrix() with a "
513 "nonnull input before calling this method.");
514
515 // Clear any previous computations.
516 IsInitialized_ = false;
517 IsComputed_ = false;
518 A_local_ = Teuchos::null;
519 A_local_crs_ = Teuchos::null;
520 A_local_crs_nc_ = Teuchos::null;
521 L_ = Teuchos::null;
522 U_ = Teuchos::null;
523
524 A_local_ = makeLocalFilter(A_); // Compute the local filter.
525 TEUCHOS_TEST_FOR_EXCEPTION(
526 A_local_.is_null(), std::logic_error,
527 "Ifpack2::RILUT::initialize: "
528 "makeLocalFilter returned null; it failed to compute A_local. "
529 "Please report this bug to the Ifpack2 developers.");
530
531 if (this->useKokkosKernelsParILUT_) {
532 this->KernelHandle_ = Teuchos::rcp(new kk_handle_type());
533 KernelHandle_->create_par_ilut_handle();
534 auto par_ilut_handle = KernelHandle_->get_par_ilut_handle();
535 par_ilut_handle->set_residual_norm_delta_stop(par_ilut_options_.residual_norm_delta_stop);
536 par_ilut_handle->set_team_size(par_ilut_options_.team_size);
537 par_ilut_handle->set_vector_size(par_ilut_options_.vector_size);
538 par_ilut_handle->set_max_iter(par_ilut_options_.max_iter);
539 par_ilut_handle->set_fill_in_limit(par_ilut_options_.fill_in_limit);
540 par_ilut_handle->set_verbose(par_ilut_options_.verbose);
541 par_ilut_handle->set_async_update(false);
542
543 {
544 Kokkos::Profiling::ScopedRegion region("Ifpack2::ILUT::initialize::par_ilut::get_or_build_A_local_crs");
545 A_local_crs_ = Ifpack2::Details::getCrsMatrix(A_local_);
546 if (A_local_crs_.is_null()) {
547 A_local_crs_nc_ = buildLocalCrsFromRowMatrix<MatrixType>(A_local_);
548 A_local_crs_ = A_local_crs_nc_;
549 }
550 }
551 auto A_local_crs_device = A_local_crs_->getLocalMatrixDevice();
552
553 // KokkosKernels requires unsigned
554 typedef typename Kokkos::View<usize_type*, array_layout, device_type> ulno_row_view_t;
555 const int NumMyRows = A_local_crs_->getRowMap()->getLocalNumElements();
556 L_rowmap_ = ulno_row_view_t("L_row_map", NumMyRows + 1);
557 U_rowmap_ = ulno_row_view_t("U_row_map", NumMyRows + 1);
558 L_rowmap_orig_ = ulno_row_view_t("L_row_map_orig", NumMyRows + 1);
559 U_rowmap_orig_ = ulno_row_view_t("U_row_map_orig", NumMyRows + 1);
560
561 KokkosSparse::Experimental::par_ilut_symbolic(KernelHandle_.getRawPtr(),
562 A_local_crs_device.graph.row_map, A_local_crs_device.graph.entries,
563 L_rowmap_,
564 U_rowmap_);
565
566 Kokkos::deep_copy(L_rowmap_orig_, L_rowmap_);
567 Kokkos::deep_copy(U_rowmap_orig_, U_rowmap_);
568 }
569
570 IsInitialized_ = true;
571 ++NumInitialize_;
572 } // timer scope
573 InitializeTime_ += (timer.wallTime() - startTime);
574}
575
576template <typename ScalarType>
577typename Teuchos::ScalarTraits<ScalarType>::magnitudeType
578scalar_mag(const ScalarType& s) {
579 return Teuchos::ScalarTraits<ScalarType>::magnitude(s);
580}
581
582template <class MatrixType>
584 using Teuchos::Array;
585 using Teuchos::ArrayRCP;
586 using Teuchos::ArrayView;
587 using Teuchos::as;
588 using Teuchos::rcp;
589 using Teuchos::RCP;
590 using Teuchos::rcp_const_cast;
591 using Teuchos::reduceAll;
592
593 // Don't count initialization in the compute() time.
594 if (!isInitialized()) {
595 initialize();
596 }
597
598 Teuchos::Time timer("ILUT::compute");
599 double startTime = timer.wallTime();
600 { // Timer scope for timing compute()
601 Teuchos::TimeMonitor timeMon(timer, true);
602
603 if (!this->useKokkosKernelsParILUT_) {
604 //--------------------------------------------------------------------------
605 // Ifpack2::ILUT's serial version is a translation of the Aztec ILUT
606 // implementation. The Aztec ILUT implementation was written by Ray Tuminaro.
607 //
608 // This isn't an exact translation of the Aztec ILUT algorithm, for the
609 // following reasons:
610 // 1. Minor differences result from the fact that Aztec factors a MSR format
611 // matrix in place, while the code below factors an input CrsMatrix which
612 // remains untouched and stores the resulting factors in separate L and U
613 // CrsMatrix objects.
614 // Also, the Aztec code begins by shifting the matrix pointers back
615 // by one, and the pointer contents back by one, and then using 1-based
616 // Fortran-style indexing in the algorithm. This Ifpack2 code uses C-style
617 // 0-based indexing throughout.
618 // 2. Aztec stores the inverse of the diagonal of U. This Ifpack2 code
619 // stores the non-inverted diagonal in U.
620 // The triangular solves (in Ifpack2::ILUT::apply()) are performed by
621 // calling the Tpetra::CrsMatrix::solve method on the L and U objects, and
622 // this requires U to contain the non-inverted diagonal.
623 //
624 // ABW.
625 //--------------------------------------------------------------------------
626
627 const scalar_type zero = STS::zero();
628 const scalar_type one = STS::one();
629
630 const local_ordinal_type myNumRows = A_local_->getLocalNumRows();
631
632 // If this macro is defined, files containing the L and U factors
633 // will be written. DON'T CHECK IN THE CODE WITH THIS MACRO ENABLED!!!
634 // #define IFPACK2_WRITE_ILUT_FACTORS
635#ifdef IFPACK2_WRITE_ILUT_FACTORS
636 std::ofstream ofsL("L.ifpack2_ilut.mtx", std::ios::out);
637 std::ofstream ofsU("U.ifpack2_ilut.mtx", std::ios::out);
638#endif
639
640 // Calculate how much fill will be allowed in addition to the
641 // space that corresponds to the input matrix entries.
642 double local_nnz = static_cast<double>(A_local_->getLocalNumEntries());
643 double fill = ((getLevelOfFill() - 1.0) * local_nnz) / (2 * myNumRows);
644
645 // std::ceil gives the smallest integer larger than the argument.
646 // this may give a slightly different result than Aztec's fill value in
647 // some cases.
648 double fill_ceil = std::ceil(fill);
649
650 // Similarly to Aztec, we will allow the same amount of fill for each
651 // row, half in L and half in U.
652 size_type fillL = static_cast<size_type>(fill_ceil);
653 size_type fillU = static_cast<size_type>(fill_ceil);
654
655 Array<scalar_type> InvDiagU(myNumRows, zero);
656
657 Array<Array<local_ordinal_type> > L_tmp_idx(myNumRows);
658 Array<Array<scalar_type> > L_tmpv(myNumRows);
659 Array<Array<local_ordinal_type> > U_tmp_idx(myNumRows);
660 Array<Array<scalar_type> > U_tmpv(myNumRows);
661
662 enum { UNUSED,
663 ORIG,
664 FILL };
665 local_ordinal_type max_col = myNumRows;
666
667 Array<int> pattern(max_col, UNUSED);
668 Array<scalar_type> cur_row(max_col, zero);
669 Array<magnitude_type> unorm(max_col);
670 magnitude_type rownorm;
671 Array<local_ordinal_type> L_cols_heap;
672 Array<local_ordinal_type> U_cols;
673 Array<local_ordinal_type> L_vals_heap;
674 Array<local_ordinal_type> U_vals_heap;
675
676 // A comparison object which will be used to create 'heaps' of indices
677 // that are ordered according to the corresponding values in the
678 // 'cur_row' array.
679 greater_indirect<scalar_type, local_ordinal_type> vals_comp(cur_row);
680
681 // =================== //
682 // start factorization //
683 // =================== //
684 nonconst_local_inds_host_view_type ColIndicesARCP;
685 nonconst_values_host_view_type ColValuesARCP;
686 if (!A_local_->supportsRowViews()) {
687 const size_t maxnz = A_local_->getLocalMaxNumRowEntries();
688 Kokkos::resize(ColIndicesARCP, maxnz);
689 Kokkos::resize(ColValuesARCP, maxnz);
690 }
691
692 for (local_ordinal_type row_i = 0; row_i < myNumRows; ++row_i) {
693 local_inds_host_view_type ColIndicesA;
694 values_host_view_type ColValuesA;
695 size_t RowNnz;
696
697 if (A_local_->supportsRowViews()) {
698 A_local_->getLocalRowView(row_i, ColIndicesA, ColValuesA);
699 RowNnz = ColIndicesA.size();
700 } else {
701 A_local_->getLocalRowCopy(row_i, ColIndicesARCP, ColValuesARCP, RowNnz);
702 ColIndicesA = Kokkos::subview(ColIndicesARCP, std::make_pair((size_t)0, RowNnz));
703 ColValuesA = Kokkos::subview(ColValuesARCP, std::make_pair((size_t)0, RowNnz));
704 }
705
706 // Always include the diagonal in the U factor. The value should get
707 // set in the next loop below.
708 U_cols.push_back(row_i);
709 cur_row[row_i] = zero;
710 pattern[row_i] = ORIG;
711
712 size_type L_cols_heaplen = 0;
713 rownorm = STM::zero();
714 for (size_t i = 0; i < RowNnz; ++i) {
715 if (ColIndicesA[i] < myNumRows) {
716 if (ColIndicesA[i] < row_i) {
717 add_to_heap(ColIndicesA[i], L_cols_heap, L_cols_heaplen);
718 } else if (ColIndicesA[i] > row_i) {
719 U_cols.push_back(ColIndicesA[i]);
720 }
721
722 cur_row[ColIndicesA[i]] = ColValuesA[i];
723 pattern[ColIndicesA[i]] = ORIG;
724 rownorm += scalar_mag(ColValuesA[i]);
725 }
726 }
727
728 // Alter the diagonal according to the absolute-threshold and
729 // relative-threshold values. If not set, those values default
730 // to zero and one respectively.
731 const magnitude_type rthresh = getRelativeThreshold();
732 const scalar_type& v = cur_row[row_i];
733 cur_row[row_i] = as<scalar_type>(getAbsoluteThreshold() * IFPACK2_SGN(v)) + rthresh * v;
734
735 size_type orig_U_len = U_cols.size();
736 RowNnz = L_cols_heap.size() + orig_U_len;
737 rownorm = getDropTolerance() * rownorm / RowNnz;
738
739 // The following while loop corresponds to the 'L30' goto's in Aztec.
740 size_type L_vals_heaplen = 0;
741 while (L_cols_heaplen > 0) {
742 local_ordinal_type row_k = L_cols_heap.front();
743
744 scalar_type multiplier = cur_row[row_k] * InvDiagU[row_k];
745 cur_row[row_k] = multiplier;
746 magnitude_type mag_mult = scalar_mag(multiplier);
747 if (mag_mult * unorm[row_k] < rownorm) {
748 pattern[row_k] = UNUSED;
749 rm_heap_root(L_cols_heap, L_cols_heaplen);
750 continue;
751 }
752 if (pattern[row_k] != ORIG) {
753 if (L_vals_heaplen < fillL) {
754 add_to_heap(row_k, L_vals_heap, L_vals_heaplen, vals_comp);
755 } else if (L_vals_heaplen == 0 ||
756 mag_mult < scalar_mag(cur_row[L_vals_heap.front()])) {
757 pattern[row_k] = UNUSED;
758 rm_heap_root(L_cols_heap, L_cols_heaplen);
759 continue;
760 } else {
761 pattern[L_vals_heap.front()] = UNUSED;
762 rm_heap_root(L_vals_heap, L_vals_heaplen, vals_comp);
763 add_to_heap(row_k, L_vals_heap, L_vals_heaplen, vals_comp);
764 }
765 }
766
767 /* Reduce current row */
768
769 ArrayView<local_ordinal_type> ColIndicesU = U_tmp_idx[row_k]();
770 ArrayView<scalar_type> ColValuesU = U_tmpv[row_k]();
771 size_type ColNnzU = ColIndicesU.size();
772
773 for (size_type j = 0; j < ColNnzU; ++j) {
774 if (ColIndicesU[j] > row_k) {
775 scalar_type tmp = multiplier * ColValuesU[j];
776 local_ordinal_type col_j = ColIndicesU[j];
777 if (pattern[col_j] != UNUSED) {
778 cur_row[col_j] -= tmp;
779 } else if (scalar_mag(tmp) > rownorm) {
780 cur_row[col_j] = -tmp;
781 pattern[col_j] = FILL;
782 if (col_j > row_i) {
783 U_cols.push_back(col_j);
784 } else {
785 add_to_heap(col_j, L_cols_heap, L_cols_heaplen);
786 }
787 }
788 }
789 }
790
791 rm_heap_root(L_cols_heap, L_cols_heaplen);
792 } // end of while(L_cols_heaplen) loop
793
794 // Put indices and values for L into arrays and then into the L_ matrix.
795
796 // first, the original entries from the L section of A:
797 for (size_type i = 0; i < (size_type)ColIndicesA.size(); ++i) {
798 if (ColIndicesA[i] < row_i) {
799 L_tmp_idx[row_i].push_back(ColIndicesA[i]);
800 L_tmpv[row_i].push_back(cur_row[ColIndicesA[i]]);
801 pattern[ColIndicesA[i]] = UNUSED;
802 }
803 }
804
805 // next, the L entries resulting from fill:
806 for (size_type j = 0; j < L_vals_heaplen; ++j) {
807 L_tmp_idx[row_i].push_back(L_vals_heap[j]);
808 L_tmpv[row_i].push_back(cur_row[L_vals_heap[j]]);
809 pattern[L_vals_heap[j]] = UNUSED;
810 }
811
812 // L has a one on the diagonal, but we don't explicitly store
813 // it. If we don't store it, then the kernel which performs the
814 // triangular solve can assume a unit diagonal, take a short-cut
815 // and perform faster.
816
817#ifdef IFPACK2_WRITE_ILUT_FACTORS
818 for (size_type ii = 0; ii < L_tmp_idx[row_i].size(); ++ii) {
819 ofsL << row_i << " " << L_tmp_idx[row_i][ii] << " "
820 << L_tmpv[row_i][ii] << std::endl;
821 }
822#endif
823
824 // Pick out the diagonal element, store its reciprocal.
825 if (cur_row[row_i] == zero) {
826 std::cerr << "Ifpack2::ILUT::Compute: zero pivot encountered! "
827 << "Replacing with rownorm and continuing..."
828 << "(You may need to set the parameter "
829 << "'fact: absolute threshold'.)" << std::endl;
830 cur_row[row_i] = rownorm;
831 }
832 InvDiagU[row_i] = one / cur_row[row_i];
833
834 // Non-inverted diagonal is stored for U:
835 U_tmp_idx[row_i].push_back(row_i);
836 U_tmpv[row_i].push_back(cur_row[row_i]);
837 unorm[row_i] = scalar_mag(cur_row[row_i]);
838 pattern[row_i] = UNUSED;
839
840 // Now put indices and values for U into arrays and then into the U_ matrix.
841 // The first entry in U_cols is the diagonal, which we just handled, so we'll
842 // start our loop at j=1.
843
844 size_type U_vals_heaplen = 0;
845 for (size_type j = 1; j < U_cols.size(); ++j) {
846 local_ordinal_type col = U_cols[j];
847 if (pattern[col] != ORIG) {
848 if (U_vals_heaplen < fillU) {
849 add_to_heap(col, U_vals_heap, U_vals_heaplen, vals_comp);
850 } else if (U_vals_heaplen != 0 && scalar_mag(cur_row[col]) >
851 scalar_mag(cur_row[U_vals_heap.front()])) {
852 rm_heap_root(U_vals_heap, U_vals_heaplen, vals_comp);
853 add_to_heap(col, U_vals_heap, U_vals_heaplen, vals_comp);
854 }
855 } else {
856 U_tmp_idx[row_i].push_back(col);
857 U_tmpv[row_i].push_back(cur_row[col]);
858 unorm[row_i] += scalar_mag(cur_row[col]);
859 }
860 pattern[col] = UNUSED;
861 }
862
863 for (size_type j = 0; j < U_vals_heaplen; ++j) {
864 U_tmp_idx[row_i].push_back(U_vals_heap[j]);
865 U_tmpv[row_i].push_back(cur_row[U_vals_heap[j]]);
866 unorm[row_i] += scalar_mag(cur_row[U_vals_heap[j]]);
867 }
868
869 unorm[row_i] /= (orig_U_len + U_vals_heaplen);
870
871#ifdef IFPACK2_WRITE_ILUT_FACTORS
872 for (int ii = 0; ii < U_tmp_idx[row_i].size(); ++ii) {
873 ofsU << row_i << " " << U_tmp_idx[row_i][ii] << " "
874 << U_tmpv[row_i][ii] << std::endl;
875 }
876#endif
877
878 L_cols_heap.clear();
879 U_cols.clear();
880 L_vals_heap.clear();
881 U_vals_heap.clear();
882 } // end of for(row_i) loop
883
884 // Now allocate and fill the matrices
885 Array<size_t> nnzPerRow(myNumRows);
886
887 // Make sure to release the old memory for L & U prior to recomputing to
888 // avoid bloating the high-water mark.
889 L_ = Teuchos::null;
890 U_ = Teuchos::null;
891 L_solver_->setMatrix(Teuchos::null);
892 U_solver_->setMatrix(Teuchos::null);
893
894 for (local_ordinal_type row_i = 0; row_i < myNumRows; ++row_i) {
895 nnzPerRow[row_i] = L_tmp_idx[row_i].size();
896 }
897
898 L_ = rcp(new crs_matrix_type(A_local_->getRowMap(), A_local_->getColMap(),
899 nnzPerRow()));
900
901 for (local_ordinal_type row_i = 0; row_i < myNumRows; ++row_i) {
902 L_->insertLocalValues(row_i, L_tmp_idx[row_i](), L_tmpv[row_i]());
903 }
904
905 L_->fillComplete();
906
907 for (local_ordinal_type row_i = 0; row_i < myNumRows; ++row_i) {
908 nnzPerRow[row_i] = U_tmp_idx[row_i].size();
909 }
910
911 U_ = rcp(new crs_matrix_type(A_local_->getRowMap(), A_local_->getColMap(),
912 nnzPerRow()));
913
914 for (local_ordinal_type row_i = 0; row_i < myNumRows; ++row_i) {
915 U_->insertLocalValues(row_i, U_tmp_idx[row_i](), U_tmpv[row_i]());
916 }
917
918 U_->fillComplete();
919
920 L_solver_->setMatrix(L_);
921 L_solver_->initialize();
922 L_solver_->compute();
923
924 U_solver_->setMatrix(U_);
925 U_solver_->initialize();
926 U_solver_->compute();
927
928 } // if (!this->useKokkosKernelsParILUT_)
929 else {
930 Kokkos::Profiling::ScopedRegion region_total("Ifpack2::ILUT::compute::par_ilut");
931
932 // Set L, U rowmaps back to original state. Par_ilut can change them, which invalidates them
933 // if compute is called again.
934 if (this->isComputed()) {
935 Kokkos::resize(L_rowmap_, L_rowmap_orig_.size());
936 Kokkos::resize(U_rowmap_, U_rowmap_orig_.size());
937 Kokkos::deep_copy(L_rowmap_, L_rowmap_orig_);
938 Kokkos::deep_copy(U_rowmap_, U_rowmap_orig_);
939 }
940
941 TEUCHOS_TEST_FOR_EXCEPTION(A_local_crs_.is_null(), std::runtime_error,
942 "Ifpack2::ILUT::compute::par_ilut: A_local_crs_ is null after initialize().");
943
944 // If A_local_ was not originally a CrsMatrix, initialize() built and cached
945 // a mutable CRS copy in A_local_crs_nc_. Repeated compute() calls must refresh
946 // that cached CRS with the current values of A_local_ before invoking par_ilut.
947 if (A_local_crs_nc_ != Teuchos::null) {
948 Kokkos::Profiling::ScopedRegion region("Ifpack2::ILUT::compute::par_ilut::refresh_cached_source_crs_values");
949 refreshCachedSourceCrsFromRowMatrix<MatrixType>(A_local_, A_local_crs_nc_);
950 }
951
952 { // Make sure values in A is picked up even in case of pattern reuse
953 auto lclMtx = A_local_crs_->getLocalMatrixDevice();
954 A_local_rowmap_ = lclMtx.graph.row_map;
955 A_local_entries_ = lclMtx.graph.entries;
956 A_local_values_ = lclMtx.values;
957 }
958
959 // JHU TODO Should allocation of L & U's column (aka entry) and value arrays occur here or in init()?
960 auto par_ilut_handle = KernelHandle_->get_par_ilut_handle();
961 auto nnzL = par_ilut_handle->get_nnzL();
962 static_graph_entries_t L_entries_ = static_graph_entries_t("L_entries", nnzL);
963 local_matrix_values_t L_values_ = local_matrix_values_t("L_values", nnzL);
964
965 auto nnzU = par_ilut_handle->get_nnzU();
966 static_graph_entries_t U_entries_ = static_graph_entries_t("U_entries", nnzU);
967 local_matrix_values_t U_values_ = local_matrix_values_t("U_values", nnzU);
968
969 {
970 Kokkos::Profiling::ScopedRegion region("Ifpack2::ILUT::compute::par_ilut::numeric");
971 KokkosSparse::Experimental::par_ilut_numeric(KernelHandle_.getRawPtr(),
972 A_local_rowmap_, A_local_entries_, A_local_values_,
973 L_rowmap_, L_entries_, L_values_, U_rowmap_, U_entries_, U_values_);
974 }
975
976 {
977 Kokkos::Profiling::ScopedRegion region("Ifpack2::ILUT::compute::par_ilut::build_factors");
978 auto L_kokkosCrsGraph = local_graph_device_type(L_entries_, L_rowmap_);
979 auto U_kokkosCrsGraph = local_graph_device_type(U_entries_, U_rowmap_);
980
981 local_matrix_device_type L_localCrsMatrix_device;
982 L_localCrsMatrix_device = local_matrix_device_type("L_Factor_localmatrix",
983 A_local_->getLocalNumRows(),
984 L_values_,
985 L_kokkosCrsGraph);
986
987 L_ = rcp(new crs_matrix_type(L_localCrsMatrix_device,
988 A_local_crs_->getRowMap(),
989 A_local_crs_->getColMap(),
990 A_local_crs_->getDomainMap(),
991 A_local_crs_->getRangeMap(),
992 A_local_crs_->getGraph()->getImporter(),
993 A_local_crs_->getGraph()->getExporter()));
994
995 local_matrix_device_type U_localCrsMatrix_device;
996 U_localCrsMatrix_device = local_matrix_device_type("U_Factor_localmatrix",
997 A_local_->getLocalNumRows(),
998 U_values_,
999 U_kokkosCrsGraph);
1000
1001 U_ = rcp(new crs_matrix_type(U_localCrsMatrix_device,
1002 A_local_crs_->getRowMap(),
1003 A_local_crs_->getColMap(),
1004 A_local_crs_->getDomainMap(),
1005 A_local_crs_->getRangeMap(),
1006 A_local_crs_->getGraph()->getImporter(),
1007 A_local_crs_->getGraph()->getExporter()));
1008 }
1009
1010 {
1011 Kokkos::Profiling::ScopedRegion region("Ifpack2::ILUT::compute::par_ilut::solver_setup");
1012 L_solver_->setMatrix(L_);
1013 L_solver_->compute(); // NOTE: Only do compute if the pointer changed. Otherwise, do nothing
1014 U_solver_->setMatrix(U_);
1015 U_solver_->compute(); // NOTE: Only do compute if the pointer changed. Otherwise, do nothing
1016 }
1017 } // if (!this->useKokkosKernelsParILUT_) ... else ...
1018
1019 } // Timer scope for timing compute()
1020 ComputeTime_ += (timer.wallTime() - startTime);
1021 IsComputed_ = true;
1022 ++NumCompute_;
1023} // compute()
1024
1025template <class MatrixType>
1027 apply(const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
1028 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
1029 Teuchos::ETransp mode,
1030 scalar_type alpha,
1031 scalar_type beta) const {
1032 using Teuchos::RCP;
1033 using Teuchos::rcp;
1034 using Teuchos::rcpFromRef;
1035
1036 TEUCHOS_TEST_FOR_EXCEPTION(
1037 !isComputed(), std::runtime_error,
1038 "Ifpack2::ILUT::apply: You must call compute() to compute the incomplete "
1039 "factorization, before calling apply().");
1040
1041 TEUCHOS_TEST_FOR_EXCEPTION(
1042 X.getNumVectors() != Y.getNumVectors(), std::runtime_error,
1043 "Ifpack2::ILUT::apply: X and Y must have the same number of columns. "
1044 "X has "
1045 << X.getNumVectors() << " columns, but Y has "
1046 << Y.getNumVectors() << " columns.");
1047
1048 const scalar_type one = STS::one();
1049 const scalar_type zero = STS::zero();
1050
1051 Teuchos::Time timer("ILUT::apply");
1052 double startTime = timer.wallTime();
1053 { // Start timing
1054 Teuchos::TimeMonitor timeMon(timer, true);
1055
1056 if (alpha == one && beta == zero) {
1057 if (mode == Teuchos::NO_TRANS) { // Solve L (U Y) = X for Y.
1058 // Start by solving L Y = X for Y.
1059 L_solver_->apply(X, Y, mode);
1060
1061 // Solve U Y = Y.
1062 U_solver_->apply(Y, Y, mode);
1063 } else { // Solve U^P (L^P Y)) = X for Y (where P is * or T).
1064
1065 // Start by solving U^P Y = X for Y.
1066 U_solver_->apply(X, Y, mode);
1067
1068 // Solve L^P Y = Y.
1069 L_solver_->apply(Y, Y, mode);
1070 }
1071 } else { // alpha != 1 or beta != 0
1072 if (alpha == zero) {
1073 // The special case for beta == 0 ensures that if Y contains Inf
1074 // or NaN values, we replace them with 0 (following BLAS
1075 // convention), rather than multiplying them by 0 to get NaN.
1076 if (beta == zero) {
1077 Y.putScalar(zero);
1078 } else {
1079 Y.scale(beta);
1080 }
1081 } else { // alpha != zero
1082 MV Y_tmp(Y.getMap(), Y.getNumVectors());
1083 apply(X, Y_tmp, mode);
1084 Y.update(alpha, Y_tmp, beta);
1085 }
1086 }
1087 } // end timing
1088
1089 ++NumApply_;
1090 ApplyTime_ += (timer.wallTime() - startTime);
1091} // apply()
1092
1093template <class MatrixType>
1095 std::ostringstream os;
1096
1097 // Output is a valid YAML dictionary in flow style. If you don't
1098 // like everything on a single line, you should call describe()
1099 // instead.
1100 os << "\"Ifpack2::ILUT\": {";
1101 os << "Initialized: " << (isInitialized() ? "true" : "false") << ", "
1102 << "Computed: " << (isComputed() ? "true" : "false") << ", ";
1103
1104 os << "Level-of-fill: " << getLevelOfFill() << ", "
1105 << "absolute threshold: " << getAbsoluteThreshold() << ", "
1106 << "relative threshold: " << getRelativeThreshold() << ", "
1107 << "relaxation value: " << getRelaxValue() << ", ";
1108
1109 if (A_.is_null()) {
1110 os << "Matrix: null";
1111 } else {
1112 os << "Global matrix dimensions: ["
1113 << A_->getGlobalNumRows() << ", " << A_->getGlobalNumCols() << "]"
1114 << ", Global nnz: " << A_->getGlobalNumEntries();
1115 }
1116
1117 os << "}";
1118 return os.str();
1119}
1120
1121template <class MatrixType>
1123 describe(Teuchos::FancyOStream& out,
1124 const Teuchos::EVerbosityLevel verbLevel) const {
1125 using std::endl;
1126 using Teuchos::Comm;
1127 using Teuchos::OSTab;
1128 using Teuchos::RCP;
1129 using Teuchos::TypeNameTraits;
1130 using Teuchos::VERB_DEFAULT;
1131 using Teuchos::VERB_EXTREME;
1132 using Teuchos::VERB_HIGH;
1133 using Teuchos::VERB_LOW;
1134 using Teuchos::VERB_MEDIUM;
1135 using Teuchos::VERB_NONE;
1136
1137 const Teuchos::EVerbosityLevel vl =
1138 (verbLevel == VERB_DEFAULT) ? VERB_LOW : verbLevel;
1139 OSTab tab0(out);
1140
1141 if (vl > VERB_NONE) {
1142 out << "\"Ifpack2::ILUT\":" << endl;
1143 OSTab tab1(out);
1144 out << "MatrixType: " << TypeNameTraits<MatrixType>::name() << endl;
1145 if (this->getObjectLabel() != "") {
1146 out << "Label: \"" << this->getObjectLabel() << "\"" << endl;
1147 }
1148 out << "Initialized: " << (isInitialized() ? "true" : "false")
1149 << endl
1150 << "Computed: " << (isComputed() ? "true" : "false")
1151 << endl
1152 << "Level of fill: " << getLevelOfFill() << endl
1153 << "Absolute threshold: " << getAbsoluteThreshold() << endl
1154 << "Relative threshold: " << getRelativeThreshold() << endl
1155 << "Relax value: " << getRelaxValue() << endl;
1156
1157 if (isComputed() && vl >= VERB_HIGH) {
1158 const double fillFraction =
1159 (double)getGlobalNumEntries() / (double)A_->getGlobalNumEntries();
1160 const double nnzToRows =
1161 (double)getGlobalNumEntries() / (double)U_->getGlobalNumRows();
1162
1163 out << "Dimensions of L: [" << L_->getGlobalNumRows() << ", "
1164 << L_->getGlobalNumRows() << "]" << endl
1165 << "Dimensions of U: [" << U_->getGlobalNumRows() << ", "
1166 << U_->getGlobalNumRows() << "]" << endl
1167 << "Number of nonzeros in factors: " << getGlobalNumEntries() << endl
1168 << "Fill fraction of factors over A: " << fillFraction << endl
1169 << "Ratio of nonzeros to rows: " << nnzToRows << endl;
1170 }
1171
1172 out << "Number of initialize calls: " << getNumInitialize() << endl
1173 << "Number of compute calls: " << getNumCompute() << endl
1174 << "Number of apply calls: " << getNumApply() << endl
1175 << "Total time in seconds for initialize: " << getInitializeTime() << endl
1176 << "Total time in seconds for compute: " << getComputeTime() << endl
1177 << "Total time in seconds for apply: " << getApplyTime() << endl;
1178
1179 out << "Local matrix:" << endl;
1180 A_local_->describe(out, vl);
1181 }
1182}
1183
1184} // namespace Ifpack2
1185
1186// FIXME (mfh 16 Sep 2014) We should really only use RowMatrix here!
1187// There's no need to instantiate for CrsMatrix too. All Ifpack2
1188// preconditioners can and should do dynamic casts if they need a type
1189// more specific than RowMatrix.
1190
1191#define IFPACK2_ILUT_INSTANT(S, LO, GO, N) \
1192 template class Ifpack2::ILUT<Tpetra::RowMatrix<S, LO, GO, N> >;
1193
1194#endif /* IFPACK2_ILUT_DEF_HPP */
ILUT (incomplete LU factorization with threshold) of a Tpetra sparse matrix.
Definition Ifpack2_ILUT_decl.hpp:65
Teuchos::ScalarTraits< scalar_type >::magnitudeType magnitude_type
The type of the magnitude (absolute value) of a matrix entry.
Definition Ifpack2_ILUT_decl.hpp:83
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Returns the input matrix's communicator.
Definition Ifpack2_ILUT_def.hpp:332
double getInitializeTime() const
Returns the time spent in Initialize().
Definition Ifpack2_ILUT_def.hpp:390
void compute()
Compute factors L and U using the specified diagonal perturbation thresholds and relaxation parameter...
Definition Ifpack2_ILUT_def.hpp:583
Teuchos::RCP< const row_matrix_type > getMatrix() const
Returns a reference to the matrix to be preconditioned.
Definition Ifpack2_ILUT_def.hpp:343
global_size_t getGlobalNumEntries() const
Returns the number of nonzero entries in the global graph.
Definition Ifpack2_ILUT_def.hpp:416
int getNumInitialize() const
Returns the number of calls to Initialize().
Definition Ifpack2_ILUT_def.hpp:375
MatrixType::local_ordinal_type local_ordinal_type
The type of local indices in the input MatrixType.
Definition Ifpack2_ILUT_decl.hpp:74
Teuchos::RCP< const map_type > getDomainMap() const
Tpetra::Map representing the domain of this operator.
Definition Ifpack2_ILUT_def.hpp:349
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 ILUT preconditioner to X, resulting in Y.
Definition Ifpack2_ILUT_def.hpp:1027
int getNumApply() const
Returns the number of calls to apply().
Definition Ifpack2_ILUT_def.hpp:385
size_t getNodeSmootherComplexity() const
Get a rough estimate of cost per iteration.
Definition Ifpack2_ILUT_def.hpp:405
MatrixType::scalar_type scalar_type
The type of the entries of the input MatrixType.
Definition Ifpack2_ILUT_decl.hpp:71
std::string description() const
Return a simple one-line description of this object.
Definition Ifpack2_ILUT_def.hpp:1094
bool hasTransposeApply() const
Whether this object's apply() method can apply the transpose (or conjugate transpose,...
Definition Ifpack2_ILUT_def.hpp:370
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Print the object with some verbosity level to an FancyOStream object.
Definition Ifpack2_ILUT_def.hpp:1123
ILUT(const Teuchos::RCP< const row_matrix_type > &A)
Constructor.
Definition Ifpack2_ILUT_def.hpp:165
virtual void setMatrix(const Teuchos::RCP< const row_matrix_type > &A)
Change the matrix to be preconditioned.
Definition Ifpack2_ILUT_def.hpp:426
Tpetra::CrsMatrix< scalar_type, local_ordinal_type, global_ordinal_type, node_type > crs_matrix_type
Type of the Tpetra::CrsMatrix specialization that this class uses for the L and U factors.
Definition Ifpack2_ILUT_decl.hpp:107
Teuchos::RCP< const map_type > getRangeMap() const
Tpetra::Map representing the range of this operator.
Definition Ifpack2_ILUT_def.hpp:360
size_t getLocalNumEntries() const
Returns the number of nonzero entries in the local graph.
Definition Ifpack2_ILUT_def.hpp:421
Tpetra::RowMatrix< scalar_type, local_ordinal_type, global_ordinal_type, node_type > row_matrix_type
Type of the Tpetra::RowMatrix specialization that this class uses.
Definition Ifpack2_ILUT_decl.hpp:90
void initialize()
Clear any previously computed factors, and potentially compute sparsity patterns of factors.
Definition Ifpack2_ILUT_def.hpp:499
int getNumCompute() const
Returns the number of calls to Compute().
Definition Ifpack2_ILUT_def.hpp:380
double getApplyTime() const
Returns the time spent in apply().
Definition Ifpack2_ILUT_def.hpp:400
void setParameters(const Teuchos::ParameterList &params)
Set preconditioner parameters.
Definition Ifpack2_ILUT_def.hpp:196
double getComputeTime() const
Returns the time spent in Compute().
Definition Ifpack2_ILUT_def.hpp:395
"Preconditioner" that solves local sparse triangular systems.
Definition Ifpack2_LocalSparseTriangularSolver_decl.hpp:54
Preconditioners and smoothers for Tpetra sparse matrices.
Definition Ifpack2_AdditiveSchwarz_decl.hpp:40
void add_to_heap(const Ordinal &idx, Teuchos::Array< Ordinal > &heap, SizeType &heap_len)
Definition Ifpack2_Heap.hpp:35
void rm_heap_root(Teuchos::Array< Ordinal > &heap, SizeType &heap_len)
Definition Ifpack2_Heap.hpp:59