Ifpack2 Templated Preconditioning Package Version 1.0
Loading...
Searching...
No Matches
Ifpack2_BlockRelaxation_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_BLOCKRELAXATION_DEF_HPP
11#define IFPACK2_BLOCKRELAXATION_DEF_HPP
12
14#include "Ifpack2_LinearPartitioner.hpp"
15#include "Ifpack2_LinePartitioner.hpp"
16#include "Ifpack2_Zoltan2Partitioner_decl.hpp"
17#include "Ifpack2_Zoltan2Partitioner_def.hpp"
19#include "Ifpack2_Details_UserPartitioner_def.hpp"
20#include "Ifpack2_LocalFilter.hpp"
21#include "Ifpack2_Parameters.hpp"
22#include "Teuchos_TimeMonitor.hpp"
23#include "Tpetra_BlockCrsMatrix_Helpers_decl.hpp"
24#include "Tpetra_Import_Util.hpp"
25#include "Ifpack2_BlockHelper_Timers.hpp"
26
27namespace Ifpack2 {
28
29template <class MatrixType, class ContainerType>
31 setMatrix(const Teuchos::RCP<const row_matrix_type>& A) {
32 if (A.getRawPtr() != A_.getRawPtr()) { // it's a different matrix
33 IsInitialized_ = false;
34 IsComputed_ = false;
35 Partitioner_ = Teuchos::null;
36 W_ = Teuchos::null;
37
38 if (!A.is_null()) {
39 IsParallel_ = (A->getRowMap()->getComm()->getSize() != 1);
40 Teuchos::RCP<const block_crs_matrix_type> A_bcrs =
41 Teuchos::rcp_dynamic_cast<const block_crs_matrix_type>(A);
42 hasBlockCrsMatrix_ = !A_bcrs.is_null();
43 }
44 if (!Container_.is_null()) {
45 // This just frees up the container's memory.
46 // The container will be fully re-constructed during initialize().
47 Container_->clearBlocks();
48 }
49 NumLocalBlocks_ = 0;
50
51 A_ = A;
52 computeImporter();
53 }
54}
55
56template <class MatrixType, class ContainerType>
58 BlockRelaxation(const Teuchos::RCP<const row_matrix_type>& A)
59 : Container_(Teuchos::null)
60 , Partitioner_(Teuchos::null)
61 , PartitionerType_("linear")
62 , NumSweeps_(1)
63 , NumLocalBlocks_(0)
64 , containerType_("TriDi")
65 , PrecType_(Ifpack2::Details::JACOBI)
66 , ZeroStartingSolution_(true)
67 , hasBlockCrsMatrix_(false)
68 , DoBackwardGS_(false)
69 , OverlapLevel_(0)
70 , nonsymCombine_(0)
71 , schwarzCombineMode_("ZERO")
72 , DampingFactor_(STS::one())
73 , IsInitialized_(false)
74 , IsComputed_(false)
75 , NumInitialize_(0)
76 , NumCompute_(0)
77 , TimerForApply_(true)
78 , NumApply_(0)
79 , InitializeTime_(0.0)
80 , ComputeTime_(0.0)
81 , NumLocalRows_(0)
82 , NumGlobalRows_(0)
83 , NumGlobalNonzeros_(0)
84 , W_(Teuchos::null)
85 , Importer_(Teuchos::null) {
86 setMatrix(A);
87}
88
89template <class MatrixType, class ContainerType>
92
93template <class MatrixType, class ContainerType>
94Teuchos::RCP<const Teuchos::ParameterList>
96 getValidParameters() const {
97 Teuchos::RCP<Teuchos::ParameterList> validParams = Teuchos::parameterList("Ifpack2::BlockRelaxation");
98
99 validParams->set("relaxation: container", "TriDi");
100 validParams->set("relaxation: backward mode", false);
101 validParams->set("relaxation: type", "Jacobi");
102 validParams->set("relaxation: sweeps", 1);
103 validParams->set("relaxation: damping factor", STS::one());
104 validParams->set("relaxation: zero starting solution", true);
105 validParams->set("block relaxation: decouple dofs", false);
106 validParams->set("schwarz: compute condest", false); // mfh 24 Mar 2015: for backwards compatibility ONLY
107 validParams->set("schwarz: combine mode", "ZERO"); // use string mode for this
108 validParams->set("schwarz: use reordering", true);
109 validParams->set("schwarz: filter singletons", false);
110 validParams->set("schwarz: overlap level", 0);
111 validParams->set("partitioner: type", "greedy");
112 validParams->set("zoltan2: algorithm", "phg");
113 validParams->set("partitioner: local parts", 1);
114 validParams->set("partitioner: overlap", 0);
115 validParams->set("partitioner: combine mode", "ZERO"); // use string mode for this
116 Teuchos::Array<Teuchos::ArrayRCP<int>> tmp0;
117 validParams->set("partitioner: parts", tmp0);
118 Teuchos::Array<Teuchos::ArrayRCP<typename MatrixType::global_ordinal_type>> tmp1;
119 validParams->set("partitioner: global ID parts", tmp1);
120 validParams->set("partitioner: nonsymmetric overlap combine", false);
121 validParams->set("partitioner: maintain sparsity", false);
122 validParams->set("fact: ilut level-of-fill", 1.0);
123 validParams->set("fact: absolute threshold", 0.0);
124 validParams->set("fact: relative threshold", 1.0);
125 validParams->set("fact: relax value", 0.0);
126
127 Teuchos::ParameterList dummyList;
128 validParams->set("Amesos2", dummyList);
129 validParams->sublist("Amesos2").disableRecursiveValidation();
130 validParams->set("Amesos2 solver name", "KLU2");
131
132 Teuchos::ArrayRCP<int> tmp;
133 validParams->set("partitioner: map", tmp);
134
135 validParams->set("partitioner: line detection threshold", 0.0);
136 validParams->set("partitioner: PDE equations", 1);
137 Teuchos::RCP<Tpetra::MultiVector<typename Teuchos::ScalarTraits<typename MatrixType::scalar_type>::magnitudeType,
138 typename MatrixType::local_ordinal_type,
139 typename MatrixType::global_ordinal_type,
140 typename MatrixType::node_type>>
141 dummy;
142 validParams->set("partitioner: coordinates", dummy);
143 validParams->set("timer for apply", true);
144 validParams->set("partitioner: subparts per part", 1);
145 validParams->set("partitioner: block size", -1);
146 validParams->set("partitioner: print level", false);
147 validParams->set("partitioner: explicit convert to BlockCrs", false);
148 validParams->set("partitioner: checkBlockConsistency", true);
149 validParams->set("partitioner: use LIDs", true);
150
151 return validParams;
152}
153
154template <class MatrixType, class ContainerType>
156 setParameters(const Teuchos::ParameterList& pl) {
157 // CAG: Copied from Relaxation
158 // FIXME (aprokop 18 Oct 2013) Casting away const is bad here.
159 // but otherwise, we will get [unused] in pl
160 this->setParametersImpl(const_cast<Teuchos::ParameterList&>(pl));
161}
162
163template <class MatrixType, class ContainerType>
165 setParametersImpl(Teuchos::ParameterList& List) {
166 if (List.isType<double>("relaxation: damping factor")) {
167 // Make sure that ST=complex can run with a damping factor that is
168 // a double.
169 scalar_type df = List.get<double>("relaxation: damping factor");
170 List.remove("relaxation: damping factor");
171 List.set("relaxation: damping factor", df);
172 }
173
174 // Note that the validation process does not change List.
175 Teuchos::RCP<const Teuchos::ParameterList> validparams;
176 validparams = this->getValidParameters();
177 List.validateParameters(*validparams);
178
179 if (List.isParameter("relaxation: container")) {
180 // If the container type isn't a string, this will throw, but it
181 // rightfully should.
182
183 // If its value does not match the currently registered Container types,
184 // the ContainerFactory will throw with an informative message.
185 containerType_ = List.get<std::string>("relaxation: container");
186 // Intercept more human-readable aliases for the *TriDi containers
187 if (containerType_ == "Tridiagonal") {
188 containerType_ = "TriDi";
189 }
190 if (containerType_ == "Block Tridiagonal") {
191 containerType_ = "BlockTriDi";
192 }
193 }
194
195 if (List.isParameter("relaxation: type")) {
196 const std::string relaxType = List.get<std::string>("relaxation: type");
197
198 if (relaxType == "Jacobi") {
199 PrecType_ = Ifpack2::Details::JACOBI;
200 } else if (relaxType == "MT Split Jacobi") {
201 PrecType_ = Ifpack2::Details::MTSPLITJACOBI;
202 } else if (relaxType == "Gauss-Seidel") {
203 PrecType_ = Ifpack2::Details::GS;
204 } else if (relaxType == "Symmetric Gauss-Seidel") {
205 PrecType_ = Ifpack2::Details::SGS;
206 } else {
207 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
208 "Ifpack2::BlockRelaxation::"
209 "setParameters: Invalid parameter value \""
210 << relaxType
211 << "\" for parameter \"relaxation: type\".");
212 }
213 }
214
215 if (List.isParameter("relaxation: sweeps")) {
216 NumSweeps_ = List.get<int>("relaxation: sweeps");
217 }
218
219 // Users may specify this as a floating-point literal. In that
220 // case, it may have type double, even if scalar_type is something
221 // else. We take care to try the various types that make sense.
222 if (List.isParameter("relaxation: damping factor")) {
223 if (List.isType<double>("relaxation: damping factor")) {
224 const double dampingFactor =
225 List.get<double>("relaxation: damping factor");
226 DampingFactor_ = static_cast<scalar_type>(dampingFactor);
227 } else if (List.isType<scalar_type>("relaxation: damping factor")) {
228 DampingFactor_ = List.get<scalar_type>("relaxation: damping factor");
229 } else if (List.isType<magnitude_type>("relaxation: damping factor")) {
230 const magnitude_type dampingFactor =
231 List.get<magnitude_type>("relaxation: damping factor");
232 DampingFactor_ = static_cast<scalar_type>(dampingFactor);
233 } else {
234 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
235 "Ifpack2::BlockRelaxation::"
236 "setParameters: Parameter \"relaxation: damping factor\" "
237 "has the wrong type.");
238 }
239 }
240
241 if (List.isParameter("relaxation: zero starting solution")) {
242 ZeroStartingSolution_ = List.get<bool>("relaxation: zero starting solution");
243 }
244
245 if (List.isParameter("relaxation: backward mode")) {
246 DoBackwardGS_ = List.get<bool>("relaxation: backward mode");
247 }
248
249 if (List.isParameter("partitioner: type")) {
250 PartitionerType_ = List.get<std::string>("partitioner: type");
251 }
252
253 // Users may specify this as an int literal, so we need to allow
254 // both int and local_ordinal_type (not necessarily same as int).
255 if (List.isParameter("partitioner: local parts")) {
256 if (List.isType<local_ordinal_type>("partitioner: local parts")) {
257 NumLocalBlocks_ = List.get<local_ordinal_type>("partitioner: local parts");
258 } else if (!std::is_same<int, local_ordinal_type>::value &&
259 List.isType<int>("partitioner: local parts")) {
260 NumLocalBlocks_ = List.get<int>("partitioner: local parts");
261 } else {
262 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
263 "Ifpack2::BlockRelaxation::"
264 "setParameters: Parameter \"partitioner: local parts\" "
265 "has the wrong type.");
266 }
267 }
268
269 if (List.isParameter("partitioner: overlap level")) {
270 if (List.isType<int>("partitioner: overlap level")) {
271 OverlapLevel_ = List.get<int>("partitioner: overlap level");
272 } else if (!std::is_same<int, local_ordinal_type>::value &&
273 List.isType<local_ordinal_type>("partitioner: overlap level")) {
274 OverlapLevel_ = List.get<local_ordinal_type>("partitioner: overlap level");
275 } else {
276 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
277 "Ifpack2::BlockRelaxation::"
278 "setParameters: Parameter \"partitioner: overlap level\" "
279 "has the wrong type.");
280 }
281 }
282 // when using global ID parts, assume that some blocks overlap even if
283 // user did not explicitly set the overlap level in the input file.
284 if ((List.isParameter("partitioner: global ID parts")) && (OverlapLevel_ < 1)) OverlapLevel_ = 1;
285
286 if (List.isParameter("partitioner: nonsymmetric overlap combine"))
287 nonsymCombine_ = List.get<bool>("partitioner: nonsymmetric overlap combine");
288
289 if (List.isParameter("partitioner: combine mode"))
290 schwarzCombineMode_ = List.get<std::string>("partitioner: combine mode");
291
292 std::string defaultContainer = "TriDi";
293 if (std::is_same<ContainerType, Container<MatrixType>>::value) {
294 // Generic container template parameter, container type specified in List
295 Ifpack2::getParameter(List, "relaxation: container", defaultContainer);
296 }
297 // check parameters
298 if (PrecType_ != Ifpack2::Details::JACOBI) {
299 OverlapLevel_ = 0;
300 }
301 if (NumLocalBlocks_ < static_cast<local_ordinal_type>(0)) {
302 NumLocalBlocks_ = A_->getLocalNumRows() / (-NumLocalBlocks_);
303 }
304
305 decouple_ = false;
306 if (List.isParameter("block relaxation: decouple dofs"))
307 decouple_ = List.get<bool>("block relaxation: decouple dofs");
308
309 // other checks are performed in Partitioner_
310
311 // NTS: Sanity check to be removed at a later date when Backward mode is enabled
312 TEUCHOS_TEST_FOR_EXCEPTION(
313 DoBackwardGS_, std::runtime_error,
314 "Ifpack2::BlockRelaxation:setParameters: Setting the \"relaxation: "
315 "backward mode\" parameter to true is not yet supported.");
316
317 if (List.isParameter("timer for apply"))
318 TimerForApply_ = List.get<bool>("timer for apply");
319
320 // copy the list as each subblock's constructor will
321 // require it later
322 List_ = List;
323}
324
325template <class MatrixType, class ContainerType>
326Teuchos::RCP<const Teuchos::Comm<int>>
328 TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error,
329 "Ifpack2::BlockRelaxation::getComm: "
330 "The matrix is null. You must call setMatrix() with a nonnull matrix "
331 "before you may call this method.");
332 return A_->getComm();
333}
334
335template <class MatrixType, class ContainerType>
336Teuchos::RCP<const Tpetra::RowMatrix<typename MatrixType::scalar_type,
337 typename MatrixType::local_ordinal_type,
338 typename MatrixType::global_ordinal_type,
339 typename MatrixType::node_type>>
343
344template <class MatrixType, class ContainerType>
345Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,
346 typename MatrixType::global_ordinal_type,
347 typename MatrixType::node_type>>
349 getDomainMap() const {
350 TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error,
351 "Ifpack2::BlockRelaxation::"
352 "getDomainMap: The matrix is null. You must call setMatrix() with a "
353 "nonnull matrix before you may call this method.");
354 return A_->getDomainMap();
355}
356
357template <class MatrixType, class ContainerType>
358Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,
359 typename MatrixType::global_ordinal_type,
360 typename MatrixType::node_type>>
362 getRangeMap() const {
363 TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error,
364 "Ifpack2::BlockRelaxation::"
365 "getRangeMap: The matrix is null. You must call setMatrix() with a "
366 "nonnull matrix before you may call this method.");
367 return A_->getRangeMap();
368}
369
370template <class MatrixType, class ContainerType>
372 hasTransposeApply() const {
373 return true;
374}
375
376template <class MatrixType, class ContainerType>
378 getNumInitialize() const {
379 return NumInitialize_;
380}
381
382template <class MatrixType, class ContainerType>
384 getNumCompute() const {
385 return NumCompute_;
386}
387
388template <class MatrixType, class ContainerType>
390 getNumApply() const {
391 return NumApply_;
392}
393
394template <class MatrixType, class ContainerType>
395double
397 getInitializeTime() const {
398 return InitializeTime_;
399}
400
401template <class MatrixType, class ContainerType>
402double
404 getComputeTime() const {
405 return ComputeTime_;
406}
407
408template <class MatrixType, class ContainerType>
409double
411 getApplyTime() const {
412 return ApplyTime_;
413}
414
415template <class MatrixType, class ContainerType>
417 TEUCHOS_TEST_FOR_EXCEPTION(
418 A_.is_null(), std::runtime_error,
419 "Ifpack2::BlockRelaxation::getNodeSmootherComplexity: "
420 "The input matrix A is null. Please call setMatrix() with a nonnull "
421 "input matrix, then call compute(), before calling this method.");
422 // Relaxation methods cost roughly one apply + one block-diagonal inverse per iteration
423 // NOTE: This approximates all blocks as dense, which may overstate the cost if you have a sparse (or banded) container.
424 size_t block_nnz = 0;
425 for (local_ordinal_type i = 0; i < NumLocalBlocks_; ++i)
426 block_nnz += Partitioner_->numRowsInPart(i) * Partitioner_->numRowsInPart(i);
427
428 return block_nnz + A_->getLocalNumEntries();
429}
430
431template <class MatrixType, class ContainerType>
433 apply(const Tpetra::MultiVector<typename MatrixType::scalar_type,
434 typename MatrixType::local_ordinal_type,
435 typename MatrixType::global_ordinal_type,
436 typename MatrixType::node_type>& X,
437 Tpetra::MultiVector<typename MatrixType::scalar_type,
438 typename MatrixType::local_ordinal_type,
439 typename MatrixType::global_ordinal_type,
440 typename MatrixType::node_type>& Y,
441 Teuchos::ETransp mode,
442 scalar_type alpha,
443 scalar_type beta) const {
444 TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error,
445 "Ifpack2::BlockRelaxation::apply: "
446 "The matrix is null. You must call setMatrix() with a nonnull matrix, "
447 "then call initialize() and compute() (in that order), before you may "
448 "call this method.");
449 TEUCHOS_TEST_FOR_EXCEPTION(
450 !isComputed(), std::runtime_error,
451 "Ifpack2::BlockRelaxation::apply: "
452 "isComputed() must be true prior to calling apply.");
453 TEUCHOS_TEST_FOR_EXCEPTION(
454 X.getNumVectors() != Y.getNumVectors(), std::invalid_argument,
455 "Ifpack2::BlockRelaxation::apply: X.getNumVectors() = "
456 << X.getNumVectors() << " != Y.getNumVectors() = "
457 << Y.getNumVectors() << ".");
458 TEUCHOS_TEST_FOR_EXCEPTION(
459 mode != Teuchos::NO_TRANS, std::logic_error,
460 "Ifpack2::BlockRelaxation::"
461 "apply: This method currently only implements the case mode == Teuchos::"
462 "NO_TRANS. Transposed modes are not currently supported.");
463 TEUCHOS_TEST_FOR_EXCEPTION(
464 alpha != Teuchos::ScalarTraits<scalar_type>::one(), std::logic_error,
465 "Ifpack2::BlockRelaxation::apply: This method currently only implements "
466 "the case alpha == 1. You specified alpha = "
467 << alpha << ".");
468 TEUCHOS_TEST_FOR_EXCEPTION(
469 beta != Teuchos::ScalarTraits<scalar_type>::zero(), std::logic_error,
470 "Ifpack2::BlockRelaxation::apply: This method currently only implements "
471 "the case beta == 0. You specified beta = "
472 << beta << ".");
473
474 const std::string timerName("Ifpack2::BlockRelaxation::apply");
475 Teuchos::RCP<Teuchos::Time> timer;
476 if (TimerForApply_) {
477 timer = Teuchos::TimeMonitor::lookupCounter(timerName);
478 if (timer.is_null()) {
479 timer = Teuchos::TimeMonitor::getNewCounter(timerName);
480 }
481 }
482
483 Teuchos::Time time = Teuchos::Time(timerName);
484 double startTime = time.wallTime();
485
486 {
487 Teuchos::RCP<Teuchos::TimeMonitor> timeMon;
488 if (TimerForApply_)
489 timeMon = Teuchos::rcp(new Teuchos::TimeMonitor(*timer));
490
491 // If X and Y are pointing to the same memory location,
492 // we need to create an auxiliary vector, Xcopy
493 Teuchos::RCP<const MV> X_copy;
494 {
495 if (X.aliases(Y)) {
496 X_copy = rcp(new MV(X, Teuchos::Copy));
497 } else {
498 X_copy = rcpFromRef(X);
499 }
500 }
501
502 if (ZeroStartingSolution_) {
503 Y.putScalar(STS::zero());
504 }
505
506 // Flops are updated in each of the following.
507 switch (PrecType_) {
508 case Ifpack2::Details::JACOBI:
509 ApplyInverseJacobi(*X_copy, Y);
510 break;
511 case Ifpack2::Details::GS:
512 ApplyInverseGS(*X_copy, Y);
513 break;
514 case Ifpack2::Details::SGS:
515 ApplyInverseSGS(*X_copy, Y);
516 break;
517 case Ifpack2::Details::MTSPLITJACOBI:
518 // note: for this method, the container is always BlockTriDi
519 Container_->applyInverseJacobi(*X_copy, Y, DampingFactor_, ZeroStartingSolution_, NumSweeps_);
520 break;
521 default:
522 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
523 "Ifpack2::BlockRelaxation::apply: Invalid "
524 "PrecType_ enum value "
525 << PrecType_ << ". Valid values are Ifpack2::"
526 "Details::JACOBI = "
527 << Ifpack2::Details::JACOBI << ", Ifpack2::Details"
528 "::GS = "
529 << Ifpack2::Details::GS << ", and Ifpack2::Details::SGS = "
530 << Ifpack2::Details::SGS << ". Please report this bug to the Ifpack2 "
531 "developers.");
532 }
533 }
534
535 ApplyTime_ += (time.wallTime() - startTime);
536 ++NumApply_;
537}
538
539template <class MatrixType, class ContainerType>
541 applyMat(const Tpetra::MultiVector<typename MatrixType::scalar_type,
542 typename MatrixType::local_ordinal_type,
543 typename MatrixType::global_ordinal_type,
544 typename MatrixType::node_type>& X,
545 Tpetra::MultiVector<typename MatrixType::scalar_type,
546 typename MatrixType::local_ordinal_type,
547 typename MatrixType::global_ordinal_type,
548 typename MatrixType::node_type>& Y,
549 Teuchos::ETransp mode) const {
550 A_->apply(X, Y, mode);
551}
552
553template <class MatrixType, class ContainerType>
555 initialize() {
556 using Teuchos::rcp;
557 typedef Tpetra::RowGraph<local_ordinal_type, global_ordinal_type, node_type>
558 row_graph_type;
559
560 TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error,
561 "Ifpack2::BlockRelaxation::initialize: "
562 "The matrix is null. You must call setMatrix() with a nonnull matrix "
563 "before you may call this method.");
564
565 Teuchos::RCP<Teuchos::Time> timer =
566 Teuchos::TimeMonitor::getNewCounter("Ifpack2::BlockRelaxation::initialize");
567 double startTime = timer->wallTime();
568
569 { // Timing of initialize starts here
570 Teuchos::TimeMonitor timeMon(*timer);
571 IsInitialized_ = false;
572
573 // Check whether we have a BlockCrsMatrix
574 Teuchos::RCP<const block_crs_matrix_type> A_bcrs =
575 Teuchos::rcp_dynamic_cast<const block_crs_matrix_type>(A_);
576 hasBlockCrsMatrix_ = !A_bcrs.is_null();
577
578 Teuchos::RCP<const row_graph_type> graph = A_->getGraph();
579
580 if (!hasBlockCrsMatrix_ && List_.isParameter("relaxation: container") && List_.get<std::string>("relaxation: container") == "BlockTriDi") {
581 IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::convertToBlockCrsMatrix", convertToBlockCrsMatrix);
582 int block_size = List_.get<int>("partitioner: block size");
583 bool use_explicit_conversion = List_.isParameter("partitioner: explicit convert to BlockCrs") && List_.get<bool>("partitioner: explicit convert to BlockCrs");
584 TEUCHOS_TEST_FOR_EXCEPT_MSG(use_explicit_conversion && block_size == -1, "A pointwise matrix and block_size = -1 were given as inputs.");
585 bool use_LID = !List_.isParameter("partitioner: use LIDs") || List_.get<bool>("partitioner: use LIDs");
586 bool check_block_consistency = !List_.isParameter("partitioner: checkBlockConsistency") || List_.get<bool>("partitioner: checkBlockConsistency");
587
588 if ((use_LID || !use_explicit_conversion) && check_block_consistency) {
589 if (!A_->getGraph()->getImporter().is_null()) {
590 TEUCHOS_TEST_FOR_EXCEPT_MSG(!Tpetra::Import_Util::checkBlockConsistency(*(A_->getGraph()->getColMap()), block_size),
591 "The pointwise graph of the input matrix A pointwise is not consistent with block_size.");
592 }
593 }
594 if (use_explicit_conversion) {
595 A_bcrs = Tpetra::convertToBlockCrsMatrix(*Teuchos::rcp_dynamic_cast<const crs_matrix_type>(A_), block_size, use_LID);
596 A_ = A_bcrs;
597 hasBlockCrsMatrix_ = true;
598 graph = A_->getGraph();
599 } else {
600 graph = Tpetra::getBlockCrsGraph(*Teuchos::rcp_dynamic_cast<const crs_matrix_type>(A_), block_size, true);
601 }
602 IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
603 }
604
605 NumLocalRows_ = A_->getLocalNumRows();
606 NumGlobalRows_ = A_->getGlobalNumRows();
607 NumGlobalNonzeros_ = A_->getGlobalNumEntries();
608
609 // NTS: Will need to add support for Zoltan2 partitions later Also,
610 // will need a better way of handling the Graph typing issue.
611 // Especially with ordinal types w.r.t the container.
612 Partitioner_ = Teuchos::null;
613
614 if (PartitionerType_ == "linear") {
615 IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::linear", linear);
616 Partitioner_ =
618 IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
619 } else if (PartitionerType_ == "line") {
620 IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::line", line);
621 Partitioner_ =
623 IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
624 } else if (PartitionerType_ == "user") {
625 IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::user", user);
626 Partitioner_ =
628 IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
629 } else if (PartitionerType_ == "zoltan2") {
630 IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::zoltan2", zoltan2);
631#if defined(HAVE_IFPACK2_ZOLTAN2)
632 if (graph->getComm()->getSize() == 1) {
633 // Only one MPI, so call zoltan2 with global graph
634 Partitioner_ =
635 rcp(new Ifpack2::Zoltan2Partitioner<row_graph_type>(graph));
636 } else {
637 // Form local matrix to get local graph for calling zoltan2
638 Teuchos::RCP<const row_matrix_type> A_local = rcp(new LocalFilter<row_matrix_type>(A_));
639 Partitioner_ =
640 rcp(new Ifpack2::Zoltan2Partitioner<row_graph_type>(A_local->getGraph()));
641 }
642#else
643 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Ifpack2::BlockRelaxation::initialize: Zoltan2 not enabled.");
644#endif
645 IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
646 } else {
647 // We should have checked for this in setParameters(), so it's a
648 // logic_error, not an invalid_argument or runtime_error.
649 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
650 "Ifpack2::BlockRelaxation::initialize: Unknown "
651 "partitioner type "
652 << PartitionerType_ << ". Valid values are "
653 "\"linear\", \"line\", and \"user\".");
654 }
655
656 // need to partition the graph of A
657 {
658 IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::Partitioner", Partitioner);
659 Partitioner_->setParameters(List_);
660 Partitioner_->compute();
661 IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
662 }
663
664 // get actual number of partitions
665 NumLocalBlocks_ = Partitioner_->numLocalParts();
666
667 // Note: Unlike Ifpack, we'll punt on computing W_ until compute(), which is where
668 // we assume that the type of relaxation has been chosen.
669
670 if (A_->getComm()->getSize() != 1) {
671 IsParallel_ = true;
672 } else {
673 IsParallel_ = false;
674 }
675
676 // We should have checked for this in setParameters(), so it's a
677 // logic_error, not an invalid_argument or runtime_error.
678 TEUCHOS_TEST_FOR_EXCEPTION(NumSweeps_ < 0, std::logic_error,
679 "Ifpack2::BlockRelaxation::initialize: "
680 "NumSweeps_ = "
681 << NumSweeps_ << " < 0.");
682
683 // Extract the submatrices
684 {
685 IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::ExtractSubmatricesStructure", ExtractSubmatricesStructure);
686 ExtractSubmatricesStructure();
687 IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
688 }
689
690 // Compute the weight vector if we're doing overlapped Jacobi (and
691 // only if we're doing overlapped Jacobi).
692 if (PrecType_ == Ifpack2::Details::JACOBI && OverlapLevel_ > 0) {
693 TEUCHOS_TEST_FOR_EXCEPTION(hasBlockCrsMatrix_, std::runtime_error,
694 "Ifpack2::BlockRelaxation::initialize: "
695 "We do not support overlapped Jacobi yet for Tpetra::BlockCrsMatrix. Sorry!");
696
697 // weight of each vertex
698 W_ = rcp(new vector_type(A_->getRowMap()));
699 W_->putScalar(STS::zero());
700 {
701 Teuchos::ArrayRCP<scalar_type> w_ptr = W_->getDataNonConst(0);
702
703 for (local_ordinal_type i = 0; i < NumLocalBlocks_; ++i) {
704 for (size_t j = 0; j < Partitioner_->numRowsInPart(i); ++j) {
705 local_ordinal_type LID = (*Partitioner_)(i, j);
706 w_ptr[LID] += STS::one();
707 }
708 }
709 }
710 // communicate to sum together W_[k]'s (# of blocks/patches) that update
711 // kth dof) and have this information in overlapped/extended vector.
712 // only needed when Schwarz combine mode is ADD as opposed to ZERO (which is RAS)
713
714 if (schwarzCombineMode_ == "ADD") {
715 IFPACK2_BLOCKHELPER_TIMER("Ifpack2::BlockRelaxation::initialize::ADD", ADD);
716 typedef Tpetra::MultiVector<typename MatrixType::scalar_type, typename MatrixType::local_ordinal_type, typename MatrixType::global_ordinal_type, typename MatrixType::node_type> scMV;
717 Teuchos::RCP<const import_type> theImport = A_->getGraph()->getImporter();
718 if (!theImport.is_null()) {
719 scMV nonOverLapW(theImport->getSourceMap(), 1, false);
720 Teuchos::ArrayRCP<scalar_type> w_ptr = W_->getDataNonConst(0);
721 Teuchos::ArrayRCP<scalar_type> nonOverLapWArray = nonOverLapW.getDataNonConst(0);
722 nonOverLapW.putScalar(STS::zero());
723 for (int ii = 0; ii < (int)theImport->getSourceMap()->getLocalNumElements(); ii++) nonOverLapWArray[ii] = w_ptr[ii];
724 nonOverLapWArray = Teuchos::null;
725 w_ptr = Teuchos::null;
726 nonOverLapW.doExport(*W_, *theImport, Tpetra::ADD);
727 W_->doImport(nonOverLapW, *theImport, Tpetra::INSERT);
728 }
729 IFPACK2_BLOCKHELPER_TIMER_DEFAULT_FENCE();
730 }
731 W_->reciprocal(*W_);
732 }
733 } // timing of initialize stops here
734
735 InitializeTime_ += (timer->wallTime() - startTime);
736 ++NumInitialize_;
737 IsInitialized_ = true;
738}
739
740template <class MatrixType, class ContainerType>
742 compute() {
743 using Teuchos::rcp;
744
745 TEUCHOS_TEST_FOR_EXCEPTION(A_.is_null(), std::runtime_error,
746 "Ifpack2::BlockRelaxation::compute: "
747 "The matrix is null. You must call setMatrix() with a nonnull matrix, "
748 "then call initialize(), before you may call this method.");
749
750 if (!isInitialized()) {
751 initialize();
752 }
753
754 Teuchos::RCP<Teuchos::Time> timer =
755 Teuchos::TimeMonitor::getNewCounter("Ifpack2::BlockRelaxation::compute");
756
757 double startTime = timer->wallTime();
758
759 {
760 Teuchos::TimeMonitor timeMon(*timer);
761
762 // reset values
763 IsComputed_ = false;
764
765 Container_->compute(); // compute each block matrix
766 }
767
768 ComputeTime_ += (timer->wallTime() - startTime);
769 ++NumCompute_;
770 IsComputed_ = true;
771}
772
773template <class MatrixType, class ContainerType>
776 TEUCHOS_TEST_FOR_EXCEPTION(Partitioner_.is_null(), std::runtime_error,
777 "Ifpack2::BlockRelaxation::"
778 "ExtractSubmatricesStructure: Partitioner object is null.");
779
780 std::string containerType = ContainerType::getName();
781 if (containerType == "Generic") {
782 // ContainerType is Container<row_matrix_type>. Thus, we need to
783 // get the container name from the parameter list. We use "TriDi"
784 // as the default container type.
785 containerType = containerType_;
786 }
787 // Whether the Container will define blocks (partitions)
788 // in terms of individual DOFs, and not by nodes (blocks).
789 bool pointIndexed = decouple_ && hasBlockCrsMatrix_;
790 Teuchos::Array<Teuchos::Array<local_ordinal_type>> blockRows;
791 if (decouple_) {
792 // dofs [per node] is how many blocks each partition will be split into
793 auto A_bcrs = Teuchos::rcp_dynamic_cast<const block_crs_matrix_type>(A_);
794 local_ordinal_type dofs = hasBlockCrsMatrix_ ? A_bcrs->getBlockSize() : List_.get<int>("partitioner: PDE equations");
795 blockRows.resize(NumLocalBlocks_ * dofs);
796 if (hasBlockCrsMatrix_) {
797 for (local_ordinal_type i = 0; i < NumLocalBlocks_; i++) {
798 size_t blockSize = Partitioner_->numRowsInPart(i);
799 // block i will be split into j different blocks,
800 // each corresponding to a different dof
801 for (local_ordinal_type j = 0; j < dofs; j++) {
802 local_ordinal_type blockIndex = i * dofs + j;
803 blockRows[blockIndex].resize(blockSize);
804 for (size_t k = 0; k < blockSize; k++) {
805 // here, the row and dof are combined to get the point index
806 //(what the row would be if A were a CrsMatrix)
807 blockRows[blockIndex][k] = (*Partitioner_)(i, k) * dofs + j;
808 }
809 }
810 }
811 } else {
812 // Rows in each partition are distributed round-robin to the blocks -
813 // that's how MueLu stores DOFs in a non-block matrix
814 for (local_ordinal_type i = 0; i < NumLocalBlocks_; i++) {
815 //#ifdef HAVE_IFPACK2_DEBUG
816 TEUCHOS_TEST_FOR_EXCEPTION(Partitioner_->numRowsInPart(i) % dofs != 0, std::logic_error,
817 "Expected size of all blocks (partitions) to be divisible by MueLu dofs/node.");
818 size_t blockSize = Partitioner_->numRowsInPart(i) / dofs;
819 //#endif
820 // block i will be split into j different blocks,
821 // each corresponding to a different dof
822 for (local_ordinal_type j = 0; j < dofs; j++) {
823 local_ordinal_type blockIndex = i * dofs + j;
824 blockRows[blockIndex].resize(blockSize);
825 for (size_t k = 0; k < blockSize; k++) {
826 blockRows[blockIndex][k] = (*Partitioner_)(i, k * dofs + j);
827 }
828 }
829 }
830 }
831 } else {
832 // No decoupling - just get the rows directly from Partitioner
833 blockRows.resize(NumLocalBlocks_);
834 for (local_ordinal_type i = 0; i < NumLocalBlocks_; ++i) {
835 const size_t numRows = Partitioner_->numRowsInPart(i);
836 blockRows[i].resize(numRows);
837 // Extract a list of the indices of each partitioner row.
838 for (size_t j = 0; j < numRows; ++j) {
839 blockRows[i][j] = (*Partitioner_)(i, j);
840 }
841 }
842 }
843 // right before constructing the
844 Container_ = ContainerFactory<MatrixType>::build(containerType, A_, blockRows, Importer_, pointIndexed);
845 Container_->setParameters(List_);
846 Container_->initialize();
847}
848
849template <class MatrixType, class ContainerType>
850void BlockRelaxation<MatrixType, ContainerType>::
851 ApplyInverseJacobi(const MV& X, MV& Y) const {
852 const size_t NumVectors = X.getNumVectors();
853
854 MV AY(Y.getMap(), NumVectors);
855
856 // Initial matvec not needed
857 int starting_iteration = 0;
858 if (OverlapLevel_ > 0) {
859 // Overlapping jacobi, with view of W_
860 auto WView = W_->getLocalViewHost(Tpetra::Access::ReadOnly);
861 if (ZeroStartingSolution_) {
862 auto XView = X.getLocalViewHost(Tpetra::Access::ReadOnly);
863 auto YView = Y.getLocalViewHost(Tpetra::Access::ReadWrite);
864 Container_->DoOverlappingJacobi(XView, YView, WView, DampingFactor_, nonsymCombine_);
865 starting_iteration = 1;
866 }
867 const scalar_type ONE = STS::one();
868 for (int j = starting_iteration; j < NumSweeps_; j++) {
869 applyMat(Y, AY);
870 AY.update(ONE, X, -ONE);
871 {
872 auto AYView = AY.getLocalViewHost(Tpetra::Access::ReadOnly);
873 auto YView = Y.getLocalViewHost(Tpetra::Access::ReadWrite);
874 Container_->DoOverlappingJacobi(AYView, YView, WView, DampingFactor_, nonsymCombine_);
875 }
876 }
877 } else {
878 // Non-overlapping
879 if (ZeroStartingSolution_) {
880 auto XView = X.getLocalViewHost(Tpetra::Access::ReadOnly);
881 auto YView = Y.getLocalViewHost(Tpetra::Access::ReadWrite);
882 Container_->DoJacobi(XView, YView, DampingFactor_);
883 starting_iteration = 1;
884 }
885 const scalar_type ONE = STS::one();
886 for (int j = starting_iteration; j < NumSweeps_; j++) {
887 applyMat(Y, AY);
888 AY.update(ONE, X, -ONE);
889 {
890 auto AYView = AY.getLocalViewHost(Tpetra::Access::ReadOnly);
891 auto YView = Y.getLocalViewHost(Tpetra::Access::ReadWrite);
892 Container_->DoJacobi(AYView, YView, DampingFactor_);
893 }
894 }
895 }
896}
897
898template <class MatrixType, class ContainerType>
899void BlockRelaxation<MatrixType, ContainerType>::
900 ApplyInverseGS(const MV& X, MV& Y) const {
901 using Teuchos::Ptr;
902 using Teuchos::ptr;
903 size_t numVecs = X.getNumVectors();
904 // Get view of X (is never modified in this function)
905 auto XView = X.getLocalViewHost(Tpetra::Access::ReadOnly);
906 auto YView = Y.getLocalViewHost(Tpetra::Access::ReadWrite);
907 // Pre-import Y, if parallel
908 Ptr<MV> Y2;
909 bool deleteY2 = false;
910 if (IsParallel_) {
911 Y2 = ptr(new MV(Importer_->getTargetMap(), numVecs));
912 deleteY2 = true;
913 } else
914 Y2 = ptr(&Y);
915 if (IsParallel_) {
916 for (int j = 0; j < NumSweeps_; ++j) {
917 // do import once per sweep
918 Y2->doImport(Y, *Importer_, Tpetra::INSERT);
919 auto Y2View = Y2->getLocalViewHost(Tpetra::Access::ReadWrite);
920 Container_->DoGaussSeidel(XView, YView, Y2View, DampingFactor_);
921 }
922 } else {
923 auto Y2View = Y2->getLocalViewHost(Tpetra::Access::ReadWrite);
924 for (int j = 0; j < NumSweeps_; ++j) {
925 Container_->DoGaussSeidel(XView, YView, Y2View, DampingFactor_);
926 }
927 }
928 if (deleteY2)
929 delete Y2.get();
930}
931
932template <class MatrixType, class ContainerType>
933void BlockRelaxation<MatrixType, ContainerType>::
934 ApplyInverseSGS(const MV& X, MV& Y) const {
935 using Teuchos::Ptr;
936 using Teuchos::ptr;
937 // Get view of X (is never modified in this function)
938 auto XView = X.getLocalViewHost(Tpetra::Access::ReadOnly);
939 auto YView = Y.getLocalViewHost(Tpetra::Access::ReadWrite);
940 // Pre-import Y, if parallel
941 Ptr<MV> Y2;
942 bool deleteY2 = false;
943 if (IsParallel_) {
944 Y2 = ptr(new MV(Importer_->getTargetMap(), X.getNumVectors()));
945 deleteY2 = true;
946 } else
947 Y2 = ptr(&Y);
948 if (IsParallel_) {
949 for (int j = 0; j < NumSweeps_; ++j) {
950 // do import once per sweep
951 Y2->doImport(Y, *Importer_, Tpetra::INSERT);
952 auto Y2View = Y2->getLocalViewHost(Tpetra::Access::ReadWrite);
953 Container_->DoSGS(XView, YView, Y2View, DampingFactor_);
954 }
955 } else {
956 auto Y2View = Y2->getLocalViewHost(Tpetra::Access::ReadWrite);
957 for (int j = 0; j < NumSweeps_; ++j) {
958 Container_->DoSGS(XView, YView, Y2View, DampingFactor_);
959 }
960 }
961 if (deleteY2)
962 delete Y2.get();
963}
964
965template <class MatrixType, class ContainerType>
966void BlockRelaxation<MatrixType, ContainerType>::computeImporter() const {
967 using Teuchos::Array;
968 using Teuchos::ArrayView;
969 using Teuchos::Comm;
970 using Teuchos::Ptr;
971 using Teuchos::RCP;
972 using Teuchos::rcp;
973 using Teuchos::rcp_dynamic_cast;
974 if (IsParallel_) {
975 if (hasBlockCrsMatrix_) {
976 const RCP<const block_crs_matrix_type> bcrs =
977 rcp_dynamic_cast<const block_crs_matrix_type>(A_);
978 int bs_ = bcrs->getBlockSize();
979 RCP<const map_type> oldDomainMap = A_->getDomainMap();
980 RCP<const map_type> oldColMap = A_->getColMap();
981 // Because A is a block CRS matrix, import will not do what you think it does
982 // We have to construct the correct maps for it
983 global_size_t numGlobalElements = oldColMap->getGlobalNumElements() * bs_;
984 global_ordinal_type indexBase = oldColMap->getIndexBase();
985 RCP<const Comm<int>> comm = oldColMap->getComm();
986 ArrayView<const global_ordinal_type> oldColElements = oldColMap->getLocalElementList();
987 Array<global_ordinal_type> newColElements(bs_ * oldColElements.size());
988 for (int i = 0; i < oldColElements.size(); i++) {
989 for (int j = 0; j < bs_; j++)
990 newColElements[i * bs_ + j] = oldColElements[i] * bs_ + j;
991 }
992 RCP<map_type> colMap(new map_type(numGlobalElements, newColElements, indexBase, comm));
993 // Create the importer
994 Importer_ = rcp(new import_type(oldDomainMap, colMap));
995 } else if (!A_.is_null()) {
996 Importer_ = A_->getGraph()->getImporter();
997 if (Importer_.is_null())
998 Importer_ = rcp(new import_type(A_->getDomainMap(), A_->getColMap()));
999 }
1000 }
1001 // otherwise, Importer_ is not needed and is left NULL
1002}
1003
1004template <class MatrixType, class ContainerType>
1005std::string
1007 description() const {
1008 std::ostringstream out;
1009
1010 // Output is a valid YAML dictionary in flow style. If you don't
1011 // like everything on a single line, you should call describe()
1012 // instead.
1013 out << "\"Ifpack2::BlockRelaxation\": {";
1014 if (this->getObjectLabel() != "") {
1015 out << "Label: \"" << this->getObjectLabel() << "\", ";
1016 }
1017 // out << "Initialized: " << (isInitialized () ? "true" : "false") << ", ";
1018 // out << "Computed: " << (isComputed () ? "true" : "false") << ", ";
1019 if (A_.is_null()) {
1020 out << "Matrix: null, ";
1021 } else {
1022 // out << "Matrix: not null"
1023 // << ", Global matrix dimensions: ["
1024 out << "Global matrix dimensions: ["
1025 << A_->getGlobalNumRows() << ", " << A_->getGlobalNumCols() << "], ";
1026 }
1027
1028 // It's useful to print this instance's relaxation method. If you
1029 // want more info than that, call describe() instead.
1030 out << "\"relaxation: type\": ";
1031 if (PrecType_ == Ifpack2::Details::JACOBI) {
1032 out << "Block Jacobi";
1033 } else if (PrecType_ == Ifpack2::Details::GS) {
1034 out << "Block Gauss-Seidel";
1035 } else if (PrecType_ == Ifpack2::Details::SGS) {
1036 out << "Block Symmetric Gauss-Seidel";
1037 } else if (PrecType_ == Ifpack2::Details::MTSPLITJACOBI) {
1038 out << "MT Split Jacobi";
1039 } else {
1040 out << "INVALID";
1041 }
1042
1043 // BlockCrs if we have that
1044 if (hasBlockCrsMatrix_)
1045 out << ", BlockCrs";
1046
1047 // Print the approximate # rows per part
1048 int approx_rows_per_part = A_->getLocalNumRows() / Partitioner_->numLocalParts();
1049 out << ", blocksize: " << approx_rows_per_part;
1050
1051 out << ", overlap: " << OverlapLevel_;
1052
1053 out << ", "
1054 << "sweeps: " << NumSweeps_ << ", "
1055 << "damping factor: " << DampingFactor_ << ", ";
1056
1057 std::string containerType = ContainerType::getName();
1058 out << "block container: " << ((containerType == "Generic") ? containerType_ : containerType);
1059 if (List_.isParameter("partitioner: PDE equations"))
1060 out << ", dofs/node: " << List_.get<int>("partitioner: PDE equations");
1061
1062 out << "}";
1063 return out.str();
1064}
1065
1066template <class MatrixType, class ContainerType>
1068 describe(Teuchos::FancyOStream& out,
1069 const Teuchos::EVerbosityLevel verbLevel) const {
1070 using std::endl;
1071 using std::setw;
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 Teuchos::EVerbosityLevel vl = verbLevel;
1081 if (vl == VERB_DEFAULT) vl = VERB_LOW;
1082 const int myImageID = A_->getComm()->getRank();
1083
1084 // Convention requires that describe() begin with a tab.
1085 Teuchos::OSTab tab(out);
1086
1087 // none: print nothing
1088 // low: print O(1) info from node 0
1089 // medium:
1090 // high:
1091 // extreme:
1092 if (vl != VERB_NONE && myImageID == 0) {
1093 out << "Ifpack2::BlockRelaxation<"
1094 << TypeNameTraits<MatrixType>::name() << ", "
1095 << TypeNameTraits<ContainerType>::name() << " >:";
1096 Teuchos::OSTab tab1(out);
1097
1098 if (this->getObjectLabel() != "") {
1099 out << "label: \"" << this->getObjectLabel() << "\"" << endl;
1100 }
1101 out << "initialized: " << (isInitialized() ? "true" : "false") << endl
1102 << "computed: " << (isComputed() ? "true" : "false") << endl;
1103
1104 std::string precType;
1105 if (PrecType_ == Ifpack2::Details::JACOBI) {
1106 precType = "Block Jacobi";
1107 } else if (PrecType_ == Ifpack2::Details::GS) {
1108 precType = "Block Gauss-Seidel";
1109 } else if (PrecType_ == Ifpack2::Details::SGS) {
1110 precType = "Block Symmetric Gauss-Seidel";
1111 }
1112 out << "type: " << precType << endl
1113 << "global number of rows: " << A_->getGlobalNumRows() << endl
1114 << "global number of columns: " << A_->getGlobalNumCols() << endl
1115 << "number of sweeps: " << NumSweeps_ << endl
1116 << "damping factor: " << DampingFactor_ << endl
1117 << "nonsymmetric overlap combine" << nonsymCombine_ << endl
1118 << "backwards mode: "
1119 << ((PrecType_ == Ifpack2::Details::GS && DoBackwardGS_) ? "true" : "false")
1120 << endl
1121 << "zero starting solution: "
1122 << (ZeroStartingSolution_ ? "true" : "false") << endl;
1123 }
1124}
1125
1126} // namespace Ifpack2
1127
1128// Macro that does explicit template instantiation (ETI) for
1129// Ifpack2::BlockRelaxation. S, LO, GO, N correspond to the four
1130// template parameters of Ifpack2::Preconditioner and
1131// Tpetra::RowMatrix.
1132//
1133// We only instantiate for MatrixType = Tpetra::RowMatrix. There's no
1134// need to instantiate for Tpetra::CrsMatrix too. All Ifpack2
1135// preconditioners can and should do dynamic casts if they need a type
1136// more specific than RowMatrix. This keeps build time short and
1137// library and executable sizes small.
1138
1139#ifdef HAVE_IFPACK2_EXPLICIT_INSTANTIATION
1140
1141#define IFPACK2_BLOCKRELAXATION_INSTANT(S, LO, GO, N) \
1142 template class Ifpack2::BlockRelaxation< \
1143 Tpetra::RowMatrix<S, LO, GO, N>, \
1144 Ifpack2::Container<Tpetra::RowMatrix<S, LO, GO, N>>>;
1145
1146#endif // HAVE_IFPACK2_EXPLICIT_INSTANTIATION
1147
1148#endif // IFPACK2_BLOCKRELAXATION_DEF_HPP
Ifpack2::BlockRelaxation class declaration.
Declaration of a user-defined partitioner in which the user can define a partition of the graph....
Block relaxation preconditioners (or smoothers) for Tpetra::RowMatrix and Tpetra::CrsMatrix sparse ma...
Definition Ifpack2_BlockRelaxation_decl.hpp:56
Teuchos::RCP< const row_matrix_type > getMatrix() const
The input matrix of this preconditioner's constructor.
Definition Ifpack2_BlockRelaxation_def.hpp:340
Teuchos::RCP< const map_type > getDomainMap() const
Returns the Tpetra::Map object associated with the domain of this operator.
Definition Ifpack2_BlockRelaxation_def.hpp:349
int getNumApply() const
Returns the number of calls to apply().
Definition Ifpack2_BlockRelaxation_def.hpp:390
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Return a list of all the parameters that this class accepts.
Definition Ifpack2_BlockRelaxation_def.hpp:96
BlockRelaxation(const Teuchos::RCP< const row_matrix_type > &Matrix)
Constructor.
Definition Ifpack2_BlockRelaxation_def.hpp:58
void compute()
compute the preconditioner for the specified matrix, diagonal perturbation thresholds and relaxation ...
Definition Ifpack2_BlockRelaxation_def.hpp:742
size_t getNodeSmootherComplexity() const
Get a rough estimate of cost per iteration.
Definition Ifpack2_BlockRelaxation_def.hpp:416
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_BlockRelaxation_def.hpp:1068
MatrixType::local_ordinal_type local_ordinal_type
The type of local indices in the input MatrixType.
Definition Ifpack2_BlockRelaxation_decl.hpp:65
virtual ~BlockRelaxation()
Destructor.
Definition Ifpack2_BlockRelaxation_def.hpp:91
int getNumCompute() const
Returns the number of calls to compute().
Definition Ifpack2_BlockRelaxation_def.hpp:384
double getApplyTime() const
Returns the time spent in apply().
Definition Ifpack2_BlockRelaxation_def.hpp:411
int getNumInitialize() const
Returns the number of calls to initialize().
Definition Ifpack2_BlockRelaxation_def.hpp:378
void initialize()
Initialize.
Definition Ifpack2_BlockRelaxation_def.hpp:555
Teuchos::RCP< const map_type > getRangeMap() const
Returns the Tpetra::Map object associated with the range of this operator.
Definition Ifpack2_BlockRelaxation_def.hpp:362
void applyMat(const MV &X, MV &Y, Teuchos::ETransp mode=Teuchos::NO_TRANS) const
Applies the matrix to a Tpetra::MultiVector.
Definition Ifpack2_BlockRelaxation_def.hpp:541
double getComputeTime() const
Returns the time spent in compute().
Definition Ifpack2_BlockRelaxation_def.hpp:404
void setParameters(const Teuchos::ParameterList &params)
Sets all the parameters for the preconditioner.
Definition Ifpack2_BlockRelaxation_def.hpp:156
double getInitializeTime() const
Returns the time spent in initialize().
Definition Ifpack2_BlockRelaxation_def.hpp:397
void apply(const MV &X, MV &Y, Teuchos::ETransp mode=Teuchos::NO_TRANS, scalar_type alpha=Teuchos::ScalarTraits< scalar_type >::one(), scalar_type beta=Teuchos::ScalarTraits< scalar_type >::zero()) const
Applies the preconditioner to X, returns the result in Y.
Definition Ifpack2_BlockRelaxation_def.hpp:433
std::string description() const
A one-line description of this object.
Definition Ifpack2_BlockRelaxation_def.hpp:1007
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
The communicator over which the input matrix is distributed.
Definition Ifpack2_BlockRelaxation_def.hpp:327
virtual void setMatrix(const Teuchos::RCP< const row_matrix_type > &A)
Change the matrix to be preconditioned.
Definition Ifpack2_BlockRelaxation_def.hpp:31
MatrixType::scalar_type scalar_type
The type of the entries of the input MatrixType.
Definition Ifpack2_BlockRelaxation_decl.hpp:62
Ifpack2's implementation of Trilinos::Details::LinearSolver interface.
Definition Ifpack2_Details_LinearSolver_decl.hpp:75
Ifpack2::LinePartitioner: A class to define partitions into a set of lines.
Definition Ifpack2_LinePartitioner_decl.hpp:45
A class to define linear partitions.
Definition Ifpack2_LinearPartitioner_decl.hpp:27
Access only local rows and columns of a sparse matrix.
Definition Ifpack2_LocalFilter_decl.hpp:128
Ifpack2::Partitioner:
Definition Ifpack2_Partitioner.hpp:146
Ifpack2 implementation details.
Preconditioners and smoothers for Tpetra sparse matrices.
Definition Ifpack2_AdditiveSchwarz_decl.hpp:40
void getValidParameters(Teuchos::ParameterList &params)
Fills a list which contains all the parameters possibly used by Ifpack2.
Definition Ifpack2_Parameters.cpp:18
void getParameter(const Teuchos::ParameterList &params, const std::string &name, T &value)
Set a value from a ParameterList if a parameter with the specified name exists.
Definition Ifpack2_Parameters.hpp:26
static Teuchos::RCP< BaseContainer > build(std::string containerType, const Teuchos::RCP< const MatrixType > &A, const Teuchos::Array< Teuchos::Array< local_ordinal_type > > &partitions, const Teuchos::RCP< const import_type > importer, bool pointIndexed)
Build a specialization of Ifpack2::Container given a key that has been registered.
Definition Ifpack2_ContainerFactory_def.hpp:54