Files
mlpack/fastlib/trilinos/include/Ifpack_SparseContainer.h
T

593 lines
16 KiB
C++

/*@HEADER
// ***********************************************************************
//
// Ifpack: Object-Oriented Algebraic Preconditioner Package
// Copyright (2002) Sandia Corporation
//
// Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
// license for use of this work by or on behalf of the U.S. Government.
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
// Questions? Contact Michael A. Heroux (maherou@sandia.gov)
//
// ***********************************************************************
//@HEADER
*/
#ifndef IFPACK_SPARSECONTAINER_H
#define IFPACK_SPARSECONTAINER_H
#include "Ifpack_Container.h"
#include "Epetra_IntSerialDenseVector.h"
#include "Epetra_MultiVector.h"
#include "Epetra_Vector.h"
#include "Epetra_Map.h"
#include "Epetra_RowMatrix.h"
#include "Epetra_CrsMatrix.h"
#include "Epetra_LinearProblem.h"
#include "Epetra_IntSerialDenseVector.h"
#include "Teuchos_ParameterList.hpp"
#include "Teuchos_RefCountPtr.hpp"
#ifdef HAVE_MPI
#include "Epetra_MpiComm.h"
#else
#include "Epetra_SerialComm.h"
#endif
/*!
\brief Ifpack_SparseContainer: a class for storing and solving linear systems
using sparse matrices.
<P>To understand what an IFPACK container is, please refer to the documentation
of the pure virtual class Ifpack_Container. Currently, containers are
used by class Ifpack_BlockRelaxation.
<P>Using block methods, one needs to store all diagonal blocks and
to be also to apply the inverse of each diagonal block. Using
class Ifpack_DenseContainer, one can store the blocks as sparse
matrices (Epetra_CrsMatrix), which can be advantageous when the
blocks are large. Otherwise,
class Ifpack_DenseContainer is probably more appropriate.
<P>Sparse containers are templated with a type T, which represent the
class to use in the application of the inverse. (T is not
used in Ifpack_DenseContainer). In SparseContainer, T must be
an Ifpack_Preconditioner derived class. The container will allocate
a \c T object, use SetParameters() and Compute(), then
use \c T every time the linear system as to be solved (using the
ApplyInverse() method of \c T).
\author Marzio Sala, SNL 9214.
\date Last modified on Nov-04.
*/
template<typename T>
class Ifpack_SparseContainer : public Ifpack_Container {
public:
//@{ Constructors/Destructors.
//! Constructor.
Ifpack_SparseContainer(const int NumRows, const int NumVectors = 1);
//! Copy constructor.
Ifpack_SparseContainer(const Ifpack_SparseContainer<T>& rhs);
//! Destructor.
virtual ~Ifpack_SparseContainer();
//@}
//@{ Overloaded operators.
//! Operator =
Ifpack_SparseContainer& operator=(const Ifpack_SparseContainer<T>& rhs);
//@}
//@{ Get/Set methods.
//! Returns the number of rows of the matrix and LHS/RHS.
virtual int NumRows() const;
//! Returns the number of vectors in LHS/RHS.
virtual int NumVectors() const
{
return(NumVectors_);
}
//! Sets the number of vectors for LHS/RHS.
virtual int SetNumVectors(const int NumVectors)
{
if (NumVectors_ == NumVectors)
return(0);
IFPACK_CHK_ERR(-99); // STILL TO DO
}
//! Returns the i-th component of the vector Vector of LHS.
virtual double& LHS(const int i, const int Vector = 0);
//! Returns the i-th component of the vector Vector of RHS.
virtual double& RHS(const int i, const int Vector = 0);
//! Returns the ID associated to local row i.
/*!
* The set of (local) rows assigned to this container is defined
* by calling ID(i) = j, where i (from 0 to NumRows()) indicates
* the container-row, and j indicates the local row in the calling
* process.
*
* This is usually used to recorder the local row ID (on calling process)
* of the i-th row in the container.
*/
virtual int& ID(const int i);
//! Set the matrix element (row,col) to \c value.
virtual int SetMatrixElement(const int row, const int col,
const double value);
//! Returns \c true is the container has been successfully initialized.
virtual bool IsInitialized() const
{
return(IsInitialized_);
}
//! Returns \c true is the container has been successfully computed.
virtual bool IsComputed() const
{
return(IsComputed_);
}
//! Sets all necessary parameters.
virtual int SetParameters(Teuchos::ParameterList& List);
//! Returns the label of \e this container.
virtual const char* Label() const
{
return(Label_.c_str());
}
//! Returns a pointer to the internally stored map.
const Epetra_Map* Map() const
{
return(Map_);
}
//! Returns a pointer to the internally stored solution multi-vector.
const Epetra_MultiVector* LHS() const
{
return(LHS_);
}
//! Returns a pointer to the internally stored rhs multi-vector.
const Epetra_MultiVector* RHS() const
{
return(RHS_);
}
//! Returns a pointer to the internally stored matrix.
const Epetra_CrsMatrix* Matrix() const
{
return(Matrix_);
}
//! Returns a pointer to the internally stored ID's.
const Epetra_IntSerialDenseVector* ID() const
{
return(GID_);
}
//! Returns a pointer to the internally stored inverse operator.
const T* Inverse() const
{
return(Inverse_);
}
//@}
//@{ Mathematical functions.
/*!
* \brief Initializes the container, by completing all the operations based
* on matrix structure.
*
* \note After a call to Initialize(), no new matrix entries can be
* added.
*/
virtual int Initialize();
//! Finalizes the linear system matrix and prepares for the application of the inverse.
virtual int Compute(const Epetra_RowMatrix& Matrix);
//! Apply the matrix to RHS, result is stored in LHS.
virtual int Apply();
//! Apply the inverse of the matrix to RHS, result is stored in LHS.
virtual int ApplyInverse();
//@}
//@{ Miscellaneous methods
//! Destroys all data.
virtual int Destroy();
//@}
//! Returns the flops in Compute().
virtual double InitializeFlops() const
{
if (Inverse_ == Teuchos::null)
return (0.0);
else
return(Inverse_->InitializeFlops());
}
//! Returns the flops in Compute().
virtual double ComputeFlops() const
{
if (Inverse_ == Teuchos::null)
return (0.0);
else
return(Inverse_->ComputeFlops());
}
//! Returns the flops in Apply().
virtual double ApplyFlops() const
{
return(ApplyFlops_);
}
//! Returns the flops in ApplyInverse().
virtual double ApplyInverseFlops() const
{
if (Inverse_ == Teuchos::null)
return (0.0);
else
return(Inverse_->ApplyInverseFlops());
}
//! Prints basic information on iostream. This function is used by operator<<.
virtual ostream& Print(std::ostream& os) const;
private:
//! Extract the submatrices identified by the ID set int ID().
virtual int Extract(const Epetra_RowMatrix& Matrix);
//! Number of rows in the local matrix.
int NumRows_;
//! Number of vectors in the local linear system.
int NumVectors_;
//! Linear map on which the local matrix is based.
Teuchos::RefCountPtr<Epetra_Map> Map_;
//! Pointer to the local matrix.
Teuchos::RefCountPtr<Epetra_CrsMatrix> Matrix_;
//! Solution vector.
Teuchos::RefCountPtr<Epetra_MultiVector> LHS_;
//! right-hand side for local problems.
Teuchos::RefCountPtr<Epetra_MultiVector> RHS_;
//! Contains the subrows/subcols of A that will be inserted in Matrix_.
Epetra_IntSerialDenseVector GID_;
//! If \c true, the container has been successfully initialized.
bool IsInitialized_;
//! If \c true, the container has been successfully computed.
bool IsComputed_;
//! Serial communicator (containing only MPI_COMM_SELF if MPI is used).
Teuchos::RefCountPtr<Epetra_Comm> SerialComm_;
//! Pointer to an Ifpack_Preconditioner object whose ApplyInverse() defined the action of the inverse of the local matrix.
Teuchos::RefCountPtr<T> Inverse_;
//! Label for \c this object
string Label_;
Teuchos::ParameterList List_;
double ApplyFlops_;
};
//==============================================================================
template<typename T>
Ifpack_SparseContainer<T>::
Ifpack_SparseContainer(const int NumRows, const int NumVectors) :
NumRows_(NumRows),
NumVectors_(NumVectors),
IsInitialized_(false),
IsComputed_(false),
ApplyFlops_(0.0)
{
#ifdef HAVE_MPI
SerialComm_ = Teuchos::rcp( new Epetra_MpiComm(MPI_COMM_SELF) );
#else
SerialComm_ = Teuchos::rcp( new Epetra_SerialComm );
#endif
}
//==============================================================================
template<typename T>
Ifpack_SparseContainer<T>::
Ifpack_SparseContainer(const Ifpack_SparseContainer<T>& rhs) :
NumRows_(rhs.NumRows()),
NumVectors_(rhs.NumVectors()),
IsInitialized_(rhs.IsInitialized()),
IsComputed_(rhs.IsComputed())
{
#ifdef HAVE_MPI
SerialComm_ = Teuchos::rcp( new Epetra_MpiComm(MPI_COMM_SELF) );
#else
SerialComm_ = Teuchos::rcp( new Epetra_SerialComm );
#endif
if (rhs.Map())
Map_ = Teuchos::rcp( new Epetra_Map(*rhs.Map()) );
if (rhs.Matrix())
Matrix_ = Teuchos::rcp( new Epetra_CrsMatrix(*rhs.Matrix()) );
if (rhs.LHS())
LHS_ = Teuchos::rcp( new Epetra_MultiVector(*rhs.LHS()) );
if (rhs.RHS())
RHS_ = Teuchos::rcp( new Epetra_MultiVector(*rhs.RHS()) );
}
//==============================================================================
template<typename T>
Ifpack_SparseContainer<T>::~Ifpack_SparseContainer()
{
Destroy();
}
//==============================================================================
template<typename T>
int Ifpack_SparseContainer<T>::NumRows() const
{
if (IsInitialized() == false)
return(0);
else
return(NumRows_);
}
//==============================================================================
template<typename T>
int Ifpack_SparseContainer<T>::Initialize()
{
if (IsInitialized_ == true)
Destroy();
IsInitialized_ = false;
Map_ = Teuchos::rcp( new Epetra_Map(NumRows_,0,*SerialComm_) );
LHS_ = Teuchos::rcp( new Epetra_MultiVector(*Map_,NumVectors_) );
RHS_ = Teuchos::rcp( new Epetra_MultiVector(*Map_,NumVectors_) );
GID_.Reshape(NumRows_,1);
Matrix_ = Teuchos::rcp( new Epetra_CrsMatrix(Copy,*Map_,0) );
// create the inverse
Inverse_ = Teuchos::rcp( new T(Matrix_.get()) );
if (Inverse_ == Teuchos::null)
IFPACK_CHK_ERR(-5);
IFPACK_CHK_ERR(Inverse_->SetParameters(List_));
// Call Inverse_->Initialize() in Compute(). This saves
// some time, because I can extract the diagonal blocks faster,
// and only once.
Label_ = "Ifpack_SparseContainer";
IsInitialized_ = true;
return(0);
}
//==============================================================================
template<typename T>
double& Ifpack_SparseContainer<T>::LHS(const int i, const int Vector)
{
return(((*LHS_)(Vector))->Values()[i]);
}
//==============================================================================
template<typename T>
double& Ifpack_SparseContainer<T>::RHS(const int i, const int Vector)
{
return(((*RHS_)(Vector))->Values()[i]);
}
//==============================================================================
template<typename T>
int Ifpack_SparseContainer<T>::
SetMatrixElement(const int row, const int col, const double value)
{
if (!IsInitialized())
IFPACK_CHK_ERR(-3); // problem not shaped yet
if ((row < 0) || (row >= NumRows())) {
IFPACK_CHK_ERR(-2); // not in range
}
if ((col < 0) || (col >= NumRows())) {
IFPACK_CHK_ERR(-2); // not in range
}
int ierr = Matrix_->InsertGlobalValues((int)row,1,(double*)&value,(int*)&col);
if (ierr < 0) {
ierr = Matrix_->SumIntoGlobalValues((int)row,1,(double*)&value,(int*)&col);
if (ierr < 0)
IFPACK_CHK_ERR(-1);
}
return(0);
}
//==============================================================================
template<typename T>
int Ifpack_SparseContainer<T>::Compute(const Epetra_RowMatrix& Matrix)
{
IsComputed_ = false;
if (!IsInitialized()) {
IFPACK_CHK_ERR(Initialize());
}
// extract the submatrices
IFPACK_CHK_ERR(Extract(Matrix));
// initialize the inverse operator
IFPACK_CHK_ERR(Inverse_->Initialize());
// compute the inverse operator
IFPACK_CHK_ERR(Inverse_->Compute());
Label_ = "Ifpack_SparseContainer";
IsComputed_ = true;
return(0);
}
//==============================================================================
template<typename T>
int Ifpack_SparseContainer<T>::Apply()
{
if (IsComputed() == false) {
IFPACK_CHK_ERR(-3); // not yet computed
}
IFPACK_CHK_ERR(Matrix_->Apply(*RHS_, *LHS_));
ApplyFlops_ += 2 * Matrix_->NumGlobalNonzeros();
return(0);
}
//==============================================================================
template<typename T>
int Ifpack_SparseContainer<T>::ApplyInverse()
{
if (!IsComputed())
IFPACK_CHK_ERR(-1);
IFPACK_CHK_ERR(Inverse_->ApplyInverse(*RHS_, *LHS_));
return(0);
}
//==============================================================================
template<typename T>
int Ifpack_SparseContainer<T>::Destroy()
{
IsInitialized_ = false;
IsComputed_ = false;
return(0);
}
//==============================================================================
template<typename T>
int& Ifpack_SparseContainer<T>::ID(const int i)
{
return(GID_[i]);
}
//==============================================================================
template<typename T>
int Ifpack_SparseContainer<T>::
SetParameters(Teuchos::ParameterList& List)
{
List_ = List;
return(0);
}
//==============================================================================
// FIXME: optimize performances of this guy...
template<typename T>
int Ifpack_SparseContainer<T>::Extract(const Epetra_RowMatrix& Matrix)
{
for (int j = 0 ; j < NumRows_ ; ++j) {
// be sure that the user has set all the ID's
if (ID(j) == -1)
IFPACK_CHK_ERR(-1);
// be sure that all are local indices
if (ID(j) > Matrix.NumMyRows())
IFPACK_CHK_ERR(-1);
}
int Length = Matrix.MaxNumEntries();
std::vector<double> Values;
Values.resize(Length);
std::vector<int> Indices;
Indices.resize(Length);
for (int j = 0 ; j < NumRows_ ; ++j) {
int LRID = ID(j);
int NumEntries;
int ierr =
Matrix.ExtractMyRowCopy(LRID, Length, NumEntries,
&Values[0], &Indices[0]);
IFPACK_CHK_ERR(ierr);
for (int k = 0 ; k < NumEntries ; ++k) {
int LCID = Indices[k];
// skip off-processor elements
if (LCID >= Matrix.NumMyRows())
continue;
// for local column IDs, look for each ID in the list
// of columns hosted by this object
// FIXME: use STL
int jj = -1;
for (int kk = 0 ; kk < NumRows_ ; ++kk)
if (ID(kk) == LCID)
jj = kk;
if (jj != -1)
SetMatrixElement(j,jj,Values[k]);
}
}
IFPACK_CHK_ERR(Matrix_->FillComplete());
return(0);
}
//==============================================================================
template<typename T>
ostream& Ifpack_SparseContainer<T>::Print(ostream & os) const
{
os << "================================================================================" << endl;
os << "Ifpack_SparseContainer" << endl;
os << "Number of rows = " << NumRows() << endl;
os << "Number of vectors = " << NumVectors() << endl;
os << "IsInitialized() = " << IsInitialized() << endl;
os << "IsComputed() = " << IsComputed() << endl;
os << "Flops in Initialize() = " << InitializeFlops() << endl;
os << "Flops in Compute() = " << ComputeFlops() << endl;
os << "Flops in ApplyInverse() = " << ApplyInverseFlops() << endl;
os << "================================================================================" << endl;
os << endl;
return(os);
}
#endif // IFPACK_SPARSECONTAINER_H