Stratimikos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
simple_stratimikos_example.cpp
Go to the documentation of this file.
00001 // @HEADER
00002 // ***********************************************************************
00003 //
00004 //         Stratimikos: Thyra-based strategies for linear solvers
00005 //                Copyright (2006) 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 Roscoe A. Bartlett (rabartl@sandia.gov)
00038 //
00039 // ***********************************************************************
00040 // @HEADER
00041 
00042 #include "Stratimikos_DefaultLinearSolverBuilder.hpp"
00043 #include "EpetraExt_readEpetraLinearSystem.h"
00044 #include "Teuchos_GlobalMPISession.hpp"
00045 #include "Teuchos_VerboseObject.hpp"
00046 #include "Teuchos_XMLParameterListHelpers.hpp"
00047 #include "Teuchos_CommandLineProcessor.hpp"
00048 #include "Teuchos_StandardCatchMacros.hpp"
00049 #ifdef HAVE_MPI
00050 #  include "Epetra_MpiComm.h"
00051 #else
00052 #  include "Epetra_SerialComm.h"
00053 #endif
00054 
00055 
00056 namespace {
00057 
00058 
00059 // Helper function to compute a single norm for a vector
00060 double epetraNorm2( const Epetra_Vector &v )
00061 {
00062   double norm[1] = { -1.0 };
00063   v.Norm2(&norm[0]);
00064   return norm[0];
00065 }
00066 
00067 
00068 } // namespace
00069 
00070 
00071 int main(int argc, char* argv[])
00072 {
00073 
00074   using Teuchos::rcp;
00075   using Teuchos::RCP;
00076   using Teuchos::CommandLineProcessor;
00077   typedef Teuchos::ParameterList::PrintOptions PLPrintOptions;
00078 
00079   bool success = true;
00080   bool verbose = true;
00081 
00082   Teuchos::GlobalMPISession mpiSession(&argc, &argv);
00083 
00084   Teuchos::RCP<Teuchos::FancyOStream>
00085     out = Teuchos::VerboseObjectBase::getDefaultOStream();
00086 
00087   try {
00088 
00089 
00090     //
00091     // A) Program setup code
00092     //
00093 
00094     //
00095     // Read options from command-line
00096     //
00097 
00098     std::string     matrixFile             = "";
00099     std::string     extraParamsFile        = "";
00100     double          tol                    = 1e-5;
00101     bool            onlyPrintOptions       = false;
00102     bool            printXmlFormat         = false;
00103     bool            showDoc                = true;
00104 
00105     Stratimikos::DefaultLinearSolverBuilder linearSolverBuilder;
00106 
00107     CommandLineProcessor  clp(false); // Don't throw exceptions
00108 
00109     // Set up command-line options for the linear solver that will be used!
00110     linearSolverBuilder.setupCLP(&clp);
00111 
00112     clp.setOption( "matrix-file", &matrixFile
00113                    ,"Defines the matrix and perhaps the RHS and LHS for a linear system to be solved." );
00114     clp.setOption( "tol", &tol, "Tolerance to check against the scaled residual norm." );
00115     clp.setOption( "extra-params-file", &extraParamsFile, "File containing extra parameters in XML format.");
00116     clp.setOption( "only-print-options", "continue-after-printing-options", &onlyPrintOptions
00117                    ,"Only print options and stop or continue on" );
00118     clp.setOption( "print-xml-format", "print-readable-format", &printXmlFormat
00119                    ,"Print the valid options in XML format or in readable format." );
00120     clp.setOption( "show-doc", "hide-doc", &showDoc
00121                    ,"Print the valid options with or without documentation." );
00122 
00123     clp.setDocString(
00124       "Simple example for the use of the Stratimikos facade Stratimikos::DefaultLinearSolverBuilder.\n"
00125       "\n"
00126       "To print out just the valid options use --matrix-file=\"\" --only-print-options with --print-xml-format"
00127       " or --print-readable-format.\n"
00128       "\n"
00129       "To solve a linear system read from a file use --matrix-file=\"SomeFile.mtx\""
00130       " with options read from an XML file using --linear-solver-params-file=\"SomeFile.xml\"\n"
00131       );
00132 
00133     CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
00134     if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) return parse_return;
00135 
00136     //
00137     // Print out the valid options and stop if asked
00138     //
00139 
00140     if(onlyPrintOptions) {
00141       if(printXmlFormat)
00142         Teuchos::writeParameterListToXmlOStream(
00143           *linearSolverBuilder.getValidParameters()
00144           ,*out
00145           );
00146       else
00147         linearSolverBuilder.getValidParameters()->print(
00148           *out,PLPrintOptions().indent(2).showTypes(true).showDoc(showDoc)
00149           );
00150       return 0;
00151     }
00152 
00153 
00154     //
00155     // B) Epetra-specific code that sets up the linear system to be solved
00156     //
00157     // While the below code reads in the Epetra objects from a file, you can
00158     // setup the Epetra objects any way you would like.  Note that this next
00159     // set of code as nothing to do with Thyra at all, and it should not.
00160     //
00161 
00162     *out << "\nReading linear system in Epetra format from the file \'"<<matrixFile<<"\' ...\n";
00163 
00164 #ifdef HAVE_MPI
00165     Epetra_MpiComm comm(MPI_COMM_WORLD);
00166 #else
00167     Epetra_SerialComm comm;
00168 #endif
00169     RCP<Epetra_CrsMatrix> epetra_A;
00170     RCP<Epetra_Vector> epetra_x, epetra_b;
00171     EpetraExt::readEpetraLinearSystem( matrixFile, comm, &epetra_A, NULL, &epetra_x, &epetra_b );
00172 
00173     if(!epetra_b.get()) {
00174       *out << "\nThe RHS b was not read in so generate a new random vector ...\n";
00175       epetra_b = rcp(new Epetra_Vector(epetra_A->OperatorRangeMap()));
00176       epetra_b->Random();
00177     }
00178 
00179     if(!epetra_x.get()) {
00180       *out << "\nThe LHS x was not read in so generate a new zero vector ...\n";
00181       epetra_x = rcp(new Epetra_Vector(epetra_A->OperatorDomainMap()));
00182       epetra_x->PutScalar(0.0); // Initial guess is critical!
00183     }
00184 
00185     *out << "\nPrinting statistics of the Epetra linear system ...\n";
00186 
00187     *out
00188       << "\n  Epetra_CrsMatrix epetra_A of dimension "
00189       << epetra_A->OperatorRangeMap().NumGlobalElements()
00190       << " x " << epetra_A->OperatorDomainMap().NumGlobalElements()
00191       << "\n  ||epetraA||inf = " << epetra_A->NormInf()
00192       << "\n  ||epetra_b||2 = " << epetraNorm2(*epetra_b)
00193       << "\n  ||epetra_x||2 = " << epetraNorm2(*epetra_x)
00194       << "\n";
00195 
00196 
00197     //
00198     // C) The "Glue" code that takes Epetra objects and wraps them as Thyra
00199     // objects
00200     //
00201     // This next set of code wraps the Epetra objects that define the linear
00202     // system to be solved as Thyra objects so that they can be passed to the
00203     // linear solver.
00204     //
00205 
00206     RCP<const Thyra::LinearOpBase<double> > A = Thyra::epetraLinearOp( epetra_A );
00207     RCP<Thyra::VectorBase<double> > x = Thyra::create_Vector( epetra_x, A->domain() );
00208     RCP<const Thyra::VectorBase<double> > b = Thyra::create_Vector( epetra_b, A->range() );
00209 
00210     // Note that above Thyra is only interacted with in the most trival of
00211     // ways.  For most users, Thyra will only be seen as a thin wrapper that
00212     // they need know little about in order to wrap their objects in order to
00213     // pass them to Thyra-enabled solvers.
00214 
00215 
00216     //
00217     // D) Thyra-specific code for solving the linear system
00218     //
00219     // Note that this code has no mention of any concrete implementation and
00220     // therefore can be used in any use case.
00221     //
00222 
00223     // Reading in the solver parameters from the parameters file and/or from
00224     // the command line.  This was setup by the command-line options
00225     // set by the setupCLP(...) function above.
00226     linearSolverBuilder.readParameters(out.get());
00227 
00228     // Augment parameters if appropriate
00229     if(extraParamsFile.length()) {
00230       Teuchos::updateParametersFromXmlFile( "./"+extraParamsFile,
00231         linearSolverBuilder.getNonconstParameterList().ptr() );
00232     }
00233 
00234     // Create a linear solver factory given information read from the
00235     // parameter list.
00236     RCP<Thyra::LinearOpWithSolveFactoryBase<double> > lowsFactory =
00237       linearSolverBuilder.createLinearSolveStrategy("");
00238 
00239     // Setup output stream and the verbosity level
00240     lowsFactory->setOStream(out);
00241     lowsFactory->setVerbLevel(Teuchos::VERB_LOW);
00242 
00243     // Create a linear solver based on the forward operator A
00244     RCP<Thyra::LinearOpWithSolveBase<double> > lows =
00245       Thyra::linearOpWithSolve(*lowsFactory, A);
00246 
00247     // Solve the linear system (note: the initial guess in 'x' is critical)
00248     Thyra::SolveStatus<double> status =
00249       Thyra::solve<double>(*lows, Thyra::NOTRANS, *b, x.ptr());
00250     *out << "\nSolve status:\n" << status;
00251 
00252     // Write the linear solver parameters after they were read
00253     linearSolverBuilder.writeParamsFile(*lowsFactory);
00254 
00255 
00256     //
00257     // E) Post process the solution and check the error
00258     //
00259     // Note that the below code is based only on the Epetra objects themselves
00260     // and does not in any way depend or interact with any Thyra-based
00261     // objects.  The point is that most users of Thyra can largely gloss over
00262     // the fact that Thyra is really being used for anything.
00263     //
00264 
00265     // Wipe out the Thyra wrapper for x to guarantee that the solution will be
00266     // written back to epetra_x!  At the time of this writting this is not
00267     // really needed but the behavior may change at some point so this is a
00268     // good idea.
00269     x = Teuchos::null;
00270 
00271     *out
00272       << "\nSolution ||epetra_x||2 = " << epetraNorm2(*epetra_x) << "\n";
00273 
00274     *out << "\nTesting the solution error ||b-A*x||/||b|| computed through the Epetra objects ...\n";
00275 
00276     // r = b - A*x
00277     Epetra_Vector epetra_r(*epetra_b);
00278     {
00279       Epetra_Vector epetra_A_x(epetra_A->OperatorRangeMap());
00280       epetra_A->Apply(*epetra_x,epetra_A_x);
00281       epetra_r.Update(-1.0,epetra_A_x,1.0);
00282     }
00283 
00284     const double
00285       nrm_r = epetraNorm2(epetra_r),
00286       nrm_b = epetraNorm2(*epetra_b),
00287       rel_err = ( nrm_r / nrm_b );
00288     const bool
00289       passed = (rel_err <= tol);
00290 
00291     *out
00292       << "||b-A*x||/||b|| = " << nrm_r << "/" << nrm_b << " = " << rel_err
00293       << " < tol = " << tol << " ? " << ( passed ? "passed" : "failed" ) << "\n";
00294 
00295     if(!passed) success = false;
00296 
00297   }
00298   TEUCHOS_STANDARD_CATCH_STATEMENTS(verbose, std::cerr, success)
00299 
00300   if (verbose) {
00301     if(success)  *out << "\nCongratulations! All of the tests checked out!\n";
00302     else         *out << "\nOh no! At least one of the tests failed!\n";
00303   }
00304 
00305   return ( success ? EXIT_SUCCESS : EXIT_FAILURE );
00306 
00307 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines