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