Ifpack2 Templated Preconditioning Package  Version 1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends
Ifpack2_Diagonal_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_DIAGONAL_DEF_HPP
00044 #define IFPACK2_DIAGONAL_DEF_HPP
00045 
00046 #include "Ifpack2_Diagonal_decl.hpp"
00047 #include "Tpetra_CrsMatrix_def.hpp"
00048 #include "Ifpack2_Condest.hpp"
00049 
00050 namespace Ifpack2 {
00051 
00052 template<class MatrixType>
00053 Diagonal<MatrixType>::Diagonal (const Teuchos::RCP<const row_matrix_type>& A) :
00054   matrix_ (A),
00055   initializeTime_ (0.0),
00056   computeTime_ (0.0),
00057   applyTime_ (0.0),
00058   numInitialize_ (0),
00059   numCompute_ (0),
00060   numApply_ (0),
00061   condEst_ (-Teuchos::ScalarTraits<magnitude_type>::one ()),
00062   isInitialized_ (false),
00063   isComputed_ (false)
00064 {}
00065 
00066 template<class MatrixType>
00067 Diagonal<MatrixType>::Diagonal (const Teuchos::RCP<const crs_matrix_type>& A) :
00068   matrix_ (A),
00069   initializeTime_ (0.0),
00070   computeTime_ (0.0),
00071   applyTime_ (0.0),
00072   numInitialize_ (0),
00073   numCompute_ (0),
00074   numApply_ (0),
00075   condEst_ (-Teuchos::ScalarTraits<magnitude_type>::one ()),
00076   isInitialized_ (false),
00077   isComputed_ (false)
00078 {}
00079 
00080 template<class MatrixType>
00081 Diagonal<MatrixType>::Diagonal (const Teuchos::RCP<const vector_type>& diag) :
00082   userInverseDiag_ (diag),
00083   inverseDiag_ (diag),
00084   initializeTime_ (0.0),
00085   computeTime_ (0.0),
00086   applyTime_ (0.0),
00087   numInitialize_ (0),
00088   numCompute_ (0),
00089   numApply_ (0),
00090   condEst_ (-Teuchos::ScalarTraits<magnitude_type>::one ()),
00091   isInitialized_ (false),
00092   isComputed_ (false)
00093 {}
00094 
00095 template<class MatrixType>
00096 Diagonal<MatrixType>::~Diagonal ()
00097 {}
00098 
00099 template<class MatrixType>
00100 Teuchos::RCP<const typename Diagonal<MatrixType>::map_type>
00101 Diagonal<MatrixType>::getDomainMap () const
00102 {
00103   if (matrix_.is_null ()) {
00104     if (userInverseDiag_.is_null ()) {
00105       TEUCHOS_TEST_FOR_EXCEPTION(
00106         true, std::runtime_error, "Ifpack2::Diagonal::getDomainMap: "
00107         "The input matrix A is null, and you did not provide a vector of "
00108         "inverse diagonal entries.  Please call setMatrix() with a nonnull "
00109         "input matrix before calling this method.");
00110     } else {
00111       return userInverseDiag_->getMap ();
00112     }
00113   } else {
00114     return matrix_->getDomainMap ();
00115   }
00116 }
00117 
00118 template<class MatrixType>
00119 Teuchos::RCP<const typename Diagonal<MatrixType>::map_type>
00120 Diagonal<MatrixType>::getRangeMap () const
00121 {
00122   if (matrix_.is_null ()) {
00123     if (userInverseDiag_.is_null ()) {
00124       TEUCHOS_TEST_FOR_EXCEPTION(
00125         true, std::runtime_error, "Ifpack2::Diagonal::getRangeMap: "
00126         "The input matrix A is null, and you did not provide a vector of "
00127         "inverse diagonal entries.  Please call setMatrix() with a nonnull "
00128         "input matrix before calling this method.");
00129     } else {
00130       return userInverseDiag_->getMap ();
00131     }
00132   } else {
00133     return matrix_->getRangeMap ();
00134   }
00135 }
00136 
00137 template<class MatrixType>
00138 void Diagonal<MatrixType>::
00139 setParameters (const Teuchos::ParameterList& /*params*/)
00140 {}
00141 
00142 template<class MatrixType>
00143 void Diagonal<MatrixType>::reset ()
00144 {
00145   inverseDiag_ = Teuchos::null;
00146   offsets_ = Teuchos::null;
00147   condEst_ = -Teuchos::ScalarTraits<magnitude_type>::one ();
00148   isInitialized_ = false;
00149   isComputed_ = false;
00150 }
00151 
00152 template<class MatrixType>
00153 void Diagonal<MatrixType>::
00154 setMatrix (const Teuchos::RCP<const row_matrix_type>& A)
00155 {
00156   if (A.getRawPtr () != matrix_.getRawPtr ()) { // it's a different matrix
00157     reset ();
00158     matrix_ = A;
00159   }
00160 }
00161 
00162 template<class MatrixType>
00163 void Diagonal<MatrixType>::initialize ()
00164 {
00165   // Either the matrix to precondition must be nonnull, or the user
00166   // must have provided a Vector of diagonal entries.
00167   TEUCHOS_TEST_FOR_EXCEPTION(
00168     matrix_.is_null () && userInverseDiag_.is_null (), std::runtime_error,
00169     "Ifpack2::Diagonal::initialize: The matrix to precondition is null, "
00170     "and you did not provide a Tpetra::Vector of diagonal entries.  "
00171     "Please call setMatrix() with a nonnull input before calling this method.");
00172 
00173   // If the user did provide an input matrix, then that takes
00174   // precedence over the vector of inverse diagonal entries, if they
00175   // provided one earlier.  This is only possible if they created this
00176   // Diagonal instance using the constructor that takes a
00177   // Tpetra::Vector pointer, and then called setMatrix() with a
00178   // nonnull input matrix.
00179   if (! matrix_.is_null ()) {
00180     // If you call initialize(), it means that you are asserting that
00181     // the structure of the input sparse matrix may have changed.
00182     // This means we should always recompute the diagonal offsets, if
00183     // the input matrix is a Tpetra::CrsMatrix.
00184     Teuchos::RCP<const crs_matrix_type> A_crs =
00185       Teuchos::rcp_dynamic_cast<const crs_matrix_type> (matrix_);
00186     if (A_crs.is_null ()) {
00187       offsets_ = Teuchos::null; // offsets are no longer valid
00188     }
00189     else {
00190       A_crs->getLocalDiagOffsets (offsets_);
00191     }
00192   }
00193 
00194   isInitialized_ = true;
00195   ++numInitialize_;
00196 }
00197 
00198 template<class MatrixType>
00199 void Diagonal<MatrixType>::compute ()
00200 {
00201   // Either the matrix to precondition must be nonnull, or the user
00202   // must have provided a Vector of diagonal entries.
00203   TEUCHOS_TEST_FOR_EXCEPTION(
00204     matrix_.is_null () && userInverseDiag_.is_null (), std::runtime_error,
00205     "Ifpack2::Diagonal::compute: The matrix to precondition is null, "
00206     "and you did not provide a Tpetra::Vector of diagonal entries.  "
00207     "Please call setMatrix() with a nonnull input before calling this method.");
00208 
00209   if (! isInitialized_) {
00210     initialize ();
00211   }
00212 
00213   // If the user did provide an input matrix, then that takes
00214   // precedence over the vector of inverse diagonal entries, if they
00215   // provided one earlier.  This is only possible if they created this
00216   // Diagonal instance using the constructor that takes a
00217   // Tpetra::Vector pointer, and then called setMatrix() with a
00218   // nonnull input matrix.
00219   if (matrix_.is_null ()) { // accept the user's diagonal
00220     inverseDiag_ = userInverseDiag_;
00221   }
00222   else {
00223     Teuchos::RCP<vector_type> tmpVec (new vector_type (matrix_->getRowMap ()));
00224     Teuchos::RCP<const crs_matrix_type> A_crs =
00225       Teuchos::rcp_dynamic_cast<const crs_matrix_type> (matrix_);
00226     if (A_crs.is_null ()) {
00227       // Get the diagonal entries from the Tpetra::RowMatrix.
00228       matrix_->getLocalDiagCopy (*tmpVec);
00229     }
00230     else {
00231       // Get the diagonal entries from the Tpetra::CrsMatrix using the
00232       // precomputed offsets.
00233       A_crs->getLocalDiagCopy (*tmpVec, offsets_ ());
00234     }
00235     tmpVec->reciprocal (*tmpVec); // invert the diagonal entries
00236     inverseDiag_ = tmpVec;
00237   }
00238 
00239   isComputed_ = true;
00240   ++numCompute_;
00241 }
00242 
00243 template<class MatrixType>
00244 void Diagonal<MatrixType>::
00245 apply (const Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type>& X,
00246        Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type>& Y,
00247        Teuchos::ETransp /*mode*/,
00248        scalar_type alpha,
00249        scalar_type beta) const
00250 {
00251   TEUCHOS_TEST_FOR_EXCEPTION(
00252     ! isComputed (), std::runtime_error, "Ifpack2::Diagonal::apply: You "
00253     "must first call compute() before you may call apply().  Once you have "
00254     "called compute(), you need not call it again unless the values in the "
00255     "matrix have changed, or unless you have called setMatrix().");
00256 
00257   // FIXME (mfh 12 Sep 2014) This assumes that row Map == range Map ==
00258   // domain Map.  If the preconditioner has a matrix, we should ask
00259   // the matrix whether we need to do an Import before and/or an
00260   // Export after.
00261 
00262   Y.elementWiseMultiply (alpha, *inverseDiag_, X, beta);
00263   ++numApply_;
00264 }
00265 
00266 template<class MatrixType>
00267 typename Teuchos::ScalarTraits<typename MatrixType::scalar_type>::magnitudeType
00268 Diagonal<MatrixType>::
00269 computeCondEst (CondestType CT,
00270                 local_ordinal_type MaxIters,
00271                 magnitude_type Tol,
00272                 const Teuchos::Ptr<const row_matrix_type>& matrix)
00273 {
00274   const magnitude_type minusOne = -Teuchos::ScalarTraits<magnitude_type>::one ();
00275 
00276   if (! isComputed ()) { // cannot compute right now
00277     return minusOne;
00278   }
00279   // NOTE: this is computing the *local* condest
00280   if (condEst_ == minusOne) {
00281     condEst_ = Ifpack2::Condest (*this, CT, MaxIters, Tol, matrix);
00282   }
00283   return condEst_;
00284 }
00285 
00286 template <class MatrixType>
00287 int Diagonal<MatrixType>::getNumInitialize() const {
00288   return numInitialize_;
00289 }
00290 
00291 template <class MatrixType>
00292 int Diagonal<MatrixType>::getNumCompute() const {
00293   return numCompute_;
00294 }
00295 
00296 template <class MatrixType>
00297 int Diagonal<MatrixType>::getNumApply() const {
00298   return numApply_;
00299 }
00300 
00301 template <class MatrixType>
00302 double Diagonal<MatrixType>::getInitializeTime() const {
00303   return initializeTime_;
00304 }
00305 
00306 template<class MatrixType>
00307 double Diagonal<MatrixType>::getComputeTime() const {
00308   return computeTime_;
00309 }
00310 
00311 template<class MatrixType>
00312 double Diagonal<MatrixType>::getApplyTime() const {
00313   return applyTime_;
00314 }
00315 
00316 template <class MatrixType>
00317 std::string Diagonal<MatrixType>::description () const
00318 {
00319   std::ostringstream out;
00320 
00321   // Output is a valid YAML dictionary in flow style.  If you don't
00322   // like everything on a single line, you should call describe()
00323   // instead.
00324   out << "\"Ifpack2::Diagonal\": "
00325       << "{";
00326   if (this->getObjectLabel () != "") {
00327     out << "Label: \"" << this->getObjectLabel () << "\", ";
00328   }
00329   if (matrix_.is_null ()) {
00330     out << "Matrix: null";
00331   }
00332   else {
00333     out << "Matrix: not null"
00334         << ", Global matrix dimensions: ["
00335         << matrix_->getGlobalNumRows () << ", "
00336         << matrix_->getGlobalNumCols () << "]";
00337   }
00338 
00339   out << "}";
00340   return out.str ();
00341 }
00342 
00343 template <class MatrixType>
00344 void Diagonal<MatrixType>::
00345 describe (Teuchos::FancyOStream &out,
00346           const Teuchos::EVerbosityLevel verbLevel) const
00347 {
00348   using std::endl;
00349 
00350   const Teuchos::EVerbosityLevel vl =
00351     (verbLevel == Teuchos::VERB_DEFAULT) ? Teuchos::VERB_LOW : verbLevel;
00352   if (vl != Teuchos::VERB_NONE) {
00353     Teuchos::OSTab tab0 (out);
00354     out << "\"Ifpack2::Diagonal\":";
00355     Teuchos::OSTab tab1 (out);
00356     out << "Template parameter: "
00357         << Teuchos::TypeNameTraits<MatrixType>::name () << endl;
00358     if (this->getObjectLabel () != "") {
00359       out << "Label: \"" << this->getObjectLabel () << "\", ";
00360     }
00361     out << "Number of initialize calls: " << numInitialize_ << endl
00362         << "Number of compute calls: " << numCompute_ << endl
00363         << "Number of apply calls: " << numApply_ << endl;
00364   }
00365 }
00366 
00367 } // namespace Ifpack2
00368 
00369 #define IFPACK2_DIAGONAL_INSTANT(S,LO,GO,N)                            \
00370   template class Ifpack2::Diagonal< Tpetra::CrsMatrix<S, LO, GO, N> >; \
00371   template class Ifpack2::Diagonal< Tpetra::RowMatrix<S, LO, GO, N> >;
00372 
00373 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends