00001 /* @HEADER@ */ 00002 /* *********************************************************************** 00003 // 00004 // TSFExtended: Trilinos Solver Framework Extended 00005 // Copyright (2004) 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 // This library is free software; you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as 00012 // published by the Free Software Foundation; either version 2.1 of the 00013 // License, or (at your option) any later version. 00014 // 00015 // This library is distributed in the hope that it will be useful, but 00016 // WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 // Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public 00021 // License along with this library; if not, write to the Free Software 00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00023 // USA 00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 00025 // 00026 // **********************************************************************/ 00027 /* @HEADER@ */ 00028 00029 #ifndef TSF_EXPLICITLYTRANSPOSED_LTI_PROBLEMFACTORY_HPP 00030 #define TSF_EXPLICITLYTRANSPOSED_LTI_PROBLEMFACTORY_HPP 00031 00032 00033 #include "SundanceDefs.hpp" 00034 #include "TSFDefaultLTIProblemFactory.hpp" 00035 #include "TSFEpetraMatrix.hpp" 00036 #include "EpetraExt_Transpose_RowMatrix.h" 00037 00038 00039 namespace TSFExtended 00040 { 00041 using namespace Teuchos; 00042 using namespace Thyra; 00043 00044 /** 00045 * This class produces LTI problems where any transpose solves are 00046 * done using explicit transforms. For example, with backwards Euler 00047 * time stepping, the advance matrix \f$ A\f$ will be 00048 * \f$ A = M B^{-1}, \f$ 00049 * where \f$ M \f$ is the mass matrix and \f$ B = M - \Delta t K \f$. However, 00050 * with the AztecOO solver we can't do a transpose solve on B, so we will want 00051 * to form \f$ B^T\f$ explicitly, after which we can form \f$ A^T \f$ 00052 * implicitly as \f$ A^T = (B^T)^{-1} M^T.\f$ In this formulation 00053 * we are only doing a solve on the {\it explicit} transpose of \f$ B. \f$ 00054 */ 00055 template <class Scalar> 00056 class ExplicitlyTransposedLTIProblemFactory 00057 : public DefaultLTIProblemFactory<Scalar> 00058 { 00059 public: 00060 /** Constructor */ 00061 ExplicitlyTransposedLTIProblemFactory(int nSteps) 00062 : DefaultLTIProblemFactory<Scalar>(nSteps), 00063 inputAt_() 00064 {} 00065 00066 00067 00068 /** 00069 * After construction, the user should set the operators by calling 00070 * init(). 00071 * 00072 * \param A The "small" A operator. Small A does the advance through 00073 * a single timestep. 00074 * \param C The "small" C operator. Small C does state observations 00075 * at a single timestep. 00076 * \param At The explicit transpose of small A. 00077 */ 00078 void init( 00079 const LinearOperator<Scalar>& A, 00080 const LinearOperator<Scalar>& At, 00081 const LinearOperator<Scalar>& C 00082 ) 00083 { 00084 /* Call the init method on the default type. This will initialize 00085 * the "small" A and C operators. */ 00086 DefaultLTIProblemFactory<Scalar>::init(A, C); 00087 00088 /* Set the "small" A^T operator to the value given by the user */ 00089 inputAt_ = At; 00090 } 00091 00092 protected: 00093 00094 /** This is a helper function that forms an explicit transpose of 00095 * an operator. For now, this only works if the operator is an 00096 * Epetra_CrsMatrix. We'll want to generalize this later to other operator 00097 * types. 00098 * 00099 * One clumsy feature of this function is that because of the way the 00100 * EpetraExt explicit transposer has been written, the storage for 00101 * the transposed operator is managed by the transposer object. 00102 * Therefore, we need to keep a copy of the transposer object around 00103 * for as long as the transposed matrix exists. We keep a copy 00104 * of it here, as the transposer_ data member of the factory object. 00105 * This means that the factory object had better not go out of scope while 00106 * the matrices it produces still exist. This is dangerous. We should 00107 * talk with Rob H and Mike H about redesigning the EpetraExt transformation 00108 * objects so that the objects they produce have integrity independent 00109 * of the transformation objects. 00110 */ 00111 LinearOperator<Scalar> formExplicitTranspose(const LinearOperator<Scalar>& X) const 00112 { 00113 /* create a transposer object, and store it in the transposer_ 00114 * data member. See the comment above about why ythis is bad but 00115 * necessary. */ 00116 transposer_ = rcp(new EpetraExt::RowMatrix_Transpose(true)); 00117 00118 /* The transposer will act on an epetra crs matrix. Extract a 00119 * Crs matrix from the input operator X. This will throw an exception 00120 * if the object handled by X is not an EpetraMatrix. */ 00121 Epetra_CrsMatrix& epX = EpetraMatrix::getConcrete(X); 00122 00123 /* Do the transpose operation, which returns a Crs matrix but in the 00124 * form of its base class, an Epetra_RowMatrix. */ 00125 Epetra_RowMatrix& eprXt = (*transposer_)(epX); 00126 00127 /* The TSF EpetraMatrix works with Epetra_CrsMatrix, so we need 00128 * to cast the RowMatrix to a CrsMatrix. This should always work, 00129 * because the transposer is implemented in terms of CrsMatrix. If it 00130 * doesn't work, there's been an error somehere in Trilinos. */ 00131 Epetra_CrsMatrix* epXt = dynamic_cast<Epetra_CrsMatrix*>(&eprXt); 00132 TEST_FOR_EXCEPTION(epXt == 0, std::runtime_error, "expected return type " 00133 "of EpetraExt tranposer to be a CrsMatrix"); 00134 00135 00136 /* We need Epetra spaces for the domain and range spaces of the new 00137 * operator. We simply get these from the original, untransposed 00138 * operator and then swap the order of domain and range. The operator 00139 * interface returns generic Thyra VectorSpace objects, which we 00140 * dynamic cast into Epetra VectorSpace objects. This cast should 00141 * always work. 00142 */ 00143 RCP<const EpetraVectorSpace> epXRange = rcp_dynamic_cast<const EpetraVectorSpace>(X.range().ptr()); 00144 RCP<const EpetraVectorSpace> epXDomain = rcp_dynamic_cast<const EpetraVectorSpace>(X.domain().ptr()); 00145 00146 00147 /* We can now create a TSF linear operator for the transpose. We need 00148 * to pass an ownership flag of "false" for the RCP of the 00149 * Epetra_CrsMatrix because the transposed matrix is 00150 * owned by the transposer. We also swap the original operator's 00151 * domain and range spaces in creating the transpose. */ 00152 RCP<LinearOpBase<Scalar> > XtPtr = rcp(new EpetraMatrix(rcp(epXt, false), 00153 epXRange, epXDomain)); 00154 LinearOperator<Scalar> Xt = XtPtr; 00155 00156 /** all done! */ 00157 return Xt; 00158 } 00159 00160 /** Return the transpose of A */ 00161 virtual LinearOperator<Scalar> createAt() const 00162 { 00163 TEST_FOR_EXCEPT(inputAt_.ptr().get() == 0); 00164 return inputAt_; 00165 } 00166 00167 private: 00168 LinearOperator<Scalar> inputAt_; 00169 /** Hack hack hack.... we need to keep the Epetra_Transposer object around 00170 * because it manages the memory of the transposed matrix. */ 00171 mutable RCP<EpetraExt::RowMatrix_Transpose> transposer_; 00172 }; 00173 } 00174 00175 00176 #endif