Belos Version of the Day
BelosAkxFactory.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 #ifndef __Belos_AkxFactory_hpp
00043 #define __Belos_AkxFactory_hpp
00044 
00045 #include <BelosMonomialOpAkx.hpp>
00046 #include <Teuchos_ParameterList.hpp>
00047 
00048 #include <algorithm>
00049 #include <cctype>
00050 
00051 // TODO Include other OpAkx implementations, and other Akx
00052 // implementations (that don't implement OpAkx) as they are completed.
00053 
00054 namespace Belos {
00055 
00069   template<class Scalar, class MV>
00070   class AkxFactory {
00071   public:
00075     typedef Akx<Scalar, MV> akx_base_type;    
00076 
00080     AkxFactory();
00081 
00103     template<class OP>
00104     Teuchos::RCP<akx_base_type>
00105     makeOpAkx (const Teuchos::RCP<const OP>& A, 
00106          const Teuchos::RCP<const OP>& M_left, 
00107          const Teuchos::RCP<const OP>& M_right,
00108          const Teuchos::RCP<const Teuchos::ParameterList>& params);
00109 
00111     Teuchos::RCP<const Teuchos::ParameterList>
00112     getDefaultParameters ();
00113 
00119     const std::string& parameterListName () const {
00120       return listName_;
00121     }
00122 
00123   private:
00133     std::string
00134     validateBasisName (const std::string& basisName) const;
00135 
00137     const std::string listName_;
00138 
00140     std::vector<std::string> validBasisNames_;
00141     
00145     Teuchos::RCP<const Teuchos::ParameterList> defaultParams_;
00146   };
00147 
00148 
00149   template<class Scalar, class MV>
00150   AkxFactory<Scalar, MV>::AkxFactory() : listName_ ("Akx") 
00151   {
00152     typedef std::vector<std::string>::size_type size_type;
00153     //
00154     // TODO (mfh 14 Feb 2011) Support more basis types later.
00155     //
00156     const size_type numValidBasisNames = 1;
00157     const char* validBasisNames[] = {"Monomial"};
00158     validBasisNames_.resize (numValidBasisNames);
00159 
00160     for (size_type k = 0; k < numValidBasisNames; ++k)
00161       validBasisNames_.push_back (validBasisNames[k]);
00162   }
00163 
00164   template<class Scalar, class MV>
00165   Teuchos::RCP<typename AkxFactory<Scalar, MV>::akx_base_type>
00166   AkxFactory<Scalar, MV>::
00167   makeOpAkx (const Teuchos::RCP<const OP>& A, 
00168        const Teuchos::RCP<const OP>& M_left, 
00169        const Teuchos::RCP<const OP>& M_right,
00170        const Teuchos::RCP<const Teuchos::ParameterList>& params)
00171   {
00172     using Teuchos::ParameterList;
00173     using Teuchos::RCP;
00174     using Teuchos::Exceptions::InvalidParameter;
00175     using Teuchos::Exceptions::InvalidParameterName;
00176     using Teuchos::Exceptions::InvalidParameterType;
00177 
00178     RCP<const ParameterList> plist = 
00179       params.is_null() ? getDefaultParameters() : params;
00180     
00181     std::string basisType;
00182     try {
00183       basisType = plist->get<std::string> ("Basis Type");
00184     } catch (InvalidParameter& e) {
00185       // FIXME (mfh 14 Feb 2011, 03 Mar 2011)
00186       //
00187       // Just rethrow for now.  Later we might wrap and rethrow, or
00188       // implement more tolerant behavior.
00189       throw e; 
00190     }
00191     // Canonicalize (case, etc.) the string and validate it.  Throw an
00192     // exception if invalid, else return the canonicalized name.
00193     const std::string validName = validateBasisName (basisType);
00194 
00195     // Recommended (at least initially) basis length.
00196     int basisLength = 5; // a reasonable default
00197     try {
00198       basisLength = plist->get<int> ("Basis Length");
00199     } catch (InvalidParameter& e) {
00200       // Do nothing; let the default stay
00201     }
00202     TEUCHOS_TEST_FOR_EXCEPTION(basisLength < 1, std::invalid_argument,
00203            "The \"Basis Length\" parameter must be >= 1, "
00204            "but its value here is " << basisLength << ".");
00205     if (validName == "Monomial")
00206       {
00207   typedef MonomialOpAkx<Scalar, MV, OP> akx_impl_type;
00208   RCP<akx_impl_type> akx (new akx_impl_type (A, M_left, M_right, basisLength));
00209   return akx;
00210       }
00211     else
00212       {
00213   TEUCHOS_TEST_FOR_EXCEPTION(validName != "Monomial", std::logic_error,
00214          "We have not yet implemented the \"" 
00215          << validName << "\" basis.");
00216   throw std::logic_error("Should never get here!");
00217       }
00218   }
00219 
00220   template<class Scalar, class MV>
00221   Teuchos::RCP<const Teuchos::ParameterList>
00222   AkxFactory<Scalar, MV>::getDefaultParameters ()
00223   {
00224     using Teuchos::RCP;
00225     using Teuchos::ParameterList;
00226     using Teuchos::parameterList;
00227 
00228     if (defaultParams_.is_null())
00229       {
00230   RCP<ParameterList> plist = parameterList (parameterListName ());
00231   // Default basis type is monomial for now; this will likely
00232   // change to the Newton basis.
00233   const std::string defaultBasis ("Monomial");
00234   {
00235     std::ostringstream os;
00236     os << "Default basis type.  Valid choices include: {";
00237     for (std::vector<std::string>::size_type k = 0; 
00238          k < validBasisNames_.size(); ++k)
00239       {
00240         os << validBasisNames_[k];
00241         if (k < validBasisNames_.size() - 1)
00242     os << ", ";
00243       }
00244     os << "}.";
00245     plist->set ("Basis Type", defaultBasis, os.str());
00246   }
00247   // An initial basis length of 5 is a reasonable first guess.
00248   // Solvers should revise this dynamically, based on their
00249   // estimates of the condition number and rank of the generated
00250   // candidate basis.
00251   const int defaultBasisLength = 5;
00252   plist->set ("Basis Length", defaultBasisLength, 
00253         "Default recommended basis length.");
00254   defaultParams_ = plist;
00255       }
00256     return defaultParams_;
00257   }
00258 
00259   template<class Scalar, class MV>
00260   std::string
00261   AkxFactory<Scalar, MV>::validateBasisName (const std::string& basisName) const
00262   {
00263     // Canonicalize the basis name.  First, strip whitespace.
00264     // Second, capitalize the first letter and lowercase the rest.
00265     TEUCHOS_TEST_FOR_EXCEPTION(basisName.empty(), std::invalid_argument,
00266            "The matrix powers kernel basis name is an empty "
00267            "string.");
00268     const size_t npos = std::string::npos;
00269     size_t firstNonSpacePos = basisName.find_first_not_of (" \t\n");
00270     size_t lastNonSpacePos = basisName.find_last_not_of (" \t\n");
00271     TEUCHOS_TEST_FOR_EXCEPTION(firstNonSpacePos == npos, std::invalid_argument,
00272            "The matrix powers kernel basis name \"" << basisName 
00273            << "\" contains only whitespace.");
00274     // canonName must have length at least one.
00275     std::string canonName = 
00276       basisName.substr (firstNonSpacePos, lastNonSpacePos-firstNonSpacePos+1);
00277     // Capitalize the first letter and lowercase the rest, in place.
00278     canonName[0] = toupper (canonName[0]);
00279     std::transform (canonName.begin()+1, canonName.end(), 
00280         canonName.begin()+1, tolower);
00281     const bool foundIt = validBasisNames_.end() != 
00282       std::find (validBasisNames_.begin(), validBasisNames_.end(), canonName);
00283     TEUCHOS_TEST_FOR_EXCEPTION(! foundIt, std::invalid_argument,
00284            "Invalid basis name \"" << basisName << "\".");
00285     return canonName;
00286   }
00287 
00288 
00289 } // namespace Belos
00290 
00291 #endif // __Belos_AkxFactory_hpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines