Ifpack2 Templated Preconditioning Package  Version 1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends
Ifpack2_TriDiContainer_def.hpp
00001 /*@HEADER
00002 // ***********************************************************************
00003 //
00004 //       Ifpack2: Tempated Object-Oriented Algebraic Preconditioner Package
00005 //                 Copyright (2009) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ***********************************************************************
00040 //@HEADER
00041 */
00042 
00043 #ifndef IFPACK2_DENSECONTAINER_DEF_HPP
00044 #define IFPACK2_DENSECONTAINER_DEF_HPP
00045 
00046 #include "Ifpack2_TriDiContainer_decl.hpp"
00047 #include "Teuchos_LAPACK.hpp"
00048 
00049 #ifdef HAVE_MPI
00050 #  include <mpi.h>
00051 #  include "Teuchos_DefaultMpiComm.hpp"
00052 #else
00053 #  include "Teuchos_DefaultSerialComm.hpp"
00054 #endif // HAVE_MPI
00055 
00056 
00057 namespace Ifpack2 {
00058 
00059 //==============================================================================
00060 template<class MatrixType, class LocalScalarType>
00061 TriDiContainer<MatrixType, LocalScalarType>::
00062 TriDiContainer (const Teuchos::RCP<const row_matrix_type>& matrix,
00063                 const Teuchos::ArrayView<const local_ordinal_type>& localRows) :
00064   Container<MatrixType> (matrix, localRows),
00065   numRows_ (localRows.size ()),
00066   diagBlock_ (numRows_, numRows_),
00067   ipiv_ (numRows_, 0)
00068 {
00069   using Teuchos::Array;
00070   using Teuchos::ArrayView;
00071   using Teuchos::RCP;
00072   using Teuchos::rcp;
00073   using Teuchos::toString;
00074   typedef Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
00075   typedef typename ArrayView<const local_ordinal_type>::size_type size_type;
00076   TEUCHOS_TEST_FOR_EXCEPTION(
00077     ! matrix->hasColMap (), std::invalid_argument, "Ifpack2::TriDiContainer: "
00078     "The constructor's input matrix must have a column Map.");
00079 
00080   // Check whether the input set of local row indices is correct.
00081   const map_type& rowMap = * (matrix->getRowMap ());
00082   const size_type numRows = localRows.size ();
00083   bool rowIndicesValid = true;
00084   Array<local_ordinal_type> invalidLocalRowIndices;
00085   for (size_type i = 0; i < numRows; ++i) {
00086     if (! rowMap.isNodeLocalElement (localRows[i])) {
00087       rowIndicesValid = false;
00088       invalidLocalRowIndices.push_back (localRows[i]);
00089       break;
00090     }
00091   }
00092   TEUCHOS_TEST_FOR_EXCEPTION(
00093     ! rowIndicesValid, std::invalid_argument, "Ifpack2::TriDiContainer: "
00094     "On process " << rowMap.getComm ()->getRank () << " of "
00095     << rowMap.getComm ()->getSize () << ", in the given set of local row "
00096     "indices localRows = " << toString (localRows) << ", the following "
00097     "entries are not valid local row indices on the calling process: "
00098     << toString (invalidLocalRowIndices) << ".");
00099 
00100 #ifdef HAVE_MPI
00101   RCP<const Teuchos::Comm<int> > localComm =
00102     rcp (new Teuchos::MpiComm<int> (MPI_COMM_SELF));
00103 #else
00104   RCP<const Teuchos::Comm<int> > localComm =
00105     rcp (new Teuchos::SerialComm<int> ());
00106 #endif // HAVE_MPI
00107 
00108   // FIXME (mfh 25 Aug 2013) What if the matrix's row Map has a
00109   // different index base than zero?
00110   const global_ordinal_type indexBase = 0;
00111   localMap_ = rcp (new map_type (numRows_, indexBase, localComm));
00112 }
00113 
00114 //==============================================================================
00115 template<class MatrixType, class LocalScalarType>
00116 TriDiContainer<MatrixType, LocalScalarType>::~TriDiContainer()
00117 {}
00118 
00119 //==============================================================================
00120 template<class MatrixType, class LocalScalarType>
00121 size_t TriDiContainer<MatrixType, LocalScalarType>::getNumRows () const
00122 {
00123   return numRows_;
00124 }
00125 
00126 //==============================================================================
00127 template<class MatrixType, class LocalScalarType>
00128 bool TriDiContainer<MatrixType, LocalScalarType>::isInitialized () const
00129 {
00130   return IsInitialized_;
00131 }
00132 
00133 //==============================================================================
00134 template<class MatrixType, class LocalScalarType>
00135 bool TriDiContainer<MatrixType, LocalScalarType>::isComputed() const
00136 {
00137   return IsComputed_;
00138 }
00139 
00140 //==============================================================================
00141 template<class MatrixType, class LocalScalarType>
00142 void TriDiContainer<MatrixType, LocalScalarType>::
00143 setParameters (const Teuchos::ParameterList& List)
00144 {
00145   (void) List; // the solver doesn't currently take any parameters
00146 }
00147 
00148 //==============================================================================
00149 template<class MatrixType, class LocalScalarType>
00150 void TriDiContainer<MatrixType, LocalScalarType>::initialize ()
00151 {
00152   using Teuchos::null;
00153   using Teuchos::rcp;
00154 
00155   // We assume that if you called this method, you intend to recompute
00156   // everything.
00157   IsInitialized_ = false;
00158   IsComputed_ = false;
00159 
00160   // Fill the diagonal block and LU permutation array with zeros.
00161   diagBlock_.putScalar (Teuchos::ScalarTraits<local_scalar_type>::zero ());
00162   std::fill (ipiv_.begin (), ipiv_.end (), 0);
00163 
00164   IsInitialized_ = true;
00165 }
00166 
00167 //==============================================================================
00168 template<class MatrixType, class LocalScalarType>
00169 void TriDiContainer<MatrixType, LocalScalarType>::compute ()
00170 {
00171   TEUCHOS_TEST_FOR_EXCEPTION(
00172     static_cast<size_t> (ipiv_.size ()) != numRows_, std::logic_error,
00173     "Ifpack2::TriDiContainer::compute: ipiv_ array has the wrong size.  "
00174     "Please report this bug to the Ifpack2 developers.");
00175 
00176   IsComputed_ = false;
00177   if (! this->isInitialized ()) {
00178     this->initialize ();
00179   }
00180 
00181   // Extract the submatrix.
00182   extract (this->getMatrix ()); // extract the submatrix
00183   factor (); // factor the submatrix
00184 
00185   IsComputed_ = true;
00186 }
00187 
00188 template<class MatrixType, class LocalScalarType>
00189 void TriDiContainer<MatrixType, LocalScalarType>::factor ()
00190 {
00191   Teuchos::LAPACK<int, local_scalar_type> lapack;
00192   int INFO = 0;
00193   lapack.GTTRF (diagBlock_.numRowsCols (),
00194     diagBlock_.DL(),
00195     diagBlock_.D(),
00196     diagBlock_.DU(),
00197     diagBlock_.DU2(),
00198                 ipiv_.getRawPtr (), &INFO);
00199   // INFO < 0 is a bug.
00200   TEUCHOS_TEST_FOR_EXCEPTION(
00201     INFO < 0, std::logic_error, "Ifpack2::TriDiContainer::factor: "
00202     "LAPACK's _GTTRF (LU factorization with partial pivoting) was called "
00203     "incorrectly.  INFO = " << INFO << " < 0.  "
00204     "Please report this bug to the Ifpack2 developers.");
00205   // INFO > 0 means the matrix is singular.  This is probably an issue
00206   // either with the choice of rows the rows we extracted, or with the
00207   // input matrix itself.
00208   TEUCHOS_TEST_FOR_EXCEPTION(
00209     INFO > 0, std::runtime_error, "Ifpack2::TriDiContainer::factor: "
00210     "LAPACK's _GTTRF (LU factorization with partial pivoting) reports that the "
00211     "computed U factor is exactly singular.  U(" << INFO << "," << INFO << ") "
00212     "(one-based index i) is exactly zero.  This probably means that the input "
00213     "matrix has a singular diagonal block.");
00214 }
00215 
00216 //==============================================================================
00217 template<class MatrixType, class LocalScalarType>
00218 void TriDiContainer<MatrixType, LocalScalarType>::
00219 applyImpl (const local_mv_type& X,
00220            local_mv_type& Y,
00221            Teuchos::ETransp mode,
00222            LocalScalarType alpha,
00223            LocalScalarType beta) const
00224 {
00225   using Teuchos::ArrayRCP;
00226   using Teuchos::RCP;
00227   using Teuchos::rcp;
00228   using Teuchos::rcpFromRef;
00229 
00230   TEUCHOS_TEST_FOR_EXCEPTION(
00231     X.getLocalLength () != Y.getLocalLength (),
00232     std::logic_error, "Ifpack2::TriDiContainer::applyImpl: X and Y have "
00233     "incompatible dimensions (" << X.getLocalLength () << " resp. "
00234     << Y.getLocalLength () << ").  Please report this bug to "
00235     "the Ifpack2 developers.");
00236   TEUCHOS_TEST_FOR_EXCEPTION(
00237     localMap_->getNodeNumElements () != X.getLocalLength (),
00238     std::logic_error, "Ifpack2::TriDiContainer::applyImpl: The inverse "
00239     "operator and X have incompatible dimensions (" <<
00240     localMap_->getNodeNumElements () << " resp. "
00241     << X.getLocalLength () << ").  Please report this bug to "
00242     "the Ifpack2 developers.");
00243   TEUCHOS_TEST_FOR_EXCEPTION(
00244     localMap_->getNodeNumElements () != Y.getLocalLength (),
00245     std::logic_error, "Ifpack2::TriDiContainer::applyImpl: The inverse "
00246     "operator and Y have incompatible dimensions (" <<
00247     localMap_->getNodeNumElements () << " resp. "
00248     << Y.getLocalLength () << ").  Please report this bug to "
00249     "the Ifpack2 developers.");
00250   TEUCHOS_TEST_FOR_EXCEPTION(
00251     X.getLocalLength () != static_cast<size_t> (diagBlock_.numRowsCols()),
00252     std::logic_error, "Ifpack2::TriDiContainer::applyImpl: The input "
00253     "multivector X has incompatible dimensions from those of the "
00254     "inverse operator (" << X.getLocalLength () << " vs. "
00255     << (mode == Teuchos::NO_TRANS ? diagBlock_.numRowsCols () : diagBlock_.numRowsCols())
00256     << ").  Please report this bug to the Ifpack2 developers.");
00257   TEUCHOS_TEST_FOR_EXCEPTION(
00258     X.getLocalLength () != static_cast<size_t> (diagBlock_.numRowsCols()),
00259     std::logic_error, "Ifpack2::TriDiContainer::applyImpl: The output "
00260     "multivector Y has incompatible dimensions from those of the "
00261     "inverse operator (" << Y.getLocalLength () << " vs. "
00262     << (mode == Teuchos::NO_TRANS ? diagBlock_.numRowsCols() : diagBlock_.numRowsCols ())
00263     << ").  Please report this bug to the Ifpack2 developers.");
00264 
00265   typedef Teuchos::ScalarTraits<local_scalar_type> STS;
00266   const int numVecs = static_cast<int> (X.getNumVectors ());
00267   if (alpha == STS::zero ()) { // don't need to solve the linear system
00268     if (beta == STS::zero ()) {
00269       // Use BLAS AXPY semantics for beta == 0: overwrite, clobbering
00270       // any Inf or NaN values in Y (rather than multiplying them by
00271       // zero, resulting in NaN values).
00272       Y.putScalar (STS::zero ());
00273     }
00274     else { // beta != 0
00275       Y.scale (beta);
00276     }
00277   }
00278   else { // alpha != 0; must solve the linear system
00279     Teuchos::LAPACK<int, local_scalar_type> lapack;
00280     // If beta is nonzero or Y is not constant stride, we have to use
00281     // a temporary output multivector.  It gets a copy of X, since
00282     // GETRS overwrites its (multi)vector input with its output.
00283     RCP<local_mv_type> Y_tmp;
00284     if (beta == STS::zero () ){
00285       Y = X;
00286       Y_tmp = rcpFromRef (Y);
00287     }
00288     else {
00289       Y_tmp = rcp (new local_mv_type (X)); // constructor copies X
00290     }
00291     const int Y_stride = static_cast<int> (Y_tmp->getStride ());
00292     ArrayRCP<local_scalar_type> Y_view = Y_tmp->get1dViewNonConst ();
00293     local_scalar_type* const Y_ptr = Y_view.getRawPtr ();
00294 
00295     int INFO = 0;
00296     const char trans =
00297       (mode == Teuchos::CONJ_TRANS ? 'C' : (mode == Teuchos::TRANS ? 'T' : 'N'));
00298     lapack.GTTRS (trans, diagBlock_.numRowsCols(),numVecs,
00299       diagBlock_.DL(),
00300       diagBlock_.D(),
00301       diagBlock_.DU(),
00302       diagBlock_.DU2(),
00303                   ipiv_.getRawPtr (), Y_ptr, Y_stride, &INFO);
00304     TEUCHOS_TEST_FOR_EXCEPTION(
00305       INFO != 0, std::runtime_error, "Ifpack2::TriDiContainer::applyImpl: "
00306       "LAPACK's _GETRS (solve using LU factorization with partial pivoting) "
00307       "failed with INFO = " << INFO << " != 0.");
00308 
00309     if (beta != STS::zero ()) {
00310       Y.update (alpha, *Y_tmp, beta);
00311     }
00312     else if (! Y.isConstantStride ()) {
00313       Y = *Y_tmp;
00314     }
00315   }
00316 }
00317 
00318 //==============================================================================
00319 template<class MatrixType, class LocalScalarType>
00320 void TriDiContainer<MatrixType, LocalScalarType>::
00321 apply (const Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type>& X,
00322        Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type>& Y,
00323        Teuchos::ETransp mode,
00324        scalar_type alpha,
00325        scalar_type beta) const
00326 {
00327   using Teuchos::ArrayView;
00328   using Teuchos::as;
00329   using Teuchos::RCP;
00330   using Teuchos::rcp;
00331 
00332   // The local operator might have a different Scalar type than
00333   // MatrixType.  This means that we might have to convert X and Y to
00334   // the Tpetra::MultiVector specialization that the local operator
00335   // wants.  This class' X_ and Y_ internal fields are of the right
00336   // type for the local operator, so we can use those as targets.
00337 
00338   // Tpetra::MultiVector specialization corresponding to MatrixType.
00339   typedef Tpetra::MultiVector<scalar_type, local_ordinal_type,
00340                               global_ordinal_type, node_type> global_mv_type;
00341   Details::MultiVectorLocalGatherScatter<global_mv_type, local_mv_type> mvgs;
00342   const size_t numVecs = X.getNumVectors ();
00343 
00344   TEUCHOS_TEST_FOR_EXCEPTION(
00345     ! IsComputed_, std::runtime_error, "Ifpack2::TriDiContainer::apply: "
00346     "You must have called the compute() method before you may call apply().  "
00347     "You may call the apply() method as many times as you want after calling "
00348     "compute() once, but you must have called compute() at least once.");
00349   TEUCHOS_TEST_FOR_EXCEPTION(
00350     numVecs != Y.getNumVectors (), std::runtime_error,
00351     "Ifpack2::TriDiContainer::apply: X and Y have different numbers of "
00352     "vectors.  X has " << X.getNumVectors ()
00353     << ", but Y has " << X.getNumVectors () << ".");
00354 
00355   if (numVecs == 0) {
00356     return; // done! nothing to do
00357   }
00358 
00359   // The local operator works on a permuted subset of the local parts
00360   // of X and Y.  The subset and permutation are defined by the index
00361   // array returned by getLocalRows().  If the permutation is trivial
00362   // and the subset is exactly equal to the local indices, then we
00363   // could use the local parts of X and Y exactly, without needing to
00364   // permute.  Otherwise, we have to use temporary storage to permute
00365   // X and Y.  For now, we always use temporary storage.
00366   //
00367   // Create temporary permuted versions of the input and output.
00368   // (Re)allocate X_ and/or Y_ only if necessary.  We'll use them to
00369   // store the permuted versions of X resp. Y.  Note that X_local has
00370   // the domain Map of the operator, which may be a permuted subset of
00371   // the local Map corresponding to X.getMap().  Similarly, Y_local
00372   // has the range Map of the operator, which may be a permuted subset
00373   // of the local Map corresponding to Y.getMap().  numRows_ here
00374   // gives the number of rows in the row Map of the local Inverse_
00375   // operator.
00376   //
00377   // FIXME (mfh 20 Aug 2013) There might be an implicit assumption
00378   // here that the row Map and the range Map of that operator are
00379   // the same.
00380   //
00381   // FIXME (mfh 20 Aug 2013) This "local permutation" functionality
00382   // really belongs in Tpetra.
00383 
00384   if (X_.is_null ()) {
00385     X_ = rcp (new local_mv_type (localMap_, numVecs));
00386   }
00387   RCP<local_mv_type> X_local = X_;
00388   TEUCHOS_TEST_FOR_EXCEPTION(
00389     X_local->getLocalLength () != numRows_, std::logic_error,
00390     "Ifpack2::TriDiContainer::apply: "
00391     "X_local has length " << X_local->getLocalLength () << ", which does "
00392     "not match numRows_ = " << numRows_ << ".  Please report this bug to "
00393     "the Ifpack2 developers.");
00394   ArrayView<const local_ordinal_type> localRows = this->getLocalRows ();
00395   mvgs.gather (*X_local, X, localRows);
00396 
00397   // We must gather the contents of the output multivector Y even on
00398   // input to applyImpl(), since the inverse operator might use it as
00399   // an initial guess for a linear solve.  We have no way of knowing
00400   // whether it does or does not.
00401 
00402   if (Y_.is_null ()) {
00403     Y_ = rcp (new local_mv_type (localMap_, numVecs));
00404   }
00405   RCP<local_mv_type> Y_local = Y_;
00406   TEUCHOS_TEST_FOR_EXCEPTION(
00407     Y_local->getLocalLength () != numRows_, std::logic_error,
00408     "Ifpack2::TriDiContainer::apply: "
00409     "Y_local has length " << X_local->getLocalLength () << ", which does "
00410     "not match numRows_ = " << numRows_ << ".  Please report this bug to "
00411     "the Ifpack2 developers.");
00412   mvgs.gather (*Y_local, Y, localRows);
00413 
00414   // Apply the local operator:
00415   // Y_local := beta*Y_local + alpha*M^{-1}*X_local
00416   this->applyImpl (*X_local, *Y_local, mode, as<local_scalar_type> (alpha),
00417                    as<local_scalar_type> (beta));
00418 
00419   // Scatter the permuted subset output vector Y_local back into the
00420   // original output multivector Y.
00421   mvgs.scatter (Y, *Y_local, localRows);
00422 }
00423 
00424 //==============================================================================
00425 template<class MatrixType, class LocalScalarType>
00426 void TriDiContainer<MatrixType,LocalScalarType>::
00427 weightedApply (const Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type>& X,
00428                Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type>& Y,
00429                const Tpetra::Vector<scalar_type,local_ordinal_type,global_ordinal_type,node_type>& D,
00430                Teuchos::ETransp mode,
00431                scalar_type alpha,
00432                scalar_type beta) const
00433 {
00434   using Teuchos::ArrayRCP;
00435   using Teuchos::ArrayView;
00436   using Teuchos::Range1D;
00437   using Teuchos::RCP;
00438   using Teuchos::rcp;
00439   using Teuchos::rcp_const_cast;
00440   using std::cerr;
00441   using std::endl;
00442   typedef Teuchos::ScalarTraits<scalar_type> STS;
00443 
00444   // The local operator template parameter might have a different
00445   // Scalar type than MatrixType.  This means that we might have to
00446   // convert X and Y to the Tpetra::MultiVector specialization that
00447   // the local operator wants.  This class' X_ and Y_ internal fields
00448   // are of the right type for the local operator, so we can use those
00449   // as targets.
00450 
00451   // Tpetra::MultiVector specialization corresponding to the global operator.
00452   typedef Tpetra::MultiVector<scalar_type, local_ordinal_type,
00453                               global_ordinal_type, node_type> global_mv_type;
00454   // Tpetra::Vector specialization corresponding to the local
00455   // operator.  We will use this for the subset permutation of the
00456   // diagonal scaling D.
00457   typedef Tpetra::Vector<local_scalar_type, local_ordinal_type,
00458                          global_ordinal_type, node_type> local_vec_type;
00459 
00460   Details::MultiVectorLocalGatherScatter<global_mv_type, local_mv_type> mvgs;
00461   const size_t numVecs = X.getNumVectors ();
00462 
00463   TEUCHOS_TEST_FOR_EXCEPTION(
00464     ! IsComputed_, std::runtime_error, "Ifpack2::TriDiContainer::"
00465     "weightedApply: You must have called the compute() method before you may "
00466     "call apply().  You may call the apply() method as many times as you want "
00467     "after calling compute() once, but you must have called compute() at least "
00468     "once.");
00469   TEUCHOS_TEST_FOR_EXCEPTION(
00470     numVecs != Y.getNumVectors (), std::runtime_error,
00471     "Ifpack2::TriDiContainer::weightedApply: X and Y have different numbers "
00472     "of vectors.  X has " << X.getNumVectors () << ", but Y has "
00473     << X.getNumVectors () << ".");
00474 
00475   if (numVecs == 0) {
00476     return; // done! nothing to do
00477   }
00478 
00479   // The local operator works on a permuted subset of the local parts
00480   // of X and Y.  The subset and permutation are defined by the index
00481   // array returned by getLocalRows().  If the permutation is trivial
00482   // and the subset is exactly equal to the local indices, then we
00483   // could use the local parts of X and Y exactly, without needing to
00484   // permute.  Otherwise, we have to use temporary storage to permute
00485   // X and Y.  For now, we always use temporary storage.
00486   //
00487   // Create temporary permuted versions of the input and output.
00488   // (Re)allocate X_ and/or Y_ only if necessary.  We'll use them to
00489   // store the permuted versions of X resp. Y.  Note that X_local has
00490   // the domain Map of the operator, which may be a permuted subset of
00491   // the local Map corresponding to X.getMap().  Similarly, Y_local
00492   // has the range Map of the operator, which may be a permuted subset
00493   // of the local Map corresponding to Y.getMap().  numRows_ here
00494   // gives the number of rows in the row Map of the local operator.
00495   //
00496   // FIXME (mfh 20 Aug 2013) There might be an implicit assumption
00497   // here that the row Map and the range Map of that operator are
00498   // the same.
00499   //
00500   // FIXME (mfh 20 Aug 2013) This "local permutation" functionality
00501   // really belongs in Tpetra.
00502 
00503   if (X_.is_null ()) {
00504     X_ = rcp (new local_mv_type (localMap_, numVecs));
00505   }
00506   RCP<local_mv_type> X_local = X_;
00507   TEUCHOS_TEST_FOR_EXCEPTION(
00508     X_local->getLocalLength () != numRows_, std::logic_error,
00509     "Ifpack2::TriDiContainer::weightedApply: "
00510     "X_local has length " << X_local->getLocalLength () << ", which does "
00511     "not match numRows_ = " << numRows_ << ".  Please report this bug to "
00512     "the Ifpack2 developers.");
00513   ArrayView<const local_ordinal_type> localRows = this->getLocalRows ();
00514   mvgs.gather (*X_local, X, localRows);
00515 
00516   // We must gather the output multivector Y even on input to
00517   // applyImpl(), since the local operator might use it as an initial
00518   // guess for a linear solve.  We have no way of knowing whether it
00519   // does or does not.
00520 
00521   if (Y_.is_null ()) {
00522     Y_ = rcp (new local_mv_type (localMap_, numVecs));
00523   }
00524   RCP<local_mv_type> Y_local = Y_;
00525   TEUCHOS_TEST_FOR_EXCEPTION(
00526     Y_local->getLocalLength () != numRows_, std::logic_error,
00527     "Ifpack2::TriDiContainer::weightedApply: "
00528     "Y_local has length " << X_local->getLocalLength () << ", which does "
00529     "not match numRows_ = " << numRows_ << ".  Please report this bug to "
00530     "the Ifpack2 developers.");
00531   mvgs.gather (*Y_local, Y, localRows);
00532 
00533   // Apply the diagonal scaling D to the input X.  It's our choice
00534   // whether the result has the original input Map of X, or the
00535   // permuted subset Map of X_local.  If the latter, we also need to
00536   // gather D into the permuted subset Map.  We choose the latter, to
00537   // save memory and computation.  Thus, we do the following:
00538   //
00539   // 1. Gather D into a temporary vector D_local.
00540   // 2. Create a temporary X_scaled to hold diag(D_local) * X_local.
00541   // 3. Compute X_scaled := diag(D_loca) * X_local.
00542 
00543   RCP<local_vec_type> D_local = rcp (new local_vec_type (localMap_));
00544   TEUCHOS_TEST_FOR_EXCEPTION(
00545     D_local->getLocalLength () != numRows_, std::logic_error,
00546     "Ifpack2::TriDiContainer::weightedApply: "
00547     "D_local has length " << X_local->getLocalLength () << ", which does "
00548     "not match numRows_ = " << numRows_ << ".  Please report this bug to "
00549     "the Ifpack2 developers.");
00550   mvgs.gather (*D_local, D, localRows);
00551   RCP<local_mv_type> X_scaled = rcp (new local_mv_type (localMap_, numVecs));
00552   X_scaled->elementWiseMultiply (STS::one (), *D_local, *X_local, STS::zero ());
00553 
00554   // Y_temp will hold the result of M^{-1}*X_scaled.  If beta == 0, we
00555   // can write the result of Inverse_->apply() directly to Y_local, so
00556   // Y_temp may alias Y_local.  Otherwise, if beta != 0, we need
00557   // temporary storage for M^{-1}*X_scaled, so Y_temp must be
00558   // different than Y_local.
00559   RCP<local_mv_type> Y_temp;
00560   if (beta == STS::zero ()) {
00561     Y_temp = Y_local;
00562   } else {
00563     Y_temp = rcp (new local_mv_type (localMap_, numVecs));
00564   }
00565 
00566   // Apply the local operator: Y_temp := M^{-1} * X_scaled
00567   applyImpl (*X_scaled, *Y_temp, mode, STS::one (), STS::zero ());
00568   // Y_local := beta * Y_local + alpha * diag(D_local) * Y_temp.
00569   //
00570   // Note that we still use the permuted subset scaling D_local here,
00571   // because Y_temp has the same permuted subset Map.  That's good, in
00572   // fact, because it's a subset: less data to read and multiply.
00573   Y_local->elementWiseMultiply (alpha, *D_local, *Y_temp, beta);
00574 
00575   // Copy the permuted subset output vector Y_local into the original
00576   // output multivector Y.
00577   mvgs.scatter (Y, *Y_local, localRows);
00578 }
00579 
00580 //==============================================================================
00581 template<class MatrixType, class LocalScalarType>
00582 std::ostream& TriDiContainer<MatrixType,LocalScalarType>::print(std::ostream& os) const
00583 {
00584   Teuchos::FancyOStream fos(Teuchos::rcp(&os,false));
00585   fos.setOutputToRootOnly(0);
00586   describe(fos);
00587   return(os);
00588 }
00589 
00590 //==============================================================================
00591 template<class MatrixType, class LocalScalarType>
00592 std::string TriDiContainer<MatrixType,LocalScalarType>::description() const
00593 {
00594   std::ostringstream oss;
00595   oss << Teuchos::Describable::description();
00596   if (isInitialized()) {
00597     if (isComputed()) {
00598       oss << "{status = initialized, computed";
00599     }
00600     else {
00601       oss << "{status = initialized, not computed";
00602     }
00603   }
00604   else {
00605     oss << "{status = not initialized, not computed";
00606   }
00607 
00608   oss << "}";
00609   return oss.str();
00610 }
00611 
00612 //==============================================================================
00613 template<class MatrixType, class LocalScalarType>
00614 void TriDiContainer<MatrixType,LocalScalarType>::describe(Teuchos::FancyOStream &os, const Teuchos::EVerbosityLevel verbLevel) const
00615 {
00616   using std::endl;
00617   if(verbLevel==Teuchos::VERB_NONE) return;
00618   os << "================================================================================" << endl;
00619   os << "Ifpack2::TriDiContainer" << endl;
00620   os << "Number of rows          = " << numRows_ << endl;
00621   os << "isInitialized()         = " << IsInitialized_ << endl;
00622   os << "isComputed()            = " << IsComputed_ << endl;
00623   os << "================================================================================" << endl;
00624   os << endl;
00625 }
00626 
00627 //==============================================================================
00628 template<class MatrixType, class LocalScalarType>
00629 void TriDiContainer<MatrixType,LocalScalarType>::
00630 extract (const Teuchos::RCP<const row_matrix_type>& globalMatrix)
00631 {
00632   using Teuchos::Array;
00633   using Teuchos::ArrayView;
00634   using Teuchos::toString;
00635   typedef local_ordinal_type LO;
00636   typedef global_ordinal_type GO;
00637   typedef Tpetra::Map<LO, GO, node_type> map_type;
00638   const size_t inputMatrixNumRows = globalMatrix->getNodeNumRows ();
00639   // We only use the rank of the calling process and the number of MPI
00640   // processes for generating error messages.  Extraction itself is
00641   // entirely local to each participating MPI process.
00642   const int myRank = globalMatrix->getRowMap ()->getComm ()->getRank ();
00643   const int numProcs = globalMatrix->getRowMap ()->getComm ()->getSize ();
00644 
00645   // Sanity check that the local row indices to extract fall within
00646   // the valid range of local row indices for the input matrix.
00647   ArrayView<const LO> localRows = this->getLocalRows ();
00648   for (size_t j = 0; j < numRows_; ++j) {
00649     TEUCHOS_TEST_FOR_EXCEPTION(
00650       localRows[j] < 0 ||
00651       static_cast<size_t> (localRows[j]) >= inputMatrixNumRows,
00652       std::runtime_error, "Ifpack2::TriDiContainer::extract: On process " <<
00653       myRank << " of " << numProcs << ", localRows[j=" << j << "] = " <<
00654       localRows[j] << ", which is out of the valid range of local row indices "
00655       "indices [0, " << (inputMatrixNumRows - 1) << "] for the input matrix.");
00656   }
00657 
00658   // Convert the local row indices we want into local column indices.
00659   // For every local row ii_local = localRows[i] we take, we also want
00660   // to take the corresponding column.  To find the corresponding
00661   // column, we use the row Map to convert the local row index
00662   // ii_local into a global index ii_global, and then use the column
00663   // Map to convert ii_global into a local column index jj_local.  If
00664   // the input matrix doesn't have a column Map, we need to be using
00665   // global indices anyway...
00666 
00667   // We use the domain Map to exclude off-process global entries.
00668   const map_type& globalRowMap = * (globalMatrix->getRowMap ());
00669   const map_type& globalColMap = * (globalMatrix->getColMap ());
00670   const map_type& globalDomMap = * (globalMatrix->getDomainMap ());
00671 
00672   bool rowIndsValid = true;
00673   bool colIndsValid = true;
00674   Array<LO> localCols (numRows_);
00675   // For error messages, collect the sets of invalid row indices and
00676   // invalid column indices.  They are otherwise not useful.
00677   Array<LO> invalidLocalRowInds;
00678   Array<GO> invalidGlobalColInds;
00679   for (size_t i = 0; i < numRows_; ++i) {
00680     // ii_local is the (local) row index we want to look up.
00681     const LO ii_local = localRows[i];
00682     // Find the global index jj_global corresponding to ii_local.
00683     // Global indices are the same (rather, are required to be the
00684     // same) in all three Maps, which is why we use jj (suggesting a
00685     // column index, which is how we will use it below).
00686     const GO jj_global = globalRowMap.getGlobalElement (ii_local);
00687     if (jj_global == Teuchos::OrdinalTraits<GO>::invalid ()) {
00688       // If ii_local is not a local index in the row Map on the
00689       // calling process, that means localRows is incorrect.  We've
00690       // already checked for this in the constructor, but we might as
00691       // well check again here, since it's cheap to do so (just an
00692       // integer comparison, since we need jj_global anyway).
00693       rowIndsValid = false;
00694       invalidLocalRowInds.push_back (ii_local);
00695       break;
00696     }
00697     // Exclude "off-process" entries: that is, those in the column Map
00698     // on this process that are not in the domain Map on this process.
00699     if (globalDomMap.isNodeGlobalElement (jj_global)) {
00700       // jj_global is not an off-process entry.  Look up its local
00701       // index in the column Map; we want to extract this column index
00702       // from the input matrix.  If jj_global is _not_ in the column
00703       // Map on the calling process, that could mean that the column
00704       // in question is empty on this process.  That would be bad for
00705       // solving linear systems with the extract submatrix.  We could
00706       // solve the resulting singular linear systems in a minimum-norm
00707       // least-squares sense, but for now we simply raise an exception.
00708       const LO jj_local = globalColMap.getLocalElement (jj_global);
00709       if (jj_local == Teuchos::OrdinalTraits<local_ordinal_type>::invalid ()) {
00710         colIndsValid = false;
00711         invalidGlobalColInds.push_back (jj_global);
00712         break;
00713       }
00714       localCols[i] = jj_local;
00715     }
00716   }
00717   TEUCHOS_TEST_FOR_EXCEPTION(
00718     ! rowIndsValid, std::logic_error, "Ifpack2::TriDiContainer::extract: "
00719     "On process " << myRank << ", at least one row index in the set of local "
00720     "row indices given to the constructor is not a valid local row index in "
00721     "the input matrix's row Map on this process.  This should be impossible "
00722     "because the constructor checks for this case.  Here is the complete set "
00723     "of invalid local row indices: " << toString (invalidLocalRowInds) << ".  "
00724     "Please report this bug to the Ifpack2 developers.");
00725   TEUCHOS_TEST_FOR_EXCEPTION(
00726     ! colIndsValid, std::runtime_error, "Ifpack2::TriDiContainer::extract: "
00727     "On process " << myRank << ", "
00728     "At least one row index in the set of row indices given to the constructor "
00729     "does not have a corresponding column index in the input matrix's column "
00730     "Map.  This probably means that the column(s) in question is/are empty on "
00731     "this process, which would make the submatrix to extract structurally "
00732     "singular.  Here is the compete set of invalid global column indices: "
00733     << toString (invalidGlobalColInds) << ".");
00734 
00735   diagBlock_.putScalar (Teuchos::ScalarTraits<local_scalar_type>::zero ());
00736 
00737   const size_t maxNumEntriesInRow = globalMatrix->getNodeMaxNumRowEntries ();
00738   Array<scalar_type> val (maxNumEntriesInRow);
00739   Array<local_ordinal_type> ind (maxNumEntriesInRow);
00740 
00741   const local_ordinal_type INVALID =
00742     Teuchos::OrdinalTraits<local_ordinal_type>::invalid ();
00743   for (size_t i = 0; i < numRows_; ++i) {
00744     const local_ordinal_type localRow = localRows[i];
00745     size_t numEntries;
00746     globalMatrix->getLocalRowCopy (localRow, ind (), val (), numEntries);
00747 
00748     for (size_t k = 0; k < numEntries; ++k) {
00749       const local_ordinal_type localCol = ind[k];
00750 
00751       // Skip off-process elements
00752       //
00753       // FIXME (mfh 24 Aug 2013) This assumes the following:
00754       //
00755       // 1. The column and row Maps begin with the same set of
00756       //    on-process entries, in the same order.  That is,
00757       //    on-process row and column indices are the same.
00758       // 2. All off-process indices in the column Map of the input
00759       //    matrix occur after that initial set.
00760       if (localCol >= 0 && static_cast<size_t> (localCol) < inputMatrixNumRows) {
00761         // for local column IDs, look for each ID in the list
00762         // of columns hosted by this object
00763         local_ordinal_type jj = INVALID;
00764         for (size_t kk = 0; kk < numRows_; ++kk) {
00765           if (localRows[kk] == localCol) {
00766             jj = kk;
00767           }
00768         }
00769         if (jj != INVALID) {
00770           diagBlock_ (i, jj) += val[k]; // ???
00771         }
00772       }
00773     }
00774   }
00775 }
00776 
00777 } // namespace Ifpack2
00778 
00779 #define IFPACK2_TRIDICONTAINER_INSTANT(S,LO,GO,N) \
00780   template class Ifpack2::TriDiContainer< Tpetra::CrsMatrix<S, LO, GO, N>, S >;
00781 
00782 #endif // IFPACK2_SPARSECONTAINER_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends