Stratimikos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
belos_tpetra_thyra_lowsf_lap.cpp
Go to the documentation of this file.
00001 
00002 // @HEADER
00003 // ***********************************************************************
00004 // 
00005 //         Stratimikos: Thyra-based strategies for linear solvers
00006 //                Copyright (2006) Sandia Corporation
00007 // 
00008 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00009 // license for use of this work by or on behalf of the U.S. Government.
00010 // 
00011 // Redistribution and use in source and binary forms, with or without
00012 // modification, are permitted provided that the following conditions are
00013 // met:
00014 //
00015 // 1. Redistributions of source code must retain the above copyright
00016 // notice, this list of conditions and the following disclaimer.
00017 //
00018 // 2. Redistributions in binary form must reproduce the above copyright
00019 // notice, this list of conditions and the following disclaimer in the
00020 // documentation and/or other materials provided with the distribution.
00021 //
00022 // 3. Neither the name of the Corporation nor the names of the
00023 // contributors may be used to endorse or promote products derived from
00024 // this software without specific prior written permission.
00025 //
00026 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00027 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00028 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00029 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00030 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00031 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00032 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00033 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00034 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00035 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00036 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037 //
00038 // Questions? Contact Roscoe A. Bartlett (rabartl@sandia.gov) 
00039 // 
00040 // ***********************************************************************
00041 // @HEADER
00042 //
00043 // This driver creates a 2D Laplacian operator as a Tpetra::CisMatrix. 
00044 // This matrix is then converted into a Thyra linear operator 
00045 // through the Thyra-Tpetra adapters.
00046 //
00047 // The right-hand sides are all random vectors.
00048 // The initial guesses are all set to zero. 
00049 //
00050 //
00051 
00052 // Thyra includes
00053 #include "Thyra_BelosLinearOpWithSolveFactory.hpp"
00054 #include "Thyra_LinearOpWithSolveFactoryHelpers.hpp"
00055 #include "Thyra_TpetraLinearOp.hpp"
00056 
00057 // Tpetra includes
00058 #include "Tpetra_ElementSpace.hpp"
00059 #include "Tpetra_VectorSpace.hpp"
00060 #include "Tpetra_CisMatrix.hpp"
00061 
00062 // Teuchos includes
00063 #include "Teuchos_ParameterList.hpp"
00064 #include "Teuchos_VerboseObject.hpp"
00065 #include "Teuchos_GlobalMPISession.hpp"
00066 
00067 #ifdef HAVE_MPI
00068 #  include "Tpetra_MpiPlatform.hpp"
00069 #else
00070 #  include "Tpetra_SerialPlatform.hpp"
00071 #endif
00072 
00073 int main(int argc, char* argv[])
00074 {
00075   //
00076   // Get a default output stream from the Teuchos::VerboseObjectBase
00077   //
00078   Teuchos::RCP<Teuchos::FancyOStream>
00079     out = Teuchos::VerboseObjectBase::getDefaultOStream();
00080   
00081   Teuchos::GlobalMPISession mpiSession(&argc,&argv);
00082 
00083   // --------------------------------------------------------------------------------
00084   //
00085   // Create the scalar-type typedefs
00086   //
00087   // --------------------------------------------------------------------------------
00088 
00089 #ifdef HAVE_COMPLEX
00090   typedef std::complex<double> ST;
00091 #elif HAVE_COMPLEX_H
00092   typedef std::complex<double> ST;
00093 #else
00094   typedef double ST;
00095 #endif
00096   typedef Teuchos::ScalarTraits<ST>::magnitudeType MT;
00097   typedef int OT;
00098 
00099   // --------------------------------------------------------------------------------
00100   //
00101   // Create 2D Laplacian using Tpetra::CisMatrix
00102   //
00103   // --------------------------------------------------------------------------------
00104 
00105 #ifdef HAVE_MPI
00106   MPI_Comm mpiComm = MPI_COMM_WORLD;
00107   const Tpetra::MpiPlatform<OT,OT>  ordinalPlatform(mpiComm);
00108   const Tpetra::MpiPlatform<OT,ST>   scalarPlatform(mpiComm);
00109 #else
00110   const Tpetra::SerialPlatform<OT,OT>  ordinalPlatform;
00111   const Tpetra::SerialPlatform<OT,ST>   scalarPlatform;
00112 #endif
00113 
00114   // Declare global dimension of the linear operator
00115   OT globalDim = 500;
00116 
00117   // Create the element space and std::vector space
00118   const Tpetra::ElementSpace<OT> elementSpace(globalDim,0,ordinalPlatform);
00119   const Tpetra::VectorSpace<OT,ST> vectorSpace(elementSpace,scalarPlatform);
00120   
00121   // Allocate the Tpetra::CisMatrix object.
00122   RCP<Tpetra::CisMatrix<OT,ST> >
00123     tpetra_A = rcp(new Tpetra::CisMatrix<OT,ST>(vectorSpace));
00124 
00125   // Get the indexes of the rows on this processor
00126   const int numMyElements = vectorSpace.getNumMyEntries();
00127   const std::vector<int> &myGlobalElements = vectorSpace.elementSpace().getMyGlobalElements();
00128 
00129   // Fill the local matrix entries one row at a time.
00130   const ST offDiag = -1.0, diag = 2.0;
00131   int numEntries; ST values[3]; int indexes[3];
00132   for( int k = 0; k < numMyElements; ++k ) {
00133     const int rowIndex = myGlobalElements[k];
00134     if( rowIndex == 0 ) {                     // First row
00135       numEntries = 2;
00136       values[0]  = diag;             values[1]  = offDiag;
00137       indexes[0] = 0;                indexes[1] = 1; 
00138     }
00139     else if( rowIndex == globalDim - 1 ) {    // Last row
00140       numEntries = 2;
00141       values[0]  = offDiag;         values[1]  = diag;
00142       indexes[0] = globalDim-2;     indexes[1] = globalDim-1; 
00143     }
00144     else {                                    // Middle rows
00145       numEntries = 3;
00146       values[0]  = offDiag;         values[1]  = diag;          values[2]  = offDiag;
00147       indexes[0] = rowIndex-1;      indexes[1] = rowIndex;      indexes[2] = rowIndex+1; 
00148     }
00149     tpetra_A->submitEntries(Tpetra::Insert,rowIndex,numEntries,values,indexes);
00150   }
00151 
00152   // Finish the construction of the Tpetra::CisMatrix
00153   tpetra_A->fillComplete();
00154 
00155   // Create a Thyra linear operator (A) using the Tpetra::CisMatrix (tpetra_A).
00156   RCP<Thyra::LinearOpBase<ST> >
00157     A = Teuchos::rcp( new Thyra::TpetraLinearOp<OT,ST>(
00158                       Teuchos::rcp_implicit_cast<Tpetra::Operator<OT,ST> >(tpetra_A) ) );
00159 
00160   // Set the parameters for the Belos LOWS Factory and create a parameter list.
00161   // NOTE:  All the code below only uses Thyra and is independent of Tpetra.
00162   //
00163   int             blockSize              = 1;  // can only be 1 right now.
00164   int             maxIterations          = globalDim;
00165   int             maxRestarts            = 0;
00166   int             gmresKrylovLength      = globalDim;
00167   int             outputFrequency        = 100;
00168   bool            outputMaxResOnly       = true;
00169   MT              maxResid               = 1e-3;
00170 
00171   ST one = Teuchos::ScalarTraits<ST>::one();
00172   ST zero = Teuchos::ScalarTraits<ST>::zero();
00173   
00174   Teuchos::RCP<Teuchos::ParameterList>
00175     belosLOWSFPL = Teuchos::rcp( new Teuchos::ParameterList() );
00176  
00177   belosLOWSFPL->set("Solver Type","Block GMRES");
00178 
00179   Teuchos::ParameterList& belosLOWSFPL_solver =
00180     belosLOWSFPL->sublist("Solver Types");
00181 
00182   Teuchos::ParameterList& belosLOWSFPL_gmres =
00183     belosLOWSFPL_solver.sublist("Block GMRES");
00184 
00185   belosLOWSFPL_gmres.set("Maximum Iterations",int(maxIterations));
00186   belosLOWSFPL_gmres.set("Convergence Tolerance",double(maxResid));
00187   belosLOWSFPL_gmres.set("Maximum Restarts",int(maxRestarts));
00188   belosLOWSFPL_gmres.set("Block Size",int(blockSize));
00189   belosLOWSFPL_gmres.set("Num Blocks",int(gmresKrylovLength));
00190   belosLOWSFPL_gmres.set("Output Frequency",int(outputFrequency));
00191   belosLOWSFPL_gmres.set("Show Maximum Residual Norm Only",bool(outputMaxResOnly));
00192  
00193   // Whether the linear solver succeeded.
00194   // (this will be set during the residual check at the end)
00195   bool success = true;
00196 
00197   // --------------------------------------------------------------------------------
00198   //
00199   // Create the right-hand sides and solution vectors
00200   //
00201   // --------------------------------------------------------------------------------
00202 
00203   // Number of random right-hand sides we will be solving for.
00204   int numRhs = 5;
00205 
00206   // Create smart pointer to right-hand side and solution std::vector to be filled in below.
00207   Teuchos::RCP<Thyra::MultiVectorBase<ST> > x, b;
00208 
00209   if (numRhs==1) {
00210     //
00211     // In this case we can construct vectors using Tpetra and just "wrap" them in Thyra objects.
00212     //
00213 
00214     // Create RHS std::vector
00215     Teuchos::RCP<Tpetra::Vector<OT,ST> > tpetra_b =
00216       Teuchos::rcp( new Tpetra::Vector<OT,ST>(vectorSpace) );
00217 
00218     // Randomize RHS std::vector
00219     tpetra_b->setAllToRandom();
00220 
00221     // Wrap Tpetra std::vector as Thyra std::vector
00222     b = Thyra::create_Vector(tpetra_b);
00223     
00224     // Create solution (LHS) std::vector
00225     Teuchos::RCP<Tpetra::Vector<OT,ST> > tpetra_x =
00226       Teuchos::rcp( new Tpetra::Vector<OT,ST>(vectorSpace) );
00227 
00228     // Initialize solution to zero
00229     tpetra_x->setAllToScalar( zero );
00230 
00231     // Wrap Tpetra std::vector as Thyra std::vector
00232     x = Thyra::create_Vector(tpetra_x);
00233 
00234   } 
00235   else {
00236     //
00237     // In this case we can construct the multivector using Thyra and extract columns of
00238     // the multivector as Tpetra std::vector, which can then be filled.  This is because
00239     // Tpetra does not have a multivector object and Thyra will emulate the multivector.
00240     //
00241     
00242     // Get the domain space for the Thyra linear operator 
00243     Teuchos::RCP<const Thyra::VectorSpaceBase<ST> > domain = A->domain();
00244     
00245     // Create a right-hand side and solution vectors with numRhs vectors in it.
00246     x = Thyra::createMembers(domain, numRhs);
00247     b = Thyra::createMembers(domain, numRhs);
00248 
00249     // Extract the Tpetra std::vector from the columns of the multivector and fill them with 
00250     // random numbers (b) or zeros (x).
00251 
00252     for ( int j=0; j<numRhs; ++j ) {
00253       //
00254       // Get the j-th column from b as a Tpetra std::vector and randomize it.
00255       // 
00256       Teuchos::RCP<Tpetra::Vector<OT,ST> > 
00257   tpetra_b_j = Thyra::get_Tpetra_Vector(vectorSpace,b->col(j));
00258       tpetra_b_j->setAllToRandom();
00259       // 
00260       // Get the j-th column from x as a Tpetra std::vector and set it to zero.
00261       //
00262       Teuchos::RCP<Tpetra::Vector<OT,ST> > 
00263   tpetra_x_j = Thyra::get_Tpetra_Vector(vectorSpace,x->col(j));
00264       tpetra_x_j->setAllToScalar( zero );
00265       //
00266       // NOTE: Tpetra vectors have element access via the [] operator.
00267       //       So and additional approach for filling in a Tpetra std::vector is:
00268       //
00269       for ( int i=0; i<numMyElements; ++i ) {
00270   //
00271   // Get the global index.
00272   //
00273   const int rowIndex = myGlobalElements[ i ];
00274 
00275   // Set the entry to zero.
00276   (*tpetra_x_j)[ rowIndex ] = zero;
00277       }
00278     }
00279   }
00280   
00281   // --------------------------------------------------------------------------------
00282   //
00283   // Create the linear operator with solve factory/object and solve the linear
00284   // system using the iterative solvers in Belos.
00285   //
00286   // NOTE:  This is the only part of the code that solely uses Thyra.
00287   //
00288   // --------------------------------------------------------------------------------
00289 
00290   // Create the Belos LOWS factory.
00291   Teuchos::RCP<Thyra::LinearOpWithSolveFactoryBase<ST> >
00292     belosLOWSFactory = Teuchos::rcp(new Thyra::BelosLinearOpWithSolveFactory<ST>());
00293   
00294   // Set the output stream and the verbosity level (prints to std::cout by defualt)
00295   // NOTE:  Set to VERB_NONE for no output from the solver.
00296   belosLOWSFactory->setVerbLevel(Teuchos::VERB_LOW);
00297   
00298   // Set the parameter list to specify the behavior of the factory.
00299   belosLOWSFactory->setParameterList( belosLOWSFPL );
00300   
00301   // Create a BelosLinearOpWithSolve object from the Belos LOWS factory.
00302   Teuchos::RCP<Thyra::LinearOpWithSolveBase<ST> >
00303     nsA = belosLOWSFactory->createOp();
00304   
00305   // Initialize the BelosLinearOpWithSolve object with the Thyra linear operator.
00306   Thyra::initializeOp<ST>( *belosLOWSFactory, A, &*nsA );
00307   
00308   // Perform solve using the linear operator to get the approximate solution of Ax=b,
00309   // where b is the right-hand side and x is the left-hand side.
00310   Thyra::SolveStatus<ST> solveStatus;
00311   solveStatus = Thyra::solve( *nsA, Thyra::NONCONJ_ELE, *b, &*x );
00312   
00313   // Print out status of solve.
00314   *out << "\nBelos LOWS Status: "<< solveStatus << std::endl;
00315   
00316   // --------------------------------------------------------------------------------
00317   // Compute residual and check convergence.
00318   // NOTE: We will do this by extracting the Tpetra vectors from the multivector.
00319   //
00320   // NOTE 2: We are using scalar traits here instead of the magnitude type
00321   //         because Tpetra defines its norm methods to return the scalar type.
00322   // --------------------------------------------------------------------------------
00323   std::vector<ST> norm_b(numRhs), norm_res(numRhs);
00324   
00325   for ( int j=0; j<numRhs; ++j ) {
00326     //
00327     // Get the j-th columns from x and b as Tpetra vectors.
00328     // 
00329     Teuchos::RCP<Tpetra::Vector<OT,ST> > 
00330       tpetra_x_j = Thyra::get_Tpetra_Vector(vectorSpace,x->col(j));
00331 
00332     Teuchos::RCP<Tpetra::Vector<OT,ST> > 
00333       tpetra_b_j = Thyra::get_Tpetra_Vector(vectorSpace,b->col(j));
00334     
00335     // Compute the column norms of the right-hand side b.
00336     norm_b[j] = tpetra_b_j->norm2();
00337       
00338     // Compute y=A*x, where x is the solution from the linear solver.
00339     Tpetra::Vector<OT,ST> y(vectorSpace);
00340     tpetra_A->apply( *tpetra_x_j, y );
00341 
00342     // Compute b-A*x = b-y
00343     y.update( one, *tpetra_b_j, -one );
00344 
00345     // Compute the column norms of A*x-b.
00346     norm_res[j] = y.norm2();
00347   }
00348 
00349   // Print out the final relative residual norms.
00350   MT rel_res = 0.0;
00351   *out << "Final relative residual norms" << std::endl;  
00352   for (int i=0; i<numRhs; ++i) {
00353     rel_res = Teuchos::ScalarTraits<ST>::real(norm_res[i]/norm_b[i]);
00354     if (rel_res > maxResid)
00355       success = false;
00356     *out << "RHS " << i+1 << " : " 
00357          << std::setw(16) << std::right << rel_res << std::endl;
00358   }
00359   
00360   return ( success ? 0 : 1 );
00361 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines