Stratimikos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
MixedOrderPhysicsBasedPreconditioner.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 "Thyra_LinearOpWithSolveFactoryHelpers.hpp"
00044 #include "Thyra_PreconditionerFactoryHelpers.hpp"
00045 #include "Thyra_DefaultInverseLinearOp.hpp"
00046 #include "Thyra_DefaultMultipliedLinearOp.hpp"
00047 #include "Thyra_EpetraThyraWrappers.hpp"
00048 #include "Thyra_EpetraLinearOp.hpp"
00049 #include "Thyra_get_Epetra_Operator.hpp"
00050 #include "Thyra_TestingTools.hpp"
00051 #include "EpetraExt_CrsMatrixIn.h"
00052 #include "Epetra_CrsMatrix.h"
00053 #include "Teuchos_GlobalMPISession.hpp"
00054 #include "Teuchos_VerboseObject.hpp"
00055 #include "Teuchos_XMLParameterListHelpers.hpp"
00056 #include "Teuchos_CommandLineProcessor.hpp"
00057 #include "Teuchos_StandardCatchMacros.hpp"
00058 #include "Teuchos_TimeMonitor.hpp"
00059 #ifdef HAVE_MPI
00060 #  include "Epetra_MpiComm.h"
00061 #else
00062 #  include "Epetra_SerialComm.h"
00063 #endif
00064 
00065 
00075 namespace {
00076 
00077 
00078 // Read a Epetra_CrsMatrix from a Matrix market file
00079 Teuchos::RCP<Epetra_CrsMatrix>
00080 readEpetraCrsMatrixFromMatrixMarket(
00081   const std::string fileName, const Epetra_Comm &comm
00082   )
00083 {
00084   Epetra_CrsMatrix *A = 0;
00085   TEUCHOS_TEST_FOR_EXCEPTION(
00086     0!=EpetraExt::MatrixMarketFileToCrsMatrix( fileName.c_str(), comm, A ),
00087     std::runtime_error,
00088     "Error, could not read matrix file \""<<fileName<<"\"!"
00089     );
00090   return Teuchos::rcp(A);
00091 }
00092 
00093 
00094 // Read an Epetra_CrsMatrix in as a wrapped Thyra::EpetraLinearOp object
00095 Teuchos::RCP<const Thyra::LinearOpBase<double> >
00096 readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
00097   const std::string fileName, const Epetra_Comm &comm,
00098   const std::string &label
00099   )
00100 {
00101   return Thyra::epetraLinearOp(
00102     readEpetraCrsMatrixFromMatrixMarket(fileName,comm),label
00103     );
00104 }
00105 
00106 
00107 } // namespace
00108 
00109 
00110 int main(int argc, char* argv[])
00111 {
00112 
00113   using Teuchos::describe;
00114   using Teuchos::rcp;
00115   using Teuchos::rcp_dynamic_cast;
00116   using Teuchos::rcp_const_cast;
00117   using Teuchos::RCP;
00118   using Teuchos::CommandLineProcessor;
00119   using Teuchos::ParameterList;
00120   using Teuchos::sublist;
00121   typedef ParameterList::PrintOptions PLPrintOptions;
00122   using Thyra::inverse;
00123   using Thyra::initializePreconditionedOp;
00124   using Thyra::initializeOp;
00125   using Thyra::unspecifiedPrec;
00126   using Thyra::solve;
00127   typedef RCP<const Thyra::LinearOpBase<double> > LinearOpPtr;
00128   typedef RCP<Thyra::VectorBase<double> > VectorPtr;
00129 
00130   bool success = true;
00131   bool verbose = true;
00132 
00133   Teuchos::GlobalMPISession mpiSession(&argc,&argv);
00134 
00135   Teuchos::RCP<Teuchos::FancyOStream>
00136     out = Teuchos::VerboseObjectBase::getDefaultOStream();
00137 
00138   try {
00139 
00140     //
00141     // Read in options from the command line
00142     //
00143 
00144     const int numVerbLevels = 6;
00145     Teuchos::EVerbosityLevel
00146       verbLevelValues[] =
00147       {
00148         Teuchos::VERB_DEFAULT, Teuchos::VERB_NONE,
00149         Teuchos::VERB_LOW, Teuchos::VERB_MEDIUM,
00150         Teuchos::VERB_HIGH, Teuchos::VERB_EXTREME
00151       };
00152     const char*
00153       verbLevelNames[] =
00154       { "default", "none", "low", "medium", "high", "extreme" };
00155 
00156     Teuchos::EVerbosityLevel verbLevel = Teuchos::VERB_MEDIUM;
00157     std::string paramsFile = "";
00158     std::string extraParamsFile = "";
00159     std::string baseDir = ".";
00160     bool useP1Prec = true;
00161     bool invertP1 = false;
00162     bool showParams = false;
00163     double solveTol = 1e-8;
00164 
00165     CommandLineProcessor clp(false); // Don't throw exceptions
00166 
00167     clp.setOption( "verb-level", &verbLevel,
00168       numVerbLevels, verbLevelValues, verbLevelNames,
00169       "Verbosity level used for all objects."
00170       );
00171     clp.setOption( "params-file", &paramsFile,
00172       "File containing parameters in XML format.",
00173       true // Required
00174       );
00175     clp.setOption( "extra-params-file", &extraParamsFile,
00176       "File containing extra parameters in XML format."
00177       );
00178     clp.setOption( "base-dir", &baseDir,
00179       "Base directory for all of the files."
00180       );
00181     clp.setOption( "use-P1-prec", "use-algebraic-prec", &useP1Prec,
00182       "Use the physics-based preconditioner for P2 based on P1 or just an algebraic preconditioner"
00183       );
00184     clp.setOption( "invert-P1", "prec-P1-only", &invertP1,
00185       "In the physics-based preconditioner, use P1's preconditioner or fully invert P1."
00186       );
00187     clp.setOption( "solve-tol", &solveTol,
00188       "Tolerance for the solution to determine success or failure!"
00189       );
00190     clp.setOption( "show-params", "no-show-params", &showParams,
00191       "Show the parameter list or not."
00192       );
00193     clp.setDocString(
00194       "This example program shows an attempt to create a physics-based\n"
00195       "preconditioner using the building blocks of Stratimikos and Thyra\n"
00196       "implicit linear operators.  The idea is to use the linear operator\n"
00197       "for first-order Lagrange finite elements as the preconditioner for the\n"
00198       "operator using second-order Lagrange finite elements.  The details of the\n"
00199       "PDE being represented, the mesh being used, or the boundary conditions are\n"
00200       "beyond the scope of this example.\n"
00201       "\n"
00202       "The matrices used in this example are:\n"
00203       "\n"
00204       "  P2: The discretized PDE matrix using second-order Lagrange finite elements.\n"
00205       "  P1: The discretized PDE matrix using first-order Lagrange finite elements.\n"
00206       "  M22: The mass matrix for the second-order Lagrange finite-element basis functions.\n"
00207       "  M11: The mass matrix for the first-order Lagrange finite-element basis functions.\n"
00208       "  M21: A rectangular matrix that uses mixed first- and second-order basis functions\n"
00209       "       to map from P2 space to P1 space.\n"
00210       "  M12: A rectangular matrix that uses mixed first- and second-order basis functions\n"
00211       "       to map from P1 space to P2 space.\n"
00212       "\n"
00213       "The above matrices are read from Matrix Market *.mtx files in the directory given by\n"
00214       "the --base-dir command-line option.\n"
00215       "\n"
00216       "The preconditioner operator created in this example program is:\n"
00217       "\n"
00218       "   precP2Op = (inv(M22) * M12) * prec(P1) * (inv(M11) * M21)\n"
00219       "\n"
00220       "where prec(P1) is either the algebraic preconditioner for P1 (--prec-P1-only)\n"
00221       "or is a full solve for P1 (--invert-P1).\n"
00222       "\n"
00223       "We use Stratimikos to specify the linear solvers and/or algebraic\n"
00224       "preconditioners and we use the Thyra implicit operators to build the\n"
00225       "implicitly multiplied linear operators associated with the preconditioner.\n"
00226       "\n"
00227       "Warning!  This physics-based preconditioner is singular and can not\n"
00228       "be used to solve the linear system given a random right-hand side.  However,\n"
00229       "singular or not, this example shows how one can use Thyra/Stratimikos to quickly\n"
00230       "try out these types of preconditioning ideas (even if they do not work).\n"
00231       );
00232 
00233     // Note: Use --help on the command line to see the above documentation
00234 
00235     CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
00236     if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) return parse_return;
00237 
00238 
00239     //
00240     *out << "\nA) Reading in Epetra_CrsMatrix objects for P1, P2, M11, M12, M21, and M22 ...\n";
00241     //
00242 
00243 #ifdef HAVE_MPI
00244     Epetra_MpiComm comm(MPI_COMM_WORLD);
00245 #else
00246     Epetra_SerialComm comm;
00247 #endif
00248 
00249     LinearOpPtr P1=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
00250       baseDir+"/P1.mtx",comm,"P1");
00251     *out << "\nP1 = " << describe(*P1,verbLevel) << "\n";
00252     LinearOpPtr P2= readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
00253       baseDir+"/P2.mtx",comm,"P2");
00254     *out << "\nP2 = " << describe(*P2,verbLevel) << "\n";
00255     LinearOpPtr M11=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
00256       baseDir+"/M11.mtx",comm,"M11");
00257     *out << "\nM11 = " << describe(*M11,verbLevel) << "\n";
00258     LinearOpPtr M22=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
00259       baseDir+"/M22.mtx",comm,"M22");
00260     *out << "\nM22 = " << describe(*M22,verbLevel) << "\n";
00261     LinearOpPtr M12=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
00262       baseDir+"/M12.mtx",comm,"M12");
00263     *out << "\nM12 = " << describe(*M12,verbLevel) << "\n";
00264     LinearOpPtr M21=readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
00265       baseDir+"/M21.mtx",comm,"M21");
00266     *out << "\nM21 = " << describe(*M21,verbLevel) << "\n";
00267 
00268     // ToDo: Replace the above functions with a general Thyra strategy object
00269     // to do the reading
00270 
00271     //
00272     *out << "\nB) Get the preconditioner and/or linear solver strategies to invert M11, M22, P1, and P2 ...\n";
00273     //
00274 
00275     //
00276     // Get separate parameter sublists for each square operator separately
00277     // that specify the type of linear solver and/or preconditioner to use.
00278     //
00279 
00280     RCP<ParameterList> paramList =
00281       Teuchos::getParametersFromXmlFile( baseDir+"/"+paramsFile );
00282     if (extraParamsFile.length()) {
00283       Teuchos::updateParametersFromXmlFile( baseDir+"/"+extraParamsFile, paramList.ptr() );
00284     }
00285     if (showParams) {
00286       *out << "\nRead in parameter list:\n\n";
00287       paramList->print(*out,PLPrintOptions().indent(2).showTypes(true));
00288     }
00289 
00290     Stratimikos::DefaultLinearSolverBuilder M11_linsolve_strategy_builder;
00291     M11_linsolve_strategy_builder.setParameterList(
00292       sublist(paramList,"M11 Solver",true) );
00293 
00294     Stratimikos::DefaultLinearSolverBuilder M22_linsolve_strategy_builder;
00295     M22_linsolve_strategy_builder.setParameterList(
00296       sublist(paramList,"M22 Solver",true) );
00297 
00298     Stratimikos::DefaultLinearSolverBuilder P1_linsolve_strategy_builder;
00299     P1_linsolve_strategy_builder.setParameterList(
00300       sublist(paramList,"P1 Solver",true) );
00301 
00302     Stratimikos::DefaultLinearSolverBuilder P2_linsolve_strategy_builder;
00303     P2_linsolve_strategy_builder.setParameterList(
00304       sublist(paramList,"P2 Solver",true) );
00305 
00306     //
00307     // Create the linear solver and/or preconditioner strategies
00308     // (i.e. factories)
00309     //
00310 
00311     // For M11 and M22, we want full linear solver factories with embedded
00312     // algebraic preconditioner factories.
00313 
00314     RCP<const Thyra::LinearOpWithSolveFactoryBase<double> > M11_linsolve_strategy
00315       = createLinearSolveStrategy(M11_linsolve_strategy_builder);
00316 
00317     RCP<Thyra::LinearOpWithSolveFactoryBase<double> > M22_linsolve_strategy
00318       = createLinearSolveStrategy(M22_linsolve_strategy_builder);
00319 
00320     // For P1, we only want its preconditioner factory.
00321 
00322     RCP<const Thyra::LinearOpWithSolveFactoryBase<double> > P1_linsolve_strategy;
00323     RCP<const Thyra::PreconditionerFactoryBase<double> > P1_prec_strategy;
00324     if(invertP1)
00325       P1_linsolve_strategy
00326         = createLinearSolveStrategy(P1_linsolve_strategy_builder);
00327     else
00328       P1_prec_strategy
00329         = createPreconditioningStrategy(P1_linsolve_strategy_builder);
00330 
00331     // For P2, we only want a linear solver factory.  We will supply the
00332     // preconditioner ourselves (that is the whole point of this example).
00333 
00334     RCP<const Thyra::LinearOpWithSolveFactoryBase<double> > P2_linsolve_strategy
00335       = createLinearSolveStrategy(P2_linsolve_strategy_builder);
00336 
00337     //
00338     *out << "\nC) Create the physics-based preconditioner! ...\n";
00339     //
00340 
00341     *out << "\nCreating inv(M11) ...\n";
00342     LinearOpPtr invM11 = inverse(*M11_linsolve_strategy, M11);
00343     *out << "\ninvM11 = " << describe(*invM11,verbLevel) << "\n";
00344 
00345     *out << "\nCreating inv(M22) ...\n";
00346     LinearOpPtr invM22 = inverse(*M22_linsolve_strategy, M22);
00347     *out << "\ninvM22 = " << describe(*invM22,verbLevel) << "\n";
00348 
00349     *out << "\nCreating prec(P1) ...\n";
00350     LinearOpPtr invP1;
00351     if(invertP1) {
00352       *out << "\nCreating prec(P1) as a full solver ...\n";
00353       invP1 = inverse(*P1_linsolve_strategy, P1);
00354     }
00355     else {
00356       *out << "\nCreating prec(P1) as just an algebraic preconditioner ...\n";
00357       RCP<Thyra::PreconditionerBase<double> >
00358         precP1 = prec(*P1_prec_strategy,P1);
00359       *out << "\nprecP1 = " << describe(*precP1,verbLevel) << "\n";
00360       invP1 = precP1->getUnspecifiedPrecOp();
00361     }
00362     rcp_const_cast<Thyra::LinearOpBase<double> >(
00363       invP1)->setObjectLabel("invP1"); // Cast to set label ...
00364     *out << "\ninvP1 = " << describe(*invP1,verbLevel) << "\n";
00365 
00366     LinearOpPtr P2ToP1 = multiply( invM11, M21 );
00367     *out << "\nP2ToP1 = " << describe(*P2ToP1,verbLevel) << "\n";
00368 
00369     LinearOpPtr P1ToP2 = multiply( invM22, M12 );
00370     *out << "\nP1ToP2 = " << describe(*P1ToP2,verbLevel) << "\n";
00371 
00372     LinearOpPtr precP2Op = multiply( P1ToP2, invP1, P2ToP1 );
00373     *out << "\nprecP2Op = " << describe(*precP2Op,verbLevel) << "\n";
00374 
00375     //
00376     *out << "\nD) Setup the solver for P2 ...\n";
00377     //
00378 
00379     RCP<Thyra::LinearOpWithSolveBase<double> >
00380       P2_lows = P2_linsolve_strategy->createOp();
00381     if(useP1Prec) {
00382       *out << "\nCreating the solver P2 using the specialized precP2Op\n";
00383       initializePreconditionedOp<double>( *P2_linsolve_strategy, P2,
00384         unspecifiedPrec(precP2Op), P2_lows.ptr());
00385     }
00386     else {
00387       *out << "\nCreating the solver P2 using algebraic preconditioner\n";
00388       initializeOp(*P2_linsolve_strategy, P2, P2_lows.ptr());
00389     }
00390     *out << "\nP2_lows = " << describe(*P2_lows, verbLevel) << "\n";
00391 
00392     //
00393     *out << "\nE) Solve P2 for a random RHS ...\n";
00394     //
00395 
00396     VectorPtr x = createMember(P2->domain());
00397     VectorPtr b = createMember(P2->range());
00398     Thyra::randomize(-1.0, +1.0, b.ptr());
00399     Thyra::assign(x.ptr(), 0.0); // Must give an initial guess!
00400 
00401     Thyra::SolveStatus<double>
00402       solveStatus = solve<double>( *P2_lows, Thyra::NOTRANS, *b, x.ptr() );
00403 
00404     *out << "\nSolve status:\n" << solveStatus;
00405 
00406     *out << "\nSolution ||x|| = " << Thyra::norm(*x) << "\n";
00407 
00408     if(showParams) {
00409       *out << "\nParameter list after use:\n\n";
00410       paramList->print(*out, PLPrintOptions().indent(2).showTypes(true));
00411     }
00412 
00413     //
00414     *out << "\nF) Checking the error in the solution of r=b-P2*x ...\n";
00415     //
00416 
00417     VectorPtr P2x = Thyra::createMember(b->space());
00418     Thyra::apply( *P2, Thyra::NOTRANS, *x, P2x.ptr() );
00419     VectorPtr r = Thyra::createMember(b->space());
00420     Thyra::V_VmV<double>(r.ptr(), *b, *P2x);
00421 
00422     double
00423       P2x_nrm = Thyra::norm(*P2x),
00424       r_nrm = Thyra::norm(*r),
00425       b_nrm = Thyra::norm(*b),
00426       r_nrm_over_b_nrm = r_nrm / b_nrm;
00427 
00428     bool result = r_nrm_over_b_nrm <= solveTol;
00429     if(!result) success = false;
00430 
00431     *out
00432       << "\n||P2*x|| = " << P2x_nrm << "\n";
00433 
00434     *out
00435       << "\n||P2*x-b||/||b|| = " << r_nrm << "/" << b_nrm
00436       << " = " << r_nrm_over_b_nrm << " <= " << solveTol
00437       << " : " << Thyra::passfail(result) << "\n";
00438 
00439     Teuchos::TimeMonitor::summarize(*out<<"\n");
00440   }
00441   TEUCHOS_STANDARD_CATCH_STATEMENTS(verbose,std::cerr,success)
00442 
00443   if (verbose) {
00444     if(success)  *out << "\nCongratulations! All of the tests checked out!\n";
00445     else         *out << "\nOh no! At least one of the tests failed!\n";
00446   }
00447 
00448   return ( success ? EXIT_SUCCESS : EXIT_FAILURE );
00449 
00450 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines