|
Stratimikos Package Browser (Single Doxygen Collection)
Version of the Day
|
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", ¶msFile, 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 }
1.7.6.1