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 
239 
240 template<class MatrixType>
241 Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,
242  typename MatrixType::global_ordinal_type,
243  typename MatrixType::node_type> >
245 {
246  return localRowMap_;
247 }
248 
249 
250 template<class MatrixType>
251 Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,
252  typename MatrixType::global_ordinal_type,
253  typename MatrixType::node_type> >
255 {
256  return localRowMap_; // FIXME (mfh 20 Nov 2013)
257 }
258 
259 
260 template<class MatrixType>
261 Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,
262  typename MatrixType::global_ordinal_type,
263  typename MatrixType::node_type> >
265 {
266  return localDomainMap_;
267 }
268 
269 
270 template<class MatrixType>
271 Teuchos::RCP<const Tpetra::Map<typename MatrixType::local_ordinal_type,
272  typename MatrixType::global_ordinal_type,
273  typename MatrixType::node_type> >
275 {
276  return localRangeMap_;
277 }
278 
279 
280 template<class MatrixType>
281 Teuchos::RCP<const Tpetra::RowGraph<typename MatrixType::local_ordinal_type,
282  typename MatrixType::global_ordinal_type,
283  typename MatrixType::node_type> >
285 {
286  // FIXME (mfh 20 Nov 2013) This is not what the documentation says
287  // this method should do! It should return the graph of the locally
288  // filtered matrix, not the original matrix's graph.
289  return A_->getGraph ();
290 }
291 
292 
293 template<class MatrixType>
295 {
296  return static_cast<global_size_t> (localRangeMap_->getNodeNumElements ());
297 }
298 
299 
300 template<class MatrixType>
302 {
303  return static_cast<global_size_t> (localDomainMap_->getNodeNumElements ());
304 }
305 
306 
307 template<class MatrixType>
309 {
310  return static_cast<size_t> (localRangeMap_->getNodeNumElements ());
311 }
312 
313 
314 template<class MatrixType>
316 {
317  return static_cast<size_t> (localDomainMap_->getNodeNumElements ());
318 }
319 
320 
321 template<class MatrixType>
322 typename MatrixType::global_ordinal_type
324 {
325  return A_->getIndexBase ();
326 }
327 
328 
329 template<class MatrixType>
331 {
332  return NumNonzeros_;
333 }
334 
335 
336 template<class MatrixType>
338 {
339  return NumNonzeros_;
340 }
341 
342 
343 template<class MatrixType>
344 size_t
346 getNumEntriesInGlobalRow (global_ordinal_type globalRow) const
347 {
348  const local_ordinal_type localRow = getRowMap ()->getLocalElement (globalRow);
350  // NOTE (mfh 26 Mar 2014) We return zero if globalRow is not in
351  // the row Map on this process, since "get the number of entries
352  // in the global row" refers only to what the calling process owns
353  // in that row. In this case, it owns no entries in that row,
354  // since it doesn't own the row.
355  return 0;
356  } else {
357  return NumEntries_[localRow];
358  }
359 }
360 
361 
362 template<class MatrixType>
363 size_t
366 {
367  // FIXME (mfh 07 Jul 2014) Shouldn't localRow be a local row index
368  // in the matrix's row Map, not in the LocalFilter's row Map? The
369  // latter is different; it even has different global indices!
370  // (Maybe _that_'s the bug.)
371 
372  if (getRowMap ()->isNodeLocalElement (localRow)) {
373  return NumEntries_[localRow];
374  } else {
375  // NOTE (mfh 26 Mar 2014) We return zero if localRow is not in the
376  // row Map on this process, since "get the number of entries in
377  // the local row" refers only to what the calling process owns in
378  // that row. In this case, it owns no entries in that row, since
379  // it doesn't own the row.
380  return 0;
381  }
382 }
383 
384 
385 template<class MatrixType>
387 {
388  return MaxNumEntries_;
389 }
390 
391 
392 template<class MatrixType>
394 {
395  return MaxNumEntries_;
396 }
397 
398 
399 template<class MatrixType>
401 {
402  return true;
403 }
404 
405 
406 template<class MatrixType>
408 {
409  return A_->isLocallyIndexed ();
410 }
411 
412 
413 template<class MatrixType>
415 {
416  return A_->isGloballyIndexed();
417 }
418 
419 
420 template<class MatrixType>
422 {
423  return A_->isFillComplete ();
424 }
425 
426 
427 template<class MatrixType>
428 void
430 getGlobalRowCopy (global_ordinal_type globalRow,
431  const Teuchos::ArrayView<global_ordinal_type>& globalIndices,
432  const Teuchos::ArrayView<scalar_type>& values,
433  size_t& numEntries) const
434 {
435  typedef local_ordinal_type LO;
436  typedef typename Teuchos::Array<LO>::size_type size_type;
437 
438  const LO localRow = this->getRowMap ()->getLocalElement (globalRow);
439  if (localRow == Teuchos::OrdinalTraits<LO>::invalid ()) {
440  // NOTE (mfh 26 Mar 2014) We return no entries if globalRow is not
441  // in the row Map on this process, since "get a copy of the
442  // entries in the global row" refers only to what the calling
443  // process owns in that row. In this case, it owns no entries in
444  // that row, since it doesn't own the row.
445  numEntries = 0;
446  }
447  else {
448  // First get a copy of the current row using local indices. Then,
449  // convert to global indices using the input matrix's column Map.
450  //
451  numEntries = this->getNumEntriesInLocalRow (localRow);
452  // FIXME (mfh 26 Mar 2014) If local_ordinal_type ==
453  // global_ordinal_type, we could just alias the input array
454  // instead of allocating a temporary array.
455  Teuchos::Array<LO> localIndices (numEntries);
456  this->getLocalRowCopy (localRow, localIndices (), values, numEntries);
457 
458  const map_type& colMap = * (this->getColMap ());
459 
460  // Don't fill the output array beyond its size.
461  const size_type numEnt =
462  std::min (static_cast<size_type> (numEntries),
463  std::min (globalIndices.size (), values.size ()));
464  for (size_type k = 0; k < numEnt; ++k) {
465  globalIndices[k] = colMap.getGlobalElement (localIndices[k]);
466  }
467  }
468 }
469 
470 
471 template<class MatrixType>
472 void
476  const Teuchos::ArrayView<scalar_type> &Values,
477  size_t &NumEntries) const
478 {
479  typedef local_ordinal_type LO;
480  typedef global_ordinal_type GO;
481 
482  if (! A_->getRowMap ()->isNodeLocalElement (LocalRow)) {
483  // The calling process owns zero entries in the row.
484  NumEntries = 0;
485  return;
486  }
487 
488  if (A_->getRowMap()->getComm()->getSize() == 1) {
489  A_->getLocalRowCopy (LocalRow, Indices (), Values (), NumEntries);
490  return;
491  }
492 
493 
494  const size_t numEntInLclRow = NumEntries_[LocalRow];
495  if (static_cast<size_t> (Indices.size ()) < numEntInLclRow ||
496  static_cast<size_t> (Values.size ()) < numEntInLclRow) {
497  // FIXME (mfh 07 Jul 2014) Return an error code instead of
498  // throwing. We should really attempt to fill as much space as
499  // we're given, in this case.
501  true, std::runtime_error,
502  "Ifpack2::LocalFilter::getLocalRowCopy: Invalid output array length. "
503  "The output arrays must each have length at least " << numEntInLclRow
504  << " for local row " << LocalRow << " on Process "
505  << localRowMap_->getComm ()->getRank () << ".");
506  }
507  else if (numEntInLclRow == static_cast<size_t> (0)) {
508  // getNumEntriesInLocalRow() returns zero if LocalRow is not owned
509  // by the calling process. In that case, the calling process owns
510  // zero entries in the row.
511  NumEntries = 0;
512  return;
513  }
514 
515  // Always extract using the temporary arrays Values_ and
516  // localIndices_. This is because I may need more space than that
517  // given by the user. The users expects only the local (in the
518  // domain Map) column indices, but I have to extract both local and
519  // remote (not in the domain Map) column indices.
520  //
521  // FIXME (mfh 07 Jul 2014) Use of temporary local storage is not
522  // conducive to thread parallelism. A better way would be to change
523  // the interface so that it only extracts values for the "local"
524  // column indices. CrsMatrix could take a set of column indices,
525  // and return their corresponding values.
526  size_t numEntInMat = 0;
527  A_->getLocalRowCopy (LocalRow, localIndices_ (), Values_ (), numEntInMat);
528 
529  // Fill the user's arrays with the "local" indices and values in
530  // that row. Note that the matrix might have a different column Map
531  // than the local filter.
532  const map_type& matrixDomMap = * (A_->getDomainMap ());
533  const map_type& matrixColMap = * (A_->getColMap ());
534 
535  const size_t capacity = static_cast<size_t> (std::min (Indices.size (),
536  Values.size ()));
537  NumEntries = 0;
538  const size_t numRows = localRowMap_->getNodeNumElements (); // superfluous
539  const bool buggy = true; // mfh 07 Jul 2014: See FIXME below.
540  for (size_t j = 0; j < numEntInMat; ++j) {
541  // The LocalFilter only includes entries in the domain Map on
542  // the calling process. We figure out whether an entry is in
543  // the domain Map by converting the (matrix column Map) index to
544  // a global index, and then asking whether that global index is
545  // in the domain Map.
546  const LO matrixLclCol = localIndices_[j];
547  const GO gblCol = matrixColMap.getGlobalElement (matrixLclCol);
548 
549  // FIXME (mfh 07 Jul 2014) This is the likely center of Bug 5992
550  // and perhaps other bugs, like Bug 6117. If 'buggy' is true,
551  // Ifpack2 tests pass; if 'buggy' is false, the tests don't pass.
552  // This suggests that Ifpack2 classes could be using LocalFilter
553  // incorrectly, perhaps by giving it an incorrect domain Map.
554  if (buggy) {
555  // only local indices
556  if ((size_t) localIndices_[j] < numRows) {
557  Indices[NumEntries] = localIndices_[j];
558  Values[NumEntries] = Values_[j];
559  NumEntries++;
560  }
561  } else {
562  if (matrixDomMap.isNodeGlobalElement (gblCol)) {
563  // Don't fill more space than the user gave us. It's an error
564  // for them not to give us enough space, but we still shouldn't
565  // overwrite memory that doesn't belong to us.
566  if (NumEntries < capacity) {
567  Indices[NumEntries] = matrixLclCol;
568  Values[NumEntries] = Values_[j];
569  }
570  NumEntries++;
571  }
572  }
573  }
574 }
575 
576 
577 template<class MatrixType>
578 void
580 getGlobalRowView (global_ordinal_type /* GlobalRow */,
582  Teuchos::ArrayView<const scalar_type> &/* values */) const
583 {
584  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
585  "Ifpack2::LocalFilter does not implement getGlobalRowView.");
586 }
587 
588 
589 template<class MatrixType>
590 void
594  Teuchos::ArrayView<const scalar_type> &/* values */) const
595 {
596  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
597  "Ifpack2::LocalFilter does not implement getLocalRowView.");
598 }
599 
600 
601 template<class MatrixType>
602 void
604 getLocalDiagCopy (Tpetra::Vector<scalar_type,local_ordinal_type,global_ordinal_type,node_type>& diag) const
605 {
606  using Teuchos::RCP;
607  typedef Tpetra::Vector<scalar_type, local_ordinal_type,
608  global_ordinal_type, node_type> vector_type;
609  // This is always correct, and doesn't require a collective check
610  // for sameness of Maps.
611  RCP<vector_type> diagView = diag.offsetViewNonConst (A_->getRowMap (), 0);
612  A_->getLocalDiagCopy (*diagView);
613 }
614 
615 
616 template<class MatrixType>
617 void
619 leftScale (const Tpetra::Vector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& /* x */)
620 {
621  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
622  "Ifpack2::LocalFilter does not implement leftScale.");
623 }
624 
625 
626 template<class MatrixType>
627 void
629 rightScale (const Tpetra::Vector<scalar_type, local_ordinal_type, global_ordinal_type, node_type>& /* x */)
630 {
631  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
632  "Ifpack2::LocalFilter does not implement rightScale.");
633 }
634 
635 
636 template<class MatrixType>
637 void
639 apply (const Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type> &X,
640  Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type> &Y,
641  Teuchos::ETransp mode,
642  scalar_type alpha,
643  scalar_type beta) const
644 {
645  typedef Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type> MV;
647  X.getNumVectors() != Y.getNumVectors(), std::runtime_error,
648  "Ifpack2::LocalFilter::apply: X and Y must have the same number of columns. "
649  "X has " << X.getNumVectors () << " columns, but Y has "
650  << Y.getNumVectors () << " columns.");
651 
652 #ifdef HAVE_IFPACK2_DEBUG
653  {
655  Teuchos::Array<magnitude_type> norms (X.getNumVectors ());
656  X.norm1 (norms ());
657  bool good = true;
658  for (size_t j = 0; j < X.getNumVectors (); ++j) {
659  if (STM::isnaninf (norms[j])) {
660  good = false;
661  break;
662  }
663  }
664  TEUCHOS_TEST_FOR_EXCEPTION( ! good, std::runtime_error, "Ifpack2::LocalFilter::apply: The 1-norm of the input X is NaN or Inf.");
665  }
666 #endif // HAVE_IFPACK2_DEBUG
667 
668  if (&X == &Y) {
669  // FIXME (mfh 23 Apr 2014) We have to do more work to figure out
670  // if X and Y alias one another. For example, we should check
671  // whether one is a noncontiguous view of the other.
672  //
673  // X and Y alias one another, so we have to copy X.
674  MV X_copy (X, Teuchos::Copy);
675  applyNonAliased (X_copy, Y, mode, alpha, beta);
676  } else {
677  applyNonAliased (X, Y, mode, alpha, beta);
678  }
679 
680 #ifdef HAVE_IFPACK2_DEBUG
681  {
683  Teuchos::Array<magnitude_type> norms (Y.getNumVectors ());
684  Y.norm1 (norms ());
685  bool good = true;
686  for (size_t j = 0; j < Y.getNumVectors (); ++j) {
687  if (STM::isnaninf (norms[j])) {
688  good = false;
689  break;
690  }
691  }
692  TEUCHOS_TEST_FOR_EXCEPTION( ! good, std::runtime_error, "Ifpack2::LocalFilter::apply: The 1-norm of the output Y is NaN or Inf.");
693  }
694 #endif // HAVE_IFPACK2_DEBUG
695 }
696 
697 template<class MatrixType>
698 void
700 applyNonAliased (const Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type> &X,
701  Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type> &Y,
702  Teuchos::ETransp mode,
703  scalar_type alpha,
704  scalar_type beta) const
705 {
706  using Teuchos::ArrayView;
707  using Teuchos::ArrayRCP;
709 
710  const scalar_type zero = STS::zero ();
711  const scalar_type one = STS::one ();
712 
713  if (beta == zero) {
714  Y.putScalar (zero);
715  }
716  else if (beta != one) {
717  Y.scale (beta);
718  }
719 
720  const size_t NumVectors = Y.getNumVectors ();
721  const size_t numRows = localRowMap_->getNodeNumElements ();
722 
723  // FIXME (mfh 14 Apr 2014) At some point, we would like to
724  // parallelize this using Kokkos. This would require a
725  // Kokkos-friendly version of getLocalRowCopy, perhaps with
726  // thread-local storage.
727 
728  const bool constantStride = X.isConstantStride () && Y.isConstantStride ();
729  if (constantStride) {
730  // Since both X and Y have constant stride, we can work with "1-D"
731  // views of their data.
732  const size_t x_stride = X.getStride();
733  const size_t y_stride = Y.getStride();
734  ArrayRCP<scalar_type> y_rcp = Y.get1dViewNonConst();
735  ArrayRCP<const scalar_type> x_rcp = X.get1dView();
736  ArrayView<scalar_type> y_ptr = y_rcp();
737  ArrayView<const scalar_type> x_ptr = x_rcp();
738  for (size_t i = 0; i < numRows; ++i) {
739  size_t Nnz;
740  // Use this class's getrow to make the below code simpler
741  getLocalRowCopy (i, localIndices_ (), Values_ (), Nnz);
742  if (mode == Teuchos::NO_TRANS) {
743  for (size_t j = 0; j < Nnz; ++j) {
744  const local_ordinal_type col = localIndices_[j];
745  for (size_t k = 0; k < NumVectors; ++k) {
746  y_ptr[i + y_stride*k] +=
747  alpha * Values_[j] * x_ptr[col + x_stride*k];
748  }
749  }
750  }
751  else if (mode == Teuchos::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[col + y_stride*k] +=
756  alpha * Values_[j] * x_ptr[i + x_stride*k];
757  }
758  }
759  }
760  else { //mode==Teuchos::CONJ_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 * STS::conjugate (Values_[j]) * x_ptr[i + x_stride*k];
766  }
767  }
768  }
769  }
770  }
771  else {
772  // At least one of X or Y does not have constant stride.
773  // This means we must work with "2-D" views of their data.
774  ArrayRCP<ArrayRCP<const scalar_type> > x_ptr = X.get2dView();
775  ArrayRCP<ArrayRCP<scalar_type> > y_ptr = Y.get2dViewNonConst();
776 
777  for (size_t i = 0; i < numRows; ++i) {
778  size_t Nnz;
779  // Use this class's getrow to make the below code simpler
780  getLocalRowCopy (i, localIndices_ (), Values_ (), Nnz);
781  if (mode == Teuchos::NO_TRANS) {
782  for (size_t k = 0; k < NumVectors; ++k) {
783  ArrayView<const scalar_type> x_local = (x_ptr())[k]();
784  ArrayView<scalar_type> y_local = (y_ptr())[k]();
785  for (size_t j = 0; j < Nnz; ++j) {
786  y_local[i] += alpha * Values_[j] * x_local[localIndices_[j]];
787  }
788  }
789  }
790  else if (mode == Teuchos::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[localIndices_[j]] += alpha * Values_[j] * x_local[i];
796  }
797  }
798  }
799  else { //mode==Teuchos::CONJ_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]] +=
805  alpha * STS::conjugate (Values_[j]) * x_local[i];
806  }
807  }
808  }
809  }
810  }
811 }
812 
813 template<class MatrixType>
815 {
816  return true;
817 }
818 
819 
820 template<class MatrixType>
822 {
823  return false;
824 }
825 
826 
827 template<class MatrixType>
828 typename
829 LocalFilter<MatrixType>::mag_type
831 {
832 #ifdef TPETRA_HAVE_KOKKOS_REFACTOR
833  typedef Kokkos::Details::ArithTraits<scalar_type> STS;
834  typedef Kokkos::Details::ArithTraits<mag_type> STM;
835 #else
838 #endif
839  typedef typename Teuchos::Array<scalar_type>::size_type size_type;
840 
841  const size_type maxNumRowEnt = getNodeMaxNumRowEntries ();
842  Teuchos::Array<local_ordinal_type> ind (maxNumRowEnt);
843  Teuchos::Array<scalar_type> val (maxNumRowEnt);
844  const size_t numRows = static_cast<size_t> (localRowMap_->getNodeNumElements ());
845 
846  // FIXME (mfh 03 Apr 2013) Scale during sum to avoid overflow.
847  mag_type sumSquared = STM::zero ();
848  for (size_t i = 0; i < numRows; ++i) {
849  size_t numEntries = 0;
850  this->getLocalRowCopy (i, ind (), val (), numEntries);
851  for (size_type k = 0; k < static_cast<size_type> (numEntries); ++k) {
852  const mag_type v_k_abs = STS::magnitude (val[k]);
853  sumSquared += v_k_abs * v_k_abs;
854  }
855  }
856  return STM::squareroot (sumSquared); // Different for each process; that's OK.
857 }
858 
859 template<class MatrixType>
860 std::string
862 {
864  std::ostringstream os;
865 
866  os << "Ifpack2::LocalFilter: {";
867  os << "MatrixType: " << TypeNameTraits<MatrixType>::name ();
868  if (this->getObjectLabel () != "") {
869  os << ", Label: \"" << this->getObjectLabel () << "\"";
870  }
871  os << ", Number of rows: " << getGlobalNumRows ()
872  << ", Number of columns: " << getGlobalNumCols ()
873  << "}";
874  return os.str ();
875 }
876 
877 
878 template<class MatrixType>
879 void
882  const Teuchos::EVerbosityLevel verbLevel) const
883 {
884  using Teuchos::OSTab;
886  using std::endl;
887 
888  const Teuchos::EVerbosityLevel vl =
889  (verbLevel == Teuchos::VERB_DEFAULT) ? Teuchos::VERB_LOW : verbLevel;
890 
891  if (vl > Teuchos::VERB_NONE) {
892  // describe() starts with a tab, by convention.
893  OSTab tab0 (out);
894 
895  out << "Ifpack2::LocalFilter:" << endl;
896  OSTab tab1 (out);
897  out << "MatrixType: " << TypeNameTraits<MatrixType>::name () << endl;
898  if (this->getObjectLabel () != "") {
899  out << "Label: \"" << this->getObjectLabel () << "\"" << endl;
900  }
901  out << "Number of rows: " << getGlobalNumRows () << endl
902  << "Number of columns: " << getGlobalNumCols () << endl
903  << "Number of nonzeros: " << NumNonzeros_ << endl;
904 
905  if (vl > Teuchos::VERB_LOW) {
906  out << "Row Map:" << endl;
907  localRowMap_->describe (out, vl);
908  out << "Domain Map:" << endl;
909  localDomainMap_->describe (out, vl);
910  out << "Range Map:" << endl;
911  localRangeMap_->describe (out, vl);
912  }
913  }
914 }
915 
916 template<class MatrixType>
917 Teuchos::RCP<const Tpetra::RowMatrix<typename MatrixType::scalar_type,
918  typename MatrixType::local_ordinal_type,
919  typename MatrixType::global_ordinal_type,
920  typename MatrixType::node_type> >
922 {
923  return A_;
924 }
925 
926 
927 } // namespace Ifpack2
928 
929 #define IFPACK2_LOCALFILTER_INSTANT(S,LO,GO,N) \
930  template class Ifpack2::LocalFilter< Tpetra::RowMatrix<S, LO, GO, N> >;
931 
932 #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:629
virtual Teuchos::RCP< const map_type > getRowMap() const
Returns the Map that describes the row distribution in this matrix.
Definition: Ifpack2_LocalFilter_def.hpp:244
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:881
basic_OSTab< char > OSTab
virtual size_t getNodeNumRows() const
The number of rows owned on the calling process.
Definition: Ifpack2_LocalFilter_def.hpp:308
virtual Teuchos::RCP< const map_type > getDomainMap() const
Returns the Map that describes the domain distribution in this matrix.
Definition: Ifpack2_LocalFilter_def.hpp:264
#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:421
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:393
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:639
virtual bool hasTransposeApply() const
Whether this operator supports applying the transpose or conjugate transpose.
Definition: Ifpack2_LocalFilter_def.hpp:814
virtual bool isLocallyIndexed() const
Whether the underlying sparse matrix is locally (opposite of globally) indexed.
Definition: Ifpack2_LocalFilter_def.hpp:407
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:580
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:604
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:830
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:284
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:821
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:346
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:619
virtual global_ordinal_type getIndexBase() const
Returns the index base for global indices for this matrix.
Definition: Ifpack2_LocalFilter_def.hpp:323
virtual bool isGloballyIndexed() const
Whether the underlying sparse matrix is globally (opposite of locally) indexed.
Definition: Ifpack2_LocalFilter_def.hpp:414
virtual size_t getGlobalMaxNumRowEntries() const
The maximum number of entries across all rows/columns on all processes.
Definition: Ifpack2_LocalFilter_def.hpp:386
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:474
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:315
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:294
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:861
virtual size_t getNodeNumEntries() const
Returns the local number of entries in this matrix.
Definition: Ifpack2_LocalFilter_def.hpp:337
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:365
virtual Teuchos::RCP< const map_type > getRangeMap() const
Returns the Map that describes the range distribution in this matrix.
Definition: Ifpack2_LocalFilter_def.hpp:274
virtual global_size_t getGlobalNumEntries() const
Returns the global number of entries in this matrix.
Definition: Ifpack2_LocalFilter_def.hpp:330
virtual Teuchos::RCP< const row_matrix_type > getUnderlyingMatrix() const
Return matrix that LocalFilter was built on.
Definition: Ifpack2_LocalFilter_def.hpp:921
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:430
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:301
virtual Teuchos::RCP< const map_type > getColMap() const
Returns the Map that describes the column distribution in this matrix.
Definition: Ifpack2_LocalFilter_def.hpp:254
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:592
virtual bool hasColMap() const
Whether this matrix has a well-defined column Map.
Definition: Ifpack2_LocalFilter_def.hpp:400