|
Belos
Version of the Day
|
00001 //@HEADER 00002 // ************************************************************************ 00003 // 00004 // Belos: Block Linear Solvers Package 00005 // Copyright 2004 Sandia Corporation 00006 // 00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, 00008 // the U.S. Government retains certain rights in this software. 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 Michael A. Heroux (maherou@sandia.gov) 00038 // 00039 // ************************************************************************ 00040 //@HEADER 00041 00042 #include <BelosStatusTestCombo.hpp> 00043 #include <BelosStatusTestGenResNorm.hpp> 00044 #include <BelosStatusTestImpResNorm.hpp> 00045 #include <BelosStatusTestMaxIters.hpp> 00046 #include <Teuchos_ParameterList.hpp> 00047 00048 namespace Belos { 00049 00080 template<class Scalar, class MV, class OP> 00081 class StatusTestFactory { 00082 public: 00083 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType magnitude_type; 00084 typedef StatusTest<Scalar,MV,OP> base_test; 00085 typedef StatusTestGenResNorm<Scalar,MV,OP> res_norm_test; 00086 typedef StatusTestMaxIters<Scalar,MV,OP> max_iter_test; 00087 typedef StatusTestCombo<Scalar,MV,OP> combo_test; 00088 00138 static Teuchos::RCP<base_test> 00139 gmresTest (const magnitude_type convTol, 00140 const int maxIterCount, 00141 const bool haveLeftPreconditioner, 00142 const ScaleType implicitScaleType = Belos::NormOfPrecInitRes, 00143 const ScaleType explicitScaleType = Belos::NormOfInitRes, 00144 const int blockSize = 1, 00145 const int defQuorum = -1, 00146 const bool showMaxResNormOnly = false); 00147 00156 static Teuchos::RCP<base_test> 00157 gmresTest (const bool haveLeftPreconditioner, 00158 const Teuchos::RCP<Teuchos::ParameterList>& params); 00159 00184 static std::pair<bool, bool> 00185 changeConvTolAndMaxIters (const Teuchos::RCP<base_test>& test, 00186 const magnitude_type convTol, 00187 const int maxIterCount); 00188 00194 static bool 00195 changeMaxNumIters (const Teuchos::RCP<base_test>& test, 00196 const int maxIterCount); 00197 00203 static bool 00204 changeConvTol (const Teuchos::RCP<base_test>& test, 00205 const magnitude_type convTol); 00206 00219 static ScaleType 00220 stringToScaleType (const std::string& scaleType); 00221 00226 Teuchos::RCP<const Teuchos::ParameterList> getValidGmresParameters (); 00227 00228 private: 00230 Teuchos::RCP<const Teuchos::ParameterList> defaultGmresParams_; 00231 }; 00232 00233 00234 template<class Scalar, class MV, class OP> 00235 Teuchos::RCP<typename StatusTestFactory<Scalar, MV, OP>::base_test> 00236 StatusTestFactory<Scalar, MV, OP>:: 00237 gmresTest (const typename StatusTestFactory<Scalar, MV, OP>::magnitude_type convTol, 00238 const int maxIterCount, 00239 const bool haveLeftPreconditioner, 00240 const ScaleType implicitScaleType = NormOfPrecInitRes, 00241 const ScaleType explicitScaleType = NormOfInitRes, 00242 const int blockSize = 1, 00243 const int defQuorum = -1, 00244 const bool showMaxResNormOnly = false) 00245 { 00246 using Teuchos::null; 00247 using Teuchos::ParameterList; 00248 using Teuchos::RCP; 00249 using Teuchos::rcp; 00250 00251 TEUCHOS_TEST_FOR_EXCEPTION(blockSize < 1, std::invalid_argument, 00252 "blockSize (= " << blockSize << ") must be >= 1."); 00253 TEUCHOS_TEST_FOR_EXCEPTION(defQuorum > blockSize, std::invalid_argument, 00254 "defQuorum (= " << defQuorum << ") may be no larger " 00255 "than blockSize (= " << blockSize << ")."); 00256 00257 // The "implicit" residual test checks the "native" residual 00258 // norm to determine if convergence was achieved. It is less 00259 // expensive than the "explicit" residual test. 00260 RCP<res_norm_test> implicitTest 00261 = rcp (new res_norm_test (convTol, defQuorum)); 00262 implicitTest->defineScaleForm (stringToScaleType (implicitScaleType), 00263 Belos::TwoNorm); 00264 implicitTest->setShowMaxResNormOnly (showMaxResNormOnly); 00265 00266 // If there's a left preconditioner, create a combined status 00267 // test that check first the "explicit," then the "implicit" 00268 // residual norm, requiring that both have converged to within 00269 // the specified tolerance. Otherwise, we only perform the 00270 // "implicit" test. 00271 RCP<res_norm_test> explicitTest; 00272 if (haveLeftPreconditioner) { // ! problem_->getLeftPrec().is_null() 00273 explicitTest = rcp (new res_norm_test (convTol, defQuorum)); 00274 explicitTest->defineResForm (res_norm_test::Explicit, Belos::TwoNorm); 00275 explicitTest->defineScaleForm (stringToScaleType (explicitScaleType), 00276 Belos::TwoNorm); 00277 explicitTest->setShowMaxResNormOnly (showMaxResNormOnly); 00278 } 00279 else { 00280 explicitTest = null; 00281 } 00282 00283 // Full convergence test: 00284 // 00285 // First, the implicit residual norm test, 00286 // Followed by the explicit residual norm test if applicable, 00287 // Followed by the user-defined convergence test if supplied. 00288 RCP<base_test> convTest; 00289 if (explicitTest.is_null()) { 00290 convTest = implicitTest; 00291 } 00292 else { 00293 // The "explicit" residual test is only performed once the 00294 // native ("implicit") residual is below the convergence 00295 // tolerance. 00296 convTest = rcp (new combo_test (combo_test::SEQ, 00297 implicitTest, 00298 explicitTest)); 00299 } 00300 00301 // Stopping criterion for maximum number of iterations. 00302 RCP<max_iter_test> maxIterTest = rcp (new max_iter_test (maxIterCount)); 00303 00304 // The "final" stopping criterion: 00305 // 00306 // Either we've run out of iterations, OR we've converged. 00307 return rcp (new combo_test (combo_test::OR, maxIterTest, convTest)); 00308 } 00309 00310 00311 template<class Scalar, class MV, class OP> 00312 Teuchos::RCP<typename StatusTestFactory<Scalar, MV, OP>::base_test> 00313 StatusTestFactory<Scalar, MV, OP>:: 00314 gmresTest (const bool haveLeftPreconditioner, 00315 const Teuchos::RCP<Teuchos::ParameterList>& params) 00316 { 00317 using Teuchos::Exceptions::InvalidParameter; 00318 using std::string; 00319 typedef Teuchos::ScalarTraits<magnitude_type> STM; 00320 00321 // "Convergence Tolerance" is a required parameter and must be 00322 // nonnegative. 00323 const magnitude_type convTol = 00324 params->get<magnitude_type> ("Convergence Tolerance"); 00325 TEUCHOS_TEST_FOR_EXCEPTION(convTol < STM::zero(), std::invalid_argument, 00326 "Convergence tolerance " << convTol 00327 << " is negative."); 00328 // "Maximum Iterations" is a required parameter and must be nonnegative. 00329 const int maxIterCount = params->get<int> ("Maximum Iterations"); 00330 TEUCHOS_TEST_FOR_EXCEPTION(maxIterCount < 0, std::invalid_argument, 00331 "Maximum number of iterations " << maxIterCount 00332 << " is negative."); 00333 00334 // PseudoBlockGmresSolMgr uses as defaults the preconditioned 00335 // initial residual for the implicit test, and the 00336 // unpreconditioned initial residual for the explicit test. 00337 ScaleType implicitScaleType = NormOfPrecInitRes; 00338 { 00339 const std::string defaultImplicitScaleType ("Norm of Preconditioned Initial Residual"); 00340 implicitScaleType = stringToScaleType (params->get ("Implicit Residual Scaling", defaultImplicitScaleType)); 00341 } 00342 ScaleType explicitScaleType = NormOfInitRes; 00343 { 00344 const std::string defaultExplicitScaleType ("Norm of Initial Residual"); 00345 explicitScaleType = stringToScaleType (params->get ("Explicit Residual Scaling", defaultExplicitScaleType)); 00346 } 00347 const int defaultBlockSize = 1; 00348 int blockSize = params->get ("Block Size", defaultBlockSize); 00349 00350 const int defaultDefQuorum = -1; 00351 int defQuorum = params->get ("Deflation Quorum", defaultDefQuorum); 00352 00353 const bool defaultShowMaxResNormOnly = false; 00354 bool showMaxResNormOnly = params->get ("Show Maximum Residual Norm Only", defaultShowMaxResNormOnly); 00355 00356 return gmresTest (convTol, maxIterCount, haveLeftPreconditioner, 00357 implicitScaleType, explicitScaleType, blockSize, 00358 defQuorum, showMaxResNormOnly); 00359 } 00360 00361 template<class Scalar, class MV, class OP> 00362 Teuchos::RCP<const Teuchos::ParameterList> 00363 getValidGmresParameters () 00364 { 00365 using Teuchos::ParameterList; 00366 using Teuchos::parameterList; 00367 using Teuchos::RCP; 00368 typedef Teuchos::ScalarTraits<Scalar> STS; 00369 typedef Teuchos::ScalarTraits<magnitude_type> STM; 00370 00371 if (defaultGmresParams_.is_null()) { 00372 // These two parameters are required. We supply defaults only 00373 // as examples. 00374 const magnitude_type convTol = STS::squareroot (STS::eps()); 00375 const int maxIterCount = 200; 00376 00377 // PseudoBlockGmresSolMgr uses as defaults the preconditioned 00378 // initial residual for the implicit test, and the 00379 // unpreconditioned initial residual for the explicit test. We 00380 // take these as the standard for all GMRES variants. 00381 const std::string defaultImplicitScaleType ("Norm of Preconditioned Initial Residual"); 00382 const std::string defaultExplicitScaleType ("Norm of Initial Residual"); 00383 const int defaultBlockSize = 1; 00384 const int defaultDefQuorum = -1; 00385 const bool defaultShowMaxResNormOnly = false; 00386 00387 RCP<ParameterList> params = parameterList (); 00388 params->set ("Convergence Tolerance", convTol); 00389 params->set ("Maximum Iterations", maxIterCount); 00390 params->set ("Implicit Residual Scaling", defaultImplicitScaleType); 00391 params->set ("Explicit Residual Scaling", defaultExplicitScaleType); 00392 params->set ("Block Size", defaultBlockSize); 00393 params->set ("Deflation Quorum", defaultDefQuorum); 00394 params->set ("Show Maximum Residual Norm Only", defaultShowMaxResNormOnly); 00395 00396 defaultGmresParams_ = params; 00397 } 00398 return defaultGmresParams_; 00399 } 00400 00401 00402 template<class Scalar, class MV, class OP> 00403 bool 00404 StatusTestFactory<Scalar, MV, OP>:: 00405 changeMaxNumIters (const Teuchos::RCP<typename StatusTestFactory<Scalar, MV, OP>::base_test>& test, 00406 const int maxIterCount) 00407 { 00408 using Teuchos::rcp_dynamic_cast; 00409 using Teuchos::nonnull; 00410 using Teuchos::RCP; 00411 using Teuchos::rcp; 00412 00413 // We declare "success" if the test or at least one of its 00414 // children (if it's a combo_test) is a max_iter_test. 00415 bool success = false; 00416 RCP<max_iter_test> maxIterTest = rcp_dynamic_cast<max_iter_test> (test); 00417 if (nonnull (maxIterTest)) 00418 { 00419 test->setMaxIters (maxIterCount); 00420 success = true; 00421 } 00422 else 00423 { 00424 RCP<combo_test> comboTest = rcp_dynamic_cast<combo_test> (test); 00425 if (nonnull (comboTest)) 00426 { 00427 typedef typename combo_test::st_vector st_vector; 00428 typedef typename st_vector::size_type size_type; 00429 st_vector tests = test->getStatusTests (); 00430 // We could use boost lambda to remove this for loop. 00431 // Standard STL doesn't have a version of mem_fun for 00432 // member functions that take > 1 argument. 00433 for (size_type k = 0; result || k < tests.end(); ++k) 00434 { // Recurse on all children, since it's possible for 00435 // more than one child to be a max_iter_test. 00436 const bool result = 00437 changeMaxNumIters (tests[k], maxIterCount); 00438 success = result || success; 00439 } 00440 } 00441 } 00442 return success; 00443 } 00444 00445 template<class Scalar, class MV, class OP> 00446 std::pair<bool, bool> 00447 StatusTestFactory<Scalar, MV, OP>:: 00448 changeConvTolAndMaxNumIters (const Teuchos::RCP<typename StatusTestFactory<Scalar, MV, OP>::base_test>& test, 00449 const typename StatusTestFactory<Scalar, MV, OP>::magnitude_type convTol, 00450 const int maxIterCount) 00451 { 00452 using Teuchos::rcp_dynamic_cast; 00453 using Teuchos::nonnull; 00454 using Teuchos::RCP; 00455 using Teuchos::rcp; 00456 typedef StatusTestResNorm<Scalar,MV,OP> res_norm_base_test; 00457 RCP<max_iter_test> maxIterTest = rcp_dynamic_cast<max_iter_test> (test); 00458 00459 // We declare "success" if we encountered a res_norm_base_test 00460 // _and_ a max_iter_test somewhere along the recursion path. 00461 bool foundResNormTest = false; 00462 bool foundMaxIterTest = false; 00463 00464 RCP<res_norm_base_test> normTest = 00465 rcp_dynamic_cast<res_norm_base_test> (test); 00466 if (nonnull (normTest)) 00467 { 00468 // NOTE (mfh 03 Mar 2011) setTolerance() returns an int 00469 // result. However, all subclasses' implementations return 0 00470 // here, and all of them always (re)set the tolerance, so I 00471 // think it's OK to ignore the result. 00472 (void) test->setTolerance (convTol); 00473 foundResNormTest = true; 00474 } 00475 else 00476 { 00477 RCP<max_iter_test> maxIterTest = 00478 rcp_dynamic_cast<max_iter_test> (test); 00479 if (nonnull (maxIterTest)) 00480 { 00481 test->setMaxIters (maxIterCount); 00482 foundMaxIterTest = true; 00483 } 00484 } 00485 if (! foundResNormTest && ! foundMaxIterTest) 00486 { 00487 RCP<combo_test> comboTest = rcp_dynamic_cast<combo_test> (test); 00488 if (nonnull (comboTest)) 00489 { 00490 typedef typename combo_test::st_vector st_vector; 00491 typedef typename st_vector::size_type size_type; 00492 st_vector tests = test->getStatusTests (); 00493 // We could use boost lambda to remove this for loop. 00494 // Standard STL doesn't have a version of mem_fun for 00495 // member functions that take > 1 argument. 00496 for (size_type k = 0; result || k < tests.end(); ++k) 00497 { // Recurse on all children. 00498 const std::pair<bool, bool> result = 00499 changeConvTolAndMaxIters (tests[k], convTol, maxIterCount); 00500 foundResNormTest = result.first || foundResNormTest; 00501 foundMaxIterTest = result.second || foundMaxIterTest; 00502 } 00503 } 00504 } 00505 return std::make_pair (foundResNormTest, foundMaxIterTest); 00506 } 00507 00508 template<class Scalar, class MV, class OP> 00509 bool 00510 StatusTestFactory<Scalar, MV, OP>:: 00511 changeConvTol (const Teuchos::RCP<typename StatusTestFactory<Scalar, MV, OP>::base_test>& test, 00512 const typename StatusTestFactory<Scalar, MV, OP>::magnitude_type convTol) 00513 { 00514 using Teuchos::rcp_dynamic_cast; 00515 using Teuchos::nonnull; 00516 using Teuchos::RCP; 00517 using Teuchos::rcp; 00518 typedef StatusTestResNorm<Scalar,MV,OP> res_norm_base_test; 00519 00520 // We declare "success" if the test or at least one of its 00521 // children (if it's a combo_test) is a res_norm_base_test. 00522 bool success = false; 00523 RCP<res_norm_base_test> normTest = 00524 rcp_dynamic_cast<res_norm_base_test> (test); 00525 if (nonnull (normTest)) 00526 { 00527 // NOTE (mfh 03 Mar 2011) setTolerance() returns an int 00528 // result. However, all subclasses' implementations return 0 00529 // here, and all of them always (re)set the tolerance, so I 00530 // think it's OK to ignore the result. 00531 (void) test->setTolerance (convTol); 00532 success = true; 00533 } 00534 else 00535 { 00536 RCP<combo_test> comboTest = rcp_dynamic_cast<combo_test> (test); 00537 if (nonnull (comboTest)) 00538 { 00539 typedef typename combo_test::st_vector st_vector; 00540 typedef typename st_vector::size_type size_type; 00541 st_vector tests = test->getStatusTests (); 00542 // We could use boost lambda to remove this for loop. 00543 // Standard STL doesn't have a version of mem_fun for 00544 // member functions that take > 1 argument. 00545 for (size_type k = 0; result || k < tests.end(); ++k) 00546 { // Recurse on all children, since it's possible for 00547 // more than one child to be a res_norm_base_test. 00548 const bool result = changeConvTol (tests[k], convTol); 00549 success = result || success; 00550 } 00551 } 00552 } 00553 return success; 00554 } 00555 00556 00557 template<class Scalar, class MV, class OP> 00558 static ScaleType 00559 StatusTestFactory<Scalar, MV, OP>:: 00560 stringToScaleType (const std::string& scaleType) 00561 { 00562 const char* validNames[] = { 00563 "Norm of Initial Residual", 00564 "Norm of Preconditioned Initial Residual", 00565 "Norm of RHS", 00566 "Norm of Right-Hand Side", 00567 "None" 00568 }; 00569 const int numValidNames = 5; 00570 const ScaleType correspondingOutputs[] = { 00571 Belos::NormOfInitRes, 00572 Belos::NormOfPrecInitRes, 00573 Belos::NormOfRHS, 00574 Belos::NormOfRHS, 00575 Belos::None 00576 }; 00577 for (int k = 0; k < numValidNames; ++k) 00578 { 00579 if (scaleType == validNames[k]) 00580 return correspondingOutputs[k]; 00581 } 00582 TEUCHOS_TEST_FOR_EXCEPTION (true, std::logic_error, 00583 "Invalid residual scaling type \"" << scaleType 00584 << "\"."); 00585 } 00586 00587 } // namespace Belos
1.7.6.1