Belos Version of the Day
BelosStatusTestFactory.hpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines