Ifpack2 Templated Preconditioning Package Version 1.0
Loading...
Searching...
No Matches
Ifpack2_LocalFilter_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_LOCALFILTER_DEF_HPP
11#define IFPACK2_LOCALFILTER_DEF_HPP
12
13#include <Ifpack2_LocalFilter_decl.hpp>
14#include <Tpetra_Map.hpp>
15#include <Tpetra_MultiVector.hpp>
16#include <Tpetra_Vector.hpp>
17
18#ifdef HAVE_MPI
19#include "Teuchos_DefaultMpiComm.hpp"
20#else
21#include "Teuchos_DefaultSerialComm.hpp"
22#endif
23
24namespace Ifpack2 {
25
26template <class MatrixType>
27bool LocalFilter<MatrixType>::
28 mapPairsAreFitted(const row_matrix_type& A) {
29 const auto rangeMap = A.getRangeMap();
30 const auto rowMap = A.getRowMap();
31 const bool rangeAndRowFitted = mapPairIsFitted(*rowMap, *rangeMap);
32
33 const auto domainMap = A.getDomainMap();
34 const auto columnMap = A.getColMap();
35 const bool domainAndColumnFitted = mapPairIsFitted(*columnMap, *domainMap);
36
37 // Note BMK 6-22: Map::isLocallyFitted is a local-only operation, not a collective.
38 // This means that it can return different values on different ranks. This can cause MPI to hang,
39 // even though it's supposed to terminate globally when any single rank does.
40 //
41 // This function doesn't need to be fast since it's debug-only code.
42 int localSuccess = rangeAndRowFitted && domainAndColumnFitted;
43 int globalSuccess;
44
45 Teuchos::reduceAll<int, int>(*(A.getComm()), Teuchos::REDUCE_MIN, localSuccess, Teuchos::outArg(globalSuccess));
46
47 return globalSuccess == 1;
48}
49
50template <class MatrixType>
51bool LocalFilter<MatrixType>::
52 mapPairIsFitted(const map_type& map1, const map_type& map2) {
53 return map1.isLocallyFitted(map2);
54}
55
56template <class MatrixType>
58 LocalFilter(const Teuchos::RCP<const row_matrix_type>& A)
59 : A_(A)
60 , NumNonzeros_(0)
61 , MaxNumEntries_(0)
62 , MaxNumEntriesA_(0) {
63 using Teuchos::RCP;
64 using Teuchos::rcp;
65
66#ifdef HAVE_IFPACK2_DEBUG
67 if (!mapPairsAreFitted(*A)) {
68 std::cout << "WARNING: Ifpack2::LocalFilter:\n"
69 << "A's Map pairs are not fitted to each other on Process "
70 << A_->getRowMap()->getComm()->getRank() << " of the input matrix's "
71 "communicator.\n"
72 "This means that LocalFilter may not work with A. "
73 "Please see discussion of Bug 5992.";
74 }
75#endif // HAVE_IFPACK2_DEBUG
76
77 // Build the local communicator (containing this process only).
78 RCP<const Teuchos::Comm<int> > localComm;
79#ifdef HAVE_MPI
80 localComm = rcp(new Teuchos::MpiComm<int>(MPI_COMM_SELF));
81#else
82 localComm = rcp(new Teuchos::SerialComm<int>());
83#endif // HAVE_MPI
84
85 // // FIXME (mfh 21 Nov 2013) Currently, the implementation implicitly
86 // // assumes that the range Map is fitted to the row Map. Otherwise,
87 // // it probably won't work at all.
88 // TEUCHOS_TEST_FOR_EXCEPTION(
89 // mapPairIsFitted (* (A_->getRangeMap ()), * (A_->getRowMap ())),
90 // std::logic_error, "Ifpack2::LocalFilter: Range Map of the input matrix "
91 // "is not fitted to its row Map. LocalFilter does not currently work in "
92 // "this case. See Bug 5992.");
93
94 // Build the local row, domain, and range Maps. They both use the
95 // local communicator built above. The global indices of each are
96 // different than those of the corresponding original Map; they
97 // actually are the same as the local indices of the original Map.
98 //
99 // It's even OK if signedness of local_ordinal_type and
100 // global_ordinal_type are different. (That would be a BAD IDEA but
101 // some users seem to enjoy making trouble for themselves and us.)
102 //
103 // Both the local row and local range Maps must have the same number
104 // of entries, namely, that of the local number of entries of A's
105 // range Map.
106
107 const int blockSize = getBlockSize();
108 const size_t numRows = A_->getRangeMap()->getLocalNumElements() / blockSize;
109
110 const global_ordinal_type indexBase = static_cast<global_ordinal_type>(0);
111
112 localRowMap_ =
113 rcp(new map_type(numRows, indexBase, localComm,
114 Tpetra::GloballyDistributed));
115 // If the original matrix's range Map is not fitted to its row Map,
116 // we'll have to do an Export when applying the matrix.
117 localRangeMap_ = localRowMap_;
118
119 // If the original matrix's domain Map is not fitted to its column
120 // Map, we'll have to do an Import when applying the matrix.
121 if (A_->getRangeMap().getRawPtr() == A_->getDomainMap().getRawPtr()) {
122 // The input matrix's domain and range Maps are identical, so the
123 // locally filtered matrix's domain and range Maps can be also.
124 localDomainMap_ = localRangeMap_;
125 } else {
126 const size_t numCols = A_->getDomainMap()->getLocalNumElements() / blockSize;
127 localDomainMap_ =
128 rcp(new map_type(numCols, indexBase, localComm,
129 Tpetra::GloballyDistributed));
130 }
131
132 // NodeNumEntries_ will contain the actual number of nonzeros for
133 // each localized row (that is, without external nodes, and always
134 // with the diagonal entry)
135 NumEntries_.resize(numRows);
136
137 // tentative value for MaxNumEntries. This is the number of
138 // nonzeros in the local matrix
139 MaxNumEntries_ = A_->getLocalMaxNumRowEntries();
140 MaxNumEntriesA_ = A_->getLocalMaxNumRowEntries();
141
142 // Allocate temporary arrays for getLocalRowCopy().
143 Kokkos::resize(localIndices_, MaxNumEntries_);
144 Kokkos::resize(localIndicesForGlobalCopy_, MaxNumEntries_);
145 Kokkos::resize(Values_, MaxNumEntries_ * blockSize * blockSize);
146
147 // now compute:
148 // - the number of nonzero per row
149 // - the total number of nonzeros
150 // - the diagonal entries
151
152 // compute nonzeros (total and per-row), and store the
153 // diagonal entries (already modified)
154 size_t ActualMaxNumEntries = 0;
155
156 for (size_t i = 0; i < numRows; ++i) {
157 NumEntries_[i] = 0;
158 size_t Nnz, NewNnz = 0;
159 A_->getLocalRowCopy(i, localIndices_, Values_, Nnz);
160 for (size_t j = 0; j < Nnz; ++j) {
161 // FIXME (mfh 03 Apr 2013) This assumes the following:
162 //
163 // 1. Row Map, range Map, and domain Map are all the same.
164 //
165 // 2. The column Map's list of GIDs on this process is the
166 // domain Map's list of GIDs, followed by remote GIDs. Thus,
167 // for any GID in the domain Map on this process, its LID in
168 // the domain Map (and therefore in the row Map, by (1)) is
169 // the same as its LID in the column Map. (Hence the
170 // less-than test, which if true, means that localIndices_[j]
171 // belongs to the row Map.)
172 if (static_cast<size_t>(localIndices_[j]) < numRows) {
173 ++NewNnz;
174 }
175 }
176
177 if (NewNnz > ActualMaxNumEntries) {
178 ActualMaxNumEntries = NewNnz;
179 }
180
181 NumNonzeros_ += NewNnz;
182 NumEntries_[i] = NewNnz;
183 }
184
185 MaxNumEntries_ = ActualMaxNumEntries;
186}
187
188template <class MatrixType>
190
191template <class MatrixType>
192Teuchos::RCP<const Teuchos::Comm<int> >
194 return localRowMap_->getComm();
195}
196
197template <class MatrixType>
198Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,
199 typename MatrixType::global_ordinal_type,
200 typename MatrixType::node_type> >
202 return localRowMap_;
203}
204
205template <class MatrixType>
206Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,
207 typename MatrixType::global_ordinal_type,
208 typename MatrixType::node_type> >
210 return localRowMap_; // FIXME (mfh 20 Nov 2013)
211}
212
213template <class MatrixType>
214Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,
215 typename MatrixType::global_ordinal_type,
216 typename MatrixType::node_type> >
218 return localDomainMap_;
219}
220
221template <class MatrixType>
222Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,
223 typename MatrixType::global_ordinal_type,
224 typename MatrixType::node_type> >
226 return localRangeMap_;
227}
228
229template <class MatrixType>
230Teuchos::RCP<const Tpetra::RowGraph<typename MatrixType::local_ordinal_type,
231 typename MatrixType::global_ordinal_type,
232 typename MatrixType::node_type> >
234 if (local_graph_ == Teuchos::null) {
235 local_ordinal_type numRows = this->getLocalNumRows();
236 Teuchos::Array<size_t> entriesPerRow(numRows);
237 for (local_ordinal_type i = 0; i < numRows; i++) {
238 entriesPerRow[i] = this->getNumEntriesInLocalRow(i);
239 }
240 Teuchos::RCP<crs_graph_type> local_graph_nc =
241 Teuchos::rcp(new crs_graph_type(this->getRowMap(),
242 this->getColMap(),
243 entriesPerRow()));
244 // copy local indexes into local graph
245 nonconst_local_inds_host_view_type indices("indices", this->getLocalMaxNumRowEntries());
246 nonconst_values_host_view_type values("values", this->getLocalMaxNumRowEntries());
247 for (local_ordinal_type i = 0; i < numRows; i++) {
248 size_t numEntries = 0;
249 this->getLocalRowCopy(i, indices, values, numEntries); // get indices & values
250 local_graph_nc->insertLocalIndices(i, numEntries, indices.data());
251 }
252 local_graph_nc->fillComplete(this->getDomainMap(), this->getRangeMap());
253 local_graph_ = Teuchos::rcp_const_cast<const crs_graph_type>(local_graph_nc);
254 }
255 return local_graph_;
256}
257
258template <class MatrixType>
260 return static_cast<global_size_t>(localRangeMap_->getLocalNumElements());
261}
262
263template <class MatrixType>
265 return static_cast<global_size_t>(localDomainMap_->getLocalNumElements());
266}
267
268template <class MatrixType>
270 return static_cast<size_t>(localRangeMap_->getLocalNumElements());
271}
272
273template <class MatrixType>
275 return static_cast<size_t>(localDomainMap_->getLocalNumElements());
276}
277
278template <class MatrixType>
279typename MatrixType::global_ordinal_type
281 return A_->getIndexBase();
282}
283
284template <class MatrixType>
286 return NumNonzeros_;
287}
288
289template <class MatrixType>
291 return NumNonzeros_;
292}
293
294template <class MatrixType>
295typename MatrixType::local_ordinal_type LocalFilter<MatrixType>::getBlockSize() const {
296 return A_->getBlockSize();
297}
298
299template <class MatrixType>
300size_t
303 const local_ordinal_type localRow = getRowMap()->getLocalElement(globalRow);
304 if (localRow == Teuchos::OrdinalTraits<local_ordinal_type>::invalid()) {
305 // NOTE (mfh 26 Mar 2014) We return zero if globalRow is not in
306 // the row Map on this process, since "get the number of entries
307 // in the global row" refers only to what the calling process owns
308 // in that row. In this case, it owns no entries in that row,
309 // since it doesn't own the row.
310 return 0;
311 } else {
312 return NumEntries_[localRow];
313 }
314}
315
316template <class MatrixType>
317size_t
320 // FIXME (mfh 07 Jul 2014) Shouldn't localRow be a local row index
321 // in the matrix's row Map, not in the LocalFilter's row Map? The
322 // latter is different; it even has different global indices!
323 // (Maybe _that_'s the bug.)
324
325 if (getRowMap()->isNodeLocalElement(localRow)) {
326 return NumEntries_[localRow];
327 } else {
328 // NOTE (mfh 26 Mar 2014) We return zero if localRow is not in the
329 // row Map on this process, since "get the number of entries in
330 // the local row" refers only to what the calling process owns in
331 // that row. In this case, it owns no entries in that row, since
332 // it doesn't own the row.
333 return 0;
334 }
335}
336
337template <class MatrixType>
339 return MaxNumEntries_;
340}
341
342template <class MatrixType>
344 return MaxNumEntries_;
345}
346
347template <class MatrixType>
349 return true;
350}
351
352template <class MatrixType>
354 return A_->isLocallyIndexed();
355}
356
357template <class MatrixType>
359 return A_->isGloballyIndexed();
360}
361
362template <class MatrixType>
364 return A_->isFillComplete();
365}
366
367template <class MatrixType>
370 nonconst_global_inds_host_view_type& globalIndices,
371 nonconst_values_host_view_type& values,
372 size_t& numEntries) const {
373 typedef local_ordinal_type LO;
374 typedef typename Teuchos::Array<LO>::size_type size_type;
375
376 const LO localRow = this->getRowMap()->getLocalElement(globalRow);
377 if (localRow == Teuchos::OrdinalTraits<LO>::invalid()) {
378 // NOTE (mfh 26 Mar 2014) We return no entries if globalRow is not
379 // in the row Map on this process, since "get a copy of the
380 // entries in the global row" refers only to what the calling
381 // process owns in that row. In this case, it owns no entries in
382 // that row, since it doesn't own the row.
383 numEntries = 0;
384 } else {
385 // First get a copy of the current row using local indices. Then,
386 // convert to global indices using the input matrix's column Map.
387 //
388 numEntries = this->getNumEntriesInLocalRow(localRow);
389 // FIXME (mfh 26 Mar 2014) If local_ordinal_type ==
390 // global_ordinal_type, we could just alias the input array
391 // instead of allocating a temporary array.
392
393 // In this case, getLocalRowCopy *does* use the localIndices_, so we use a second temp array
394 this->getLocalRowCopy(localRow, localIndicesForGlobalCopy_, values, numEntries);
395
396 const map_type& colMap = *(this->getColMap());
397
398 // Don't fill the output array beyond its size.
399 const size_type numEnt =
400 std::min(static_cast<size_type>(numEntries),
401 std::min((size_type)globalIndices.size(), (size_type)values.size()));
402 for (size_type k = 0; k < numEnt; ++k) {
403 globalIndices[k] = colMap.getGlobalElement(localIndicesForGlobalCopy_[k]);
404 }
405 }
406}
407
408template <class MatrixType>
411 nonconst_local_inds_host_view_type& Indices,
412 nonconst_values_host_view_type& Values,
413 size_t& NumEntries) const {
414 typedef local_ordinal_type LO;
415 typedef global_ordinal_type GO;
416
417 if (!A_->getRowMap()->isNodeLocalElement(LocalRow)) {
418 // The calling process owns zero entries in the row.
419 NumEntries = 0;
420 return;
421 }
422
423 if (A_->getRowMap()->getComm()->getSize() == 1) {
424 A_->getLocalRowCopy(LocalRow, Indices, Values, NumEntries);
425 return;
426 }
427
428 const LO blockNumEntr = getBlockSize() * getBlockSize();
429
430 const size_t numEntInLclRow = NumEntries_[LocalRow];
431 if (static_cast<size_t>(Indices.size()) < numEntInLclRow ||
432 static_cast<size_t>(Values.size()) < numEntInLclRow * blockNumEntr) {
433 // FIXME (mfh 07 Jul 2014) Return an error code instead of
434 // throwing. We should really attempt to fill as much space as
435 // we're given, in this case.
436 TEUCHOS_TEST_FOR_EXCEPTION(
437 true, std::runtime_error,
438 "Ifpack2::LocalFilter::getLocalRowCopy: Invalid output array length. "
439 "The output arrays must each have length at least "
440 << numEntInLclRow
441 << " for local row " << LocalRow << " on Process "
442 << localRowMap_->getComm()->getRank() << ".");
443 } else if (numEntInLclRow == static_cast<size_t>(0)) {
444 // getNumEntriesInLocalRow() returns zero if LocalRow is not owned
445 // by the calling process. In that case, the calling process owns
446 // zero entries in the row.
447 NumEntries = 0;
448 return;
449 }
450
451 // Always extract using the temporary arrays Values_ and
452 // localIndices_. This is because I may need more space than that
453 // given by the user. The users expects only the local (in the
454 // domain Map) column indices, but I have to extract both local and
455 // remote (not in the domain Map) column indices.
456 //
457 // FIXME (mfh 07 Jul 2014) Use of temporary local storage is not
458 // conducive to thread parallelism. A better way would be to change
459 // the interface so that it only extracts values for the "local"
460 // column indices. CrsMatrix could take a set of column indices,
461 // and return their corresponding values.
462 size_t numEntInMat = 0;
463 A_->getLocalRowCopy(LocalRow, localIndices_, Values_, numEntInMat);
464
465 // Fill the user's arrays with the "local" indices and values in
466 // that row. Note that the matrix might have a different column Map
467 // than the local filter.
468 const map_type& matrixDomMap = *(A_->getDomainMap());
469 const map_type& matrixColMap = *(A_->getColMap());
470
471 const size_t capacity = static_cast<size_t>(std::min(Indices.size(),
472 Values.size() / blockNumEntr));
473 NumEntries = 0;
474 const size_t numRows = localRowMap_->getLocalNumElements(); // superfluous
475 const bool buggy = true; // mfh 07 Jul 2014: See FIXME below.
476 for (size_t j = 0; j < numEntInMat; ++j) {
477 // The LocalFilter only includes entries in the domain Map on
478 // the calling process. We figure out whether an entry is in
479 // the domain Map by converting the (matrix column Map) index to
480 // a global index, and then asking whether that global index is
481 // in the domain Map.
482 const LO matrixLclCol = localIndices_[j];
483 const GO gblCol = matrixColMap.getGlobalElement(matrixLclCol);
484
485 // FIXME (mfh 07 Jul 2014) This is the likely center of Bug 5992
486 // and perhaps other bugs, like Bug 6117. If 'buggy' is true,
487 // Ifpack2 tests pass; if 'buggy' is false, the tests don't pass.
488 // This suggests that Ifpack2 classes could be using LocalFilter
489 // incorrectly, perhaps by giving it an incorrect domain Map.
490 if (buggy) {
491 // only local indices
492 if ((size_t)localIndices_[j] < numRows) {
493 Indices[NumEntries] = localIndices_[j];
494 for (LO k = 0; k < blockNumEntr; ++k)
495 Values[NumEntries * blockNumEntr + k] = Values_[j * blockNumEntr + k];
496 NumEntries++;
497 }
498 } else {
499 if (matrixDomMap.isNodeGlobalElement(gblCol)) {
500 // Don't fill more space than the user gave us. It's an error
501 // for them not to give us enough space, but we still shouldn't
502 // overwrite memory that doesn't belong to us.
503 if (NumEntries < capacity) {
504 Indices[NumEntries] = matrixLclCol;
505 for (LO k = 0; k < blockNumEntr; ++k)
506 Values[NumEntries * blockNumEntr + k] = Values_[j * blockNumEntr + k];
507 }
508 NumEntries++;
509 }
510 }
511 }
512}
513
514template <class MatrixType>
517 global_inds_host_view_type& /*indices*/,
518 values_host_view_type& /*values*/) const {
519 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
520 "Ifpack2::LocalFilter does not implement getGlobalRowView.");
521}
522
523template <class MatrixType>
526 local_inds_host_view_type& /*indices*/,
527 values_host_view_type& /*values*/) const {
528 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
529 "Ifpack2::LocalFilter does not implement getLocalRowView.");
530}
531
532template <class MatrixType>
534 getLocalDiagCopy(Tpetra::Vector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& diag) const {
535 using Teuchos::RCP;
536 typedef Tpetra::Vector<scalar_type, local_ordinal_type,
538 vector_type;
539 // This is always correct, and doesn't require a collective check
540 // for sameness of Maps.
541 RCP<vector_type> diagView = diag.offsetViewNonConst(A_->getRowMap(), 0);
542 A_->getLocalDiagCopy(*diagView);
543}
544
545template <class MatrixType>
547 leftScale(const Tpetra::Vector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& /* x */) {
548 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
549 "Ifpack2::LocalFilter does not implement leftScale.");
550}
551
552template <class MatrixType>
554 rightScale(const Tpetra::Vector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& /* x */) {
555 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
556 "Ifpack2::LocalFilter does not implement rightScale.");
557}
558
559template <class MatrixType>
561 apply(const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
562 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
563 Teuchos::ETransp mode,
564 scalar_type alpha,
565 scalar_type beta) const {
566 typedef Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type> MV;
567 TEUCHOS_TEST_FOR_EXCEPTION(
568 X.getNumVectors() != Y.getNumVectors(), std::runtime_error,
569 "Ifpack2::LocalFilter::apply: X and Y must have the same number of columns. "
570 "X has "
571 << X.getNumVectors() << " columns, but Y has "
572 << Y.getNumVectors() << " columns.");
573
574#ifdef HAVE_IFPACK2_DEBUG
575 {
576 typedef Teuchos::ScalarTraits<magnitude_type> STM;
577 Teuchos::Array<magnitude_type> norms(X.getNumVectors());
578 X.norm1(norms());
579 bool good = true;
580 for (size_t j = 0; j < X.getNumVectors(); ++j) {
581 if (STM::isnaninf(norms[j])) {
582 good = false;
583 break;
584 }
585 }
586 TEUCHOS_TEST_FOR_EXCEPTION(!good, std::runtime_error, "Ifpack2::LocalFilter::apply: The 1-norm of the input X is NaN or Inf.");
587 }
588#endif // HAVE_IFPACK2_DEBUG
589
590 TEUCHOS_TEST_FOR_EXCEPTION(
591 getBlockSize() > 1, std::runtime_error,
592 "Ifpack2::LocalFilter::apply: Block size greater than zero is not yet supported for "
593 "LocalFilter::apply. Please contact an Ifpack2 developer to request this feature.");
594
595 if (&X == &Y) {
596 // FIXME (mfh 23 Apr 2014) We have to do more work to figure out
597 // if X and Y alias one another. For example, we should check
598 // whether one is a noncontiguous view of the other.
599 //
600 // X and Y alias one another, so we have to copy X.
601 MV X_copy(X, Teuchos::Copy);
602 applyNonAliased(X_copy, Y, mode, alpha, beta);
603 } else {
604 applyNonAliased(X, Y, mode, alpha, beta);
605 }
606
607#ifdef HAVE_IFPACK2_DEBUG
608 {
609 typedef Teuchos::ScalarTraits<magnitude_type> STM;
610 Teuchos::Array<magnitude_type> norms(Y.getNumVectors());
611 Y.norm1(norms());
612 bool good = true;
613 for (size_t j = 0; j < Y.getNumVectors(); ++j) {
614 if (STM::isnaninf(norms[j])) {
615 good = false;
616 break;
617 }
618 }
619 TEUCHOS_TEST_FOR_EXCEPTION(!good, std::runtime_error, "Ifpack2::LocalFilter::apply: The 1-norm of the output Y is NaN or Inf.");
620 }
621#endif // HAVE_IFPACK2_DEBUG
622}
623
624template <class MatrixType>
626 applyNonAliased(const Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& X,
627 Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& Y,
628 Teuchos::ETransp mode,
629 scalar_type alpha,
630 scalar_type beta) const {
631 using Teuchos::ArrayRCP;
632 using Teuchos::ArrayView;
633 typedef Teuchos::ScalarTraits<scalar_type> STS;
634
635 const scalar_type zero = STS::zero();
636 const scalar_type one = STS::one();
637
638 if (beta == zero) {
639 Y.putScalar(zero);
640 } else if (beta != one) {
641 Y.scale(beta);
642 }
643
644 const size_t NumVectors = Y.getNumVectors();
645 const size_t numRows = localRowMap_->getLocalNumElements();
646
647 // FIXME (mfh 14 Apr 2014) At some point, we would like to
648 // parallelize this using Kokkos. This would require a
649 // Kokkos-friendly version of getLocalRowCopy, perhaps with
650 // thread-local storage.
651
652 const bool constantStride = X.isConstantStride() && Y.isConstantStride();
653 if (constantStride) {
654 // Since both X and Y have constant stride, we can work with "1-D"
655 // views of their data.
656 const size_t x_stride = X.getStride();
657 const size_t y_stride = Y.getStride();
658 ArrayRCP<scalar_type> y_rcp = Y.get1dViewNonConst();
659 ArrayRCP<const scalar_type> x_rcp = X.get1dView();
660 ArrayView<scalar_type> y_ptr = y_rcp();
661 ArrayView<const scalar_type> x_ptr = x_rcp();
662 for (size_t i = 0; i < numRows; ++i) {
663 size_t Nnz;
664 // Use this class's getrow to make the below code simpler
665 getLocalRowCopy(i, localIndices_, Values_, Nnz);
666 scalar_type* Values = reinterpret_cast<scalar_type*>(Values_.data());
667 if (mode == Teuchos::NO_TRANS) {
668 for (size_t j = 0; j < Nnz; ++j) {
669 const local_ordinal_type col = localIndices_[j];
670 for (size_t k = 0; k < NumVectors; ++k) {
671 y_ptr[i + y_stride * k] +=
672 alpha * Values[j] * x_ptr[col + x_stride * k];
673 }
674 }
675 } else if (mode == Teuchos::TRANS) {
676 for (size_t j = 0; j < Nnz; ++j) {
677 const local_ordinal_type col = localIndices_[j];
678 for (size_t k = 0; k < NumVectors; ++k) {
679 y_ptr[col + y_stride * k] +=
680 alpha * Values[j] * x_ptr[i + x_stride * k];
681 }
682 }
683 } else { // mode==Teuchos::CONJ_TRANS
684 for (size_t j = 0; j < Nnz; ++j) {
685 const local_ordinal_type col = localIndices_[j];
686 for (size_t k = 0; k < NumVectors; ++k) {
687 y_ptr[col + y_stride * k] +=
688 alpha * STS::conjugate(Values[j]) * x_ptr[i + x_stride * k];
689 }
690 }
691 }
692 }
693 } else {
694 // At least one of X or Y does not have constant stride.
695 // This means we must work with "2-D" views of their data.
696 ArrayRCP<ArrayRCP<const scalar_type> > x_ptr = X.get2dView();
697 ArrayRCP<ArrayRCP<scalar_type> > y_ptr = Y.get2dViewNonConst();
698
699 for (size_t i = 0; i < numRows; ++i) {
700 size_t Nnz;
701 // Use this class's getrow to make the below code simpler
702 getLocalRowCopy(i, localIndices_, Values_, Nnz);
703 scalar_type* Values = reinterpret_cast<scalar_type*>(Values_.data());
704 if (mode == Teuchos::NO_TRANS) {
705 for (size_t k = 0; k < NumVectors; ++k) {
706 ArrayView<const scalar_type> x_local = (x_ptr())[k]();
707 ArrayView<scalar_type> y_local = (y_ptr())[k]();
708 for (size_t j = 0; j < Nnz; ++j) {
709 y_local[i] += alpha * Values[j] * x_local[localIndices_[j]];
710 }
711 }
712 } else if (mode == Teuchos::TRANS) {
713 for (size_t k = 0; k < NumVectors; ++k) {
714 ArrayView<const scalar_type> x_local = (x_ptr())[k]();
715 ArrayView<scalar_type> y_local = (y_ptr())[k]();
716 for (size_t j = 0; j < Nnz; ++j) {
717 y_local[localIndices_[j]] += alpha * Values[j] * x_local[i];
718 }
719 }
720 } else { // mode==Teuchos::CONJ_TRANS
721 for (size_t k = 0; k < NumVectors; ++k) {
722 ArrayView<const scalar_type> x_local = (x_ptr())[k]();
723 ArrayView<scalar_type> y_local = (y_ptr())[k]();
724 for (size_t j = 0; j < Nnz; ++j) {
725 y_local[localIndices_[j]] +=
726 alpha * STS::conjugate(Values[j]) * x_local[i];
727 }
728 }
729 }
730 }
731 }
732}
733
734template <class MatrixType>
736 return true;
737}
738
739template <class MatrixType>
741 return false;
742}
743
744template <class MatrixType>
745typename LocalFilter<MatrixType>::mag_type
747#if KOKKOS_VERSION >= 40799
748 typedef KokkosKernels::ArithTraits<scalar_type> STS;
749#else
750 typedef Kokkos::ArithTraits<scalar_type> STS;
751#endif
752#if KOKKOS_VERSION >= 40799
753 typedef KokkosKernels::ArithTraits<mag_type> STM;
754#else
755 typedef Kokkos::ArithTraits<mag_type> STM;
756#endif
757 typedef typename Teuchos::Array<scalar_type>::size_type size_type;
758
759 const size_type maxNumRowEnt = getLocalMaxNumRowEntries();
760 const local_ordinal_type blockNumEntr = getBlockSize() * getBlockSize();
761 nonconst_local_inds_host_view_type ind("ind", maxNumRowEnt);
762 nonconst_values_host_view_type val("val", maxNumRowEnt * blockNumEntr);
763 const size_t numRows = static_cast<size_t>(localRowMap_->getLocalNumElements());
764
765 // FIXME (mfh 03 Apr 2013) Scale during sum to avoid overflow.
766 mag_type sumSquared = STM::zero();
767 for (size_t i = 0; i < numRows; ++i) {
768 size_t numEntries = 0;
769 this->getLocalRowCopy(i, ind, val, numEntries);
770 for (size_type k = 0; k < static_cast<size_type>(numEntries * blockNumEntr); ++k) {
771 const mag_type v_k_abs = STS::magnitude(val[k]);
772 sumSquared += v_k_abs * v_k_abs;
773 }
774 }
775 return STM::squareroot(sumSquared); // Different for each process; that's OK.
776}
777
778template <class MatrixType>
779std::string
781 using Teuchos::TypeNameTraits;
782 std::ostringstream os;
783
784 os << "Ifpack2::LocalFilter: {";
785 os << "MatrixType: " << TypeNameTraits<MatrixType>::name();
786 if (this->getObjectLabel() != "") {
787 os << ", Label: \"" << this->getObjectLabel() << "\"";
788 }
789 os << ", Number of rows: " << getGlobalNumRows()
790 << ", Number of columns: " << getGlobalNumCols()
791 << "}";
792 return os.str();
793}
794
795template <class MatrixType>
797 describe(Teuchos::FancyOStream& out,
798 const Teuchos::EVerbosityLevel verbLevel) const {
799 using std::endl;
800 using Teuchos::OSTab;
801 using Teuchos::TypeNameTraits;
802
803 const Teuchos::EVerbosityLevel vl =
804 (verbLevel == Teuchos::VERB_DEFAULT) ? Teuchos::VERB_LOW : verbLevel;
805
806 if (vl > Teuchos::VERB_NONE) {
807 // describe() starts with a tab, by convention.
808 OSTab tab0(out);
809
810 out << "Ifpack2::LocalFilter:" << endl;
811 OSTab tab1(out);
812 out << "MatrixType: " << TypeNameTraits<MatrixType>::name() << endl;
813 if (this->getObjectLabel() != "") {
814 out << "Label: \"" << this->getObjectLabel() << "\"" << endl;
815 }
816 out << "Number of rows: " << getGlobalNumRows() << endl
817 << "Number of columns: " << getGlobalNumCols() << endl
818 << "Number of nonzeros: " << NumNonzeros_ << endl;
819
820 if (vl > Teuchos::VERB_LOW) {
821 out << "Row Map:" << endl;
822 localRowMap_->describe(out, vl);
823 out << "Domain Map:" << endl;
824 localDomainMap_->describe(out, vl);
825 out << "Range Map:" << endl;
826 localRangeMap_->describe(out, vl);
827 }
828 }
829}
830
831template <class MatrixType>
832Teuchos::RCP<const Tpetra::RowMatrix<typename MatrixType::scalar_type,
833 typename MatrixType::local_ordinal_type,
834 typename MatrixType::global_ordinal_type,
835 typename MatrixType::node_type> >
839
840} // namespace Ifpack2
841
842#define IFPACK2_LOCALFILTER_INSTANT(S, LO, GO, N) \
843 template class Ifpack2::LocalFilter<Tpetra::RowMatrix<S, LO, GO, N> >;
844
845#endif
Access only local rows and columns of a sparse matrix.
Definition Ifpack2_LocalFilter_decl.hpp:128
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Print the object to the given output stream.
Definition Ifpack2_LocalFilter_def.hpp:797
virtual Teuchos::RCP< const Tpetra::RowGraph< local_ordinal_type, global_ordinal_type, node_type > > getGraph() const
The (locally filtered) matrix's graph.
Definition Ifpack2_LocalFilter_def.hpp:233
virtual Teuchos::RCP< const map_type > getDomainMap() const
Returns the Map that describes the domain distribution in this matrix.
Definition Ifpack2_LocalFilter_def.hpp:217
virtual size_t getGlobalMaxNumRowEntries() const
The maximum number of entries across all rows/columns on all processes.
Definition Ifpack2_LocalFilter_def.hpp:338
virtual void leftScale(const Tpetra::Vector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > &x)
Scales the RowMatrix on the left with the Vector x.
Definition Ifpack2_LocalFilter_def.hpp:547
virtual void getGlobalRowCopy(global_ordinal_type GlobalRow, nonconst_global_inds_host_view_type &Indices, nonconst_values_host_view_type &Values, size_t &NumEntries) const
Get the entries in the given row, using global indices.
Definition Ifpack2_LocalFilter_def.hpp:369
virtual bool isGloballyIndexed() const
Whether the underlying sparse matrix is globally (opposite of locally) indexed.
Definition Ifpack2_LocalFilter_def.hpp:358
virtual Teuchos::RCP< const row_matrix_type > getUnderlyingMatrix() const
Return matrix that LocalFilter was built on.
Definition Ifpack2_LocalFilter_def.hpp:836
MatrixType::scalar_type scalar_type
The type of the entries of the input MatrixType.
Definition Ifpack2_LocalFilter_decl.hpp:146
virtual Teuchos::RCP< const map_type > getRangeMap() const
Returns the Map that describes the range distribution in this matrix.
Definition Ifpack2_LocalFilter_def.hpp:225
virtual mag_type getFrobeniusNorm() const
The Frobenius norm of the (locally filtered) matrix.
Definition Ifpack2_LocalFilter_def.hpp:746
virtual size_t getNumEntriesInGlobalRow(global_ordinal_type globalRow) const
The current number of entries on this node in the specified global row.
Definition Ifpack2_LocalFilter_def.hpp:302
MatrixType::node_type node_type
The Node type used by the input MatrixType.
Definition Ifpack2_LocalFilter_decl.hpp:155
virtual global_size_t getGlobalNumCols() const
The number of global columns in this matrix.
Definition Ifpack2_LocalFilter_def.hpp:264
virtual bool hasColMap() const
Whether this matrix has a well-defined column Map.
Definition Ifpack2_LocalFilter_def.hpp:348
virtual void getGlobalRowView(global_ordinal_type GlobalRow, global_inds_host_view_type &indices, values_host_view_type &values) const
Extract a const, non-persisting view of global indices in a specified row of the matrix.
Definition Ifpack2_LocalFilter_def.hpp:516
MatrixType::global_ordinal_type global_ordinal_type
The type of global indices in the input MatrixType.
Definition Ifpack2_LocalFilter_decl.hpp:152
virtual bool isFillComplete() const
Returns true if fillComplete() has been called.
Definition Ifpack2_LocalFilter_def.hpp:363
virtual bool isLocallyIndexed() const
Whether the underlying sparse matrix is locally (opposite of globally) indexed.
Definition Ifpack2_LocalFilter_def.hpp:353
virtual size_t getLocalNumCols() const
The number of columns in the (locally filtered) matrix.
Definition Ifpack2_LocalFilter_def.hpp:274
virtual Teuchos::RCP< const map_type > getColMap() const
Returns the Map that describes the column distribution in this matrix.
Definition Ifpack2_LocalFilter_def.hpp:209
virtual bool hasTransposeApply() const
Whether this operator supports applying the transpose or conjugate transpose.
Definition Ifpack2_LocalFilter_def.hpp:735
virtual void getLocalDiagCopy(Tpetra::Vector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > &diag) const
Get the diagonal entries of the (locally filtered) matrix.
Definition Ifpack2_LocalFilter_def.hpp:534
virtual size_t getLocalMaxNumRowEntries() const
The maximum number of entries across all rows/columns on this process.
Definition Ifpack2_LocalFilter_def.hpp:343
LocalFilter(const Teuchos::RCP< const row_matrix_type > &A)
Constructor.
Definition Ifpack2_LocalFilter_def.hpp:58
virtual global_ordinal_type getIndexBase() const
Returns the index base for global indices for this matrix.
Definition Ifpack2_LocalFilter_def.hpp:280
virtual bool supportsRowViews() const
Returns true if RowViews are supported.
Definition Ifpack2_LocalFilter_def.hpp:740
virtual std::string description() const
A one-line description of this object.
Definition Ifpack2_LocalFilter_def.hpp:780
virtual global_size_t getGlobalNumEntries() const
Returns the global number of entries in this matrix.
Definition Ifpack2_LocalFilter_def.hpp:285
virtual local_ordinal_type getBlockSize() const
The number of degrees of freedom per mesh point.
Definition Ifpack2_LocalFilter_def.hpp:295
virtual ~LocalFilter()
Destructor.
Definition Ifpack2_LocalFilter_def.hpp:189
virtual size_t getLocalNumRows() const
The number of rows owned on the calling process.
Definition Ifpack2_LocalFilter_def.hpp:269
virtual 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
Compute Y = beta*Y + alpha*A_local*X.
Definition Ifpack2_LocalFilter_def.hpp:561
MatrixType::local_ordinal_type local_ordinal_type
The type of local indices in the input MatrixType.
Definition Ifpack2_LocalFilter_decl.hpp:149
virtual void rightScale(const Tpetra::Vector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > &x)
Scales the RowMatrix on the right with the Vector x.
Definition Ifpack2_LocalFilter_def.hpp:554
virtual void getLocalRowCopy(local_ordinal_type LocalRow, nonconst_local_inds_host_view_type &Indices, nonconst_values_host_view_type &Values, size_t &NumEntries) const
Get the entries in the given row, using local indices.
Definition Ifpack2_LocalFilter_def.hpp:410
virtual size_t getNumEntriesInLocalRow(local_ordinal_type localRow) const
The current number of entries on this node in the specified local row.
Definition Ifpack2_LocalFilter_def.hpp:319
virtual void getLocalRowView(local_ordinal_type LocalRow, local_inds_host_view_type &indices, values_host_view_type &values) const
Extract a const, non-persisting view of local indices in a specified row of the matrix.
Definition Ifpack2_LocalFilter_def.hpp:525
virtual global_size_t getGlobalNumRows() const
The number of global rows in this matrix.
Definition Ifpack2_LocalFilter_def.hpp:259
Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > map_type
Type of the Tpetra::Map specialization that this class uses.
Definition Ifpack2_LocalFilter_decl.hpp:185
virtual size_t getLocalNumEntries() const
Returns the local number of entries in this matrix.
Definition Ifpack2_LocalFilter_def.hpp:290
virtual Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Returns the communicator.
Definition Ifpack2_LocalFilter_def.hpp:193
virtual Teuchos::RCP< const map_type > getRowMap() const
Returns the Map that describes the row distribution in this matrix.
Definition Ifpack2_LocalFilter_def.hpp:201
Preconditioners and smoothers for Tpetra sparse matrices.
Definition Ifpack2_AdditiveSchwarz_decl.hpp:40