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