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