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<const 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 
00189 
00195     static bool
00196     changeMaxNumIters (const Teuchos::RCP<base_test>& test, 
00197            const int maxIterCount);
00198 
00204     static bool
00205     changeConvTol (const Teuchos::RCP<base_test>& test, 
00206        const magnitude_type convTol);
00207 
00220     static ScaleType
00221     stringToScaleType (const std::string& scaleType);
00222   };
00223 
00224 
00225   template<class Scalar, class MV, class OP>
00226   Teuchos::RCP<typename StatusTestFactory<Scalar, MV, OP>::base_test>
00227   StatusTestFactory<Scalar, MV, OP>::
00228   gmresTest (const typename StatusTestFactory<Scalar, MV, OP>::magnitude_type convTol,
00229        const int maxIterCount,
00230        const bool haveLeftPreconditioner,
00231        const ScaleType implicitScaleType = NormOfPrecInitRes,
00232        const ScaleType explicitScaleType = NormOfInitRes,
00233        const int blockSize = 1,
00234        const int defQuorum = -1,
00235        const bool showMaxResNormOnly = false)
00236   {
00237     using Teuchos::null;
00238     using Teuchos::ParameterList;
00239     using Teuchos::RCP;
00240     using Teuchos::rcp;
00241 
00242     TEST_FOR_EXCEPTION(blockSize < 1, std::invalid_argument,
00243            "blockSize (= " << blockSize << ") must be >= 1.");
00244     TEST_FOR_EXCEPTION(defQuorum > blockSize, std::invalid_argument,
00245            "defQuorum (= " << defQuorum << ") may be no larger "
00246            "than blockSize (= " << blockSize << ").");
00247 
00248     // The "implicit" residual test checks the "native" residual
00249     // norm to determine if convergence was achieved.  It is less
00250     // expensive than the "explicit" residual test.
00251     RCP<res_norm_test> implicitTest 
00252       = rcp (new res_norm_test (convTol, defQuorum));
00253     implicitTest->defineScaleForm (stringToScaleType (implicitScaleType), 
00254            Belos::TwoNorm);
00255     implicitTest->setShowMaxResNormOnly (showMaxResNormOnly);
00256 
00257     // If there's a left preconditioner, create a combined status
00258     // test that check first the "explicit," then the "implicit"
00259     // residual norm, requiring that both have converged to within
00260     // the specified tolerance.  Otherwise, we only perform the
00261     // "implicit" test.
00262     RCP<res_norm_test> explicitTest;
00263     if (haveLeftPreconditioner) // ! problem_->getLeftPrec().is_null()
00264       {
00265   explicitTest = rcp (new res_norm_test (convTol, defQuorum));
00266   explicitTest->defineResForm (res_norm_test::Explicit, Belos::TwoNorm);
00267   explicitTest->defineScaleForm (stringToScaleType (explicitScaleType),
00268                Belos::TwoNorm);
00269   explicitTest->setShowMaxResNormOnly (showMaxResNormOnly);
00270       }
00271     else
00272       explicitTest = null;
00273 
00274     // Full convergence test:
00275     //
00276     // First, the implicit residual norm test,
00277     // Followed by the explicit residual norm test if applicable,
00278     // Followed by the user-defined convergence test if supplied.
00279     RCP<base_test> convTest;
00280     if (explicitTest.is_null())
00281       convTest = implicitTest;
00282     else
00283       // The "explicit" residual test is only performed once the
00284       // native ("implicit") residual is below the convergence
00285       // tolerance.
00286       convTest = rcp (new combo_test (combo_test::SEQ, 
00287               implicitTest, 
00288               explicitTest));
00289 
00290     // Stopping criterion for maximum number of iterations.
00291     RCP<max_iter_test> maxIterTest = rcp (new max_iter_test (maxIterCount));
00292 
00293     // The "final" stopping criterion:
00294     //
00295     // Either we've run out of iterations, OR we've converged.
00296     return rcp (new combo_test (combo_test::OR, maxIterTest, convTest));
00297   }
00298 
00299 
00300   template<class Scalar, class MV, class OP>
00301   Teuchos::RCP<typename StatusTestFactory<Scalar, MV, OP>::base_test>
00302   StatusTestFactory<Scalar, MV, OP>::
00303   gmresTest (const bool haveLeftPreconditioner, 
00304        const Teuchos::RCP<const Teuchos::ParameterList>& params)
00305   {
00306     using Teuchos::Exceptions::InvalidParameter;
00307     using std::string;
00308     typedef Teuchos::ScalarTraits<magnitude_type> STM;
00309 
00310     const magnitude_type convTol = 
00311       params->get<magnitude_type> ("Convergence Tolerance");
00312     TEST_FOR_EXCEPTION(convTol < STM::zero(), std::invalid_argument,
00313            "Convergence tolerance " << convTol 
00314            << " is negative.");
00315     const int maxIterCount = params->get<int> ("Maximum Iterations");
00316     TEST_FOR_EXCEPTION(maxIterCount < 0, std::invalid_argument,
00317            "Maximum number of iterations " << maxIterCount
00318            << " is negative.");
00319 
00320     ScaleType implicitScaleType = NormOfPrecInitRes;
00321     try {
00322       implicitScaleType = 
00323   stringToScaleType (params->get<string> ("Implicit Residual Scaling"));
00324     } catch (InvalidParameter&) {
00325       // Do nothing; leave default value
00326     }
00327     ScaleType explicitScaleType = NormOfInitRes;
00328     try {
00329       explicitScaleType = 
00330   stringToScaleType (params->get<string> ("Explicit Residual Scaling"));
00331     } catch (InvalidParameter&) {
00332       // Do nothing; leave default value
00333     }
00334     int blockSize = 1;
00335     try {
00336       blockSize = params->get<int> ("Block Size");
00337     } catch (InvalidParameter&) {
00338       // Do nothing; leave default value
00339     }
00340     int defQuorum = -1;
00341     try {
00342       defQuorum = params->get<int> ("Deflation Quorum");
00343     } catch (InvalidParameter&) {
00344       // Do nothing; leave default value
00345     }
00346     bool showMaxResNormOnly = false;
00347     try {
00348       showMaxResNormOnly = 
00349   params->get<bool> ("Show Maximum Residual Norm Only");
00350     } catch (InvalidParameter&) {
00351       // Do nothing; leave default value
00352     }
00353 
00354     return gmresTest (convTol, maxIterCount, haveLeftPreconditioner,
00355           implicitScaleType, explicitScaleType, blockSize,
00356           defQuorum, showMaxResNormOnly);
00357   }
00358 
00359 
00360   template<class Scalar, class MV, class OP>
00361   bool
00362   StatusTestFactory<Scalar, MV, OP>::
00363   changeMaxNumIters (const Teuchos::RCP<typename StatusTestFactory<Scalar, MV, OP>::base_test>& test,
00364          const int maxIterCount)
00365   {
00366     using Teuchos::rcp_dynamic_cast;
00367     using Teuchos::nonnull;
00368     using Teuchos::RCP;
00369     using Teuchos::rcp;
00370 
00371     // We declare "success" if the test or at least one of its
00372     // children (if it's a combo_test) is a max_iter_test.
00373     bool success = false;
00374     RCP<max_iter_test> maxIterTest = rcp_dynamic_cast<max_iter_test> (test);
00375     if (nonnull (maxIterTest))
00376       {
00377   test->setMaxIters (maxIterCount);
00378   success = true;
00379       }
00380     else
00381       {
00382   RCP<combo_test> comboTest = rcp_dynamic_cast<combo_test> (test);
00383   if (nonnull (comboTest))
00384     {
00385       typedef typename combo_test::st_vector st_vector;
00386       typedef typename st_vector::size_type size_type;
00387       st_vector tests = test->getStatusTests ();
00388       // We could use boost lambda to remove this for loop.
00389       // Standard STL doesn't have a version of mem_fun for
00390       // member functions that take > 1 argument.
00391       for (size_type k = 0; result || k < tests.end(); ++k)
00392         { // Recurse on all children, since it's possible for
00393     // more than one child to be a max_iter_test.
00394     const bool result =
00395       changeMaxNumIters (tests[k], maxIterCount);
00396     success = result || success;
00397         }
00398     }
00399       }
00400     return success;
00401   }
00402 
00403   template<class Scalar, class MV, class OP>
00404   std::pair<bool, bool>
00405   StatusTestFactory<Scalar, MV, OP>::
00406   changeConvTolAndMaxNumIters (const Teuchos::RCP<typename StatusTestFactory<Scalar, MV, OP>::base_test>& test,
00407              const typename StatusTestFactory<Scalar, MV, OP>::magnitude_type convTol,
00408              const int maxIterCount)
00409   {
00410     using Teuchos::rcp_dynamic_cast;
00411     using Teuchos::nonnull;
00412     using Teuchos::RCP;
00413     using Teuchos::rcp;
00414     typedef StatusTestResNorm<Scalar,MV,OP> res_norm_base_test;
00415     RCP<max_iter_test> maxIterTest = rcp_dynamic_cast<max_iter_test> (test);
00416 
00417     // We declare "success" if we encountered a res_norm_base_test
00418     // _and_ a max_iter_test somewhere along the recursion path.
00419     bool foundResNormTest = false;
00420     bool foundMaxIterTest = false;
00421 
00422     RCP<res_norm_base_test> normTest = 
00423       rcp_dynamic_cast<res_norm_base_test> (test);
00424     if (nonnull (normTest))
00425       { 
00426   // NOTE (mfh 03 Mar 2011) setTolerance() returns an int
00427   // result.  However, all subclasses' implementations return 0
00428   // here, and all of them always (re)set the tolerance, so I
00429   // think it's OK to ignore the result.
00430   (void) test->setTolerance (convTol);
00431   foundResNormTest = true;
00432       }
00433     else 
00434       {
00435   RCP<max_iter_test> maxIterTest = 
00436     rcp_dynamic_cast<max_iter_test> (test);
00437   if (nonnull (maxIterTest))
00438     {
00439       test->setMaxIters (maxIterCount);
00440       foundMaxIterTest = true;
00441     }
00442       }
00443     if (! foundResNormTest && ! foundMaxIterTest)
00444       {
00445   RCP<combo_test> comboTest = rcp_dynamic_cast<combo_test> (test);
00446   if (nonnull (comboTest))
00447     {
00448       typedef typename combo_test::st_vector st_vector;
00449       typedef typename st_vector::size_type size_type;
00450       st_vector tests = test->getStatusTests ();
00451       // We could use boost lambda to remove this for loop.
00452       // Standard STL doesn't have a version of mem_fun for
00453       // member functions that take > 1 argument.
00454       for (size_type k = 0; result || k < tests.end(); ++k)
00455         { // Recurse on all children.
00456     const std::pair<bool, bool> result = 
00457       changeConvTolAndMaxIters (tests[k], convTol, maxIterCount);
00458     foundResNormTest = result.first || foundResNormTest;
00459     foundMaxIterTest = result.second || foundMaxIterTest;     
00460         }
00461     }
00462       }
00463     return std::make_pair (foundResNormTest, foundMaxIterTest);
00464   }
00465 
00466   template<class Scalar, class MV, class OP>
00467   bool
00468   StatusTestFactory<Scalar, MV, OP>::
00469   changeConvTol (const Teuchos::RCP<typename StatusTestFactory<Scalar, MV, OP>::base_test>& test,
00470      const typename StatusTestFactory<Scalar, MV, OP>::magnitude_type convTol)
00471   {
00472     using Teuchos::rcp_dynamic_cast;
00473     using Teuchos::nonnull;
00474     using Teuchos::RCP;
00475     using Teuchos::rcp;
00476     typedef StatusTestResNorm<Scalar,MV,OP> res_norm_base_test;
00477 
00478     // We declare "success" if the test or at least one of its
00479     // children (if it's a combo_test) is a res_norm_base_test.
00480     bool success = false;
00481     RCP<res_norm_base_test> normTest = 
00482       rcp_dynamic_cast<res_norm_base_test> (test);
00483     if (nonnull (normTest))
00484       { 
00485   // NOTE (mfh 03 Mar 2011) setTolerance() returns an int
00486   // result.  However, all subclasses' implementations return 0
00487   // here, and all of them always (re)set the tolerance, so I
00488   // think it's OK to ignore the result.
00489   (void) test->setTolerance (convTol);
00490   success = true;
00491       }
00492     else
00493       {
00494   RCP<combo_test> comboTest = rcp_dynamic_cast<combo_test> (test);
00495   if (nonnull (comboTest))
00496     {
00497       typedef typename combo_test::st_vector st_vector;
00498       typedef typename st_vector::size_type size_type;
00499       st_vector tests = test->getStatusTests ();
00500       // We could use boost lambda to remove this for loop.
00501       // Standard STL doesn't have a version of mem_fun for
00502       // member functions that take > 1 argument.
00503       for (size_type k = 0; result || k < tests.end(); ++k)
00504         { // Recurse on all children, since it's possible for
00505     // more than one child to be a res_norm_base_test.
00506     const bool result = changeConvTol (tests[k], convTol);
00507     success = result || success;
00508         }
00509     }
00510       }
00511     return success;
00512   }
00513 
00514 
00515   template<class Scalar, class MV, class OP>
00516   static ScaleType
00517   StatusTestFactory<Scalar, MV, OP>::
00518   stringToScaleType (const std::string& scaleType) 
00519   {
00520     const char* validNames[] = {
00521       "Norm of Initial Residual", 
00522       "Norm of Preconditioned Initial Residual",
00523       "Norm of RHS",
00524       "Norm of Right-Hand Side",
00525       "None"
00526     };
00527     const int numValidNames = 5;
00528     const ScaleType correspondingOutputs[] = {
00529       Belos::NormOfInitRes,
00530       Belos::NormOfPrecInitRes,
00531       Belos::NormOfRHS,
00532       Belos::NormOfRHS,
00533       Belos::None
00534     };
00535     for (int k = 0; k < numValidNames; ++k)
00536       {
00537   if (scaleType == validNames[k])
00538     return correspondingOutputs[k];
00539       }
00540     TEST_FOR_EXCEPTION (true, std::logic_error,
00541       "Invalid residual scaling type \"" << scaleType 
00542       << "\".");
00543   }
00544 
00545 } // namespace Belos
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines