Rythmos - Transient Integration for Differential Equations Version of the Day
Rythmos_TimeStepNonlinearSolver_def.hpp
00001 //@HEADER
00002 // ***********************************************************************
00003 //
00004 //                           Rythmos Package
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 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
00023 // USA
00024 // Questions? Contact Todd S. Coffey (tscoffe@sandia.gov)
00025 //
00026 // ***********************************************************************
00027 //@HEADER
00028 
00029 
00030 #ifndef RYTHMOS_TIME_STEP_NONLINEAR_SOLVER_DEF_HPP
00031 #define RYTHMOS_TIME_STEP_NONLINEAR_SOLVER_DEF_HPP
00032 
00033 #include "Rythmos_TimeStepNonlinearSolver_decl.hpp"
00034 
00035 #include "Thyra_TestingTools.hpp"
00036 #include "Thyra_ModelEvaluatorHelpers.hpp"
00037 #include "Teuchos_VerboseObjectParameterListHelpers.hpp"
00038 #include "Teuchos_StandardParameterEntryValidators.hpp"
00039 #include "Teuchos_as.hpp"
00040 
00041 namespace Rythmos {
00042 
00043 
00044 // ////////////////////////
00045 // Defintions
00046 
00047 
00048 // Static members
00049 
00050 
00051 template<class Scalar>
00052 const std::string
00053 TimeStepNonlinearSolver<Scalar>::DefaultTol_name_ = "Default Tol";
00054 
00055 template<class Scalar>
00056 const double
00057 TimeStepNonlinearSolver<Scalar>::DefaultTol_default_ = 1e-2;
00058 
00059 
00060 template<class Scalar>
00061 const std::string
00062 TimeStepNonlinearSolver<Scalar>::DefaultMaxIters_name_ = "Default Max Iters";
00063 
00064 template<class Scalar>
00065 const int
00066 TimeStepNonlinearSolver<Scalar>::DefaultMaxIters_default_ = 3;
00067 
00068 
00069 template<class Scalar>
00070 const std::string
00071 TimeStepNonlinearSolver<Scalar>::NonlinearSafetyFactor_name_
00072 = "Nonlinear Safety Factor";
00073 
00074 template<class Scalar>
00075 const double
00076 TimeStepNonlinearSolver<Scalar>::NonlinearSafetyFactor_default_ = 0.1;
00077 
00078 
00079 template<class Scalar>
00080 const std::string
00081 TimeStepNonlinearSolver<Scalar>::LinearSafetyFactor_name_ = "Linear Safety Factor";
00082 
00083 template<class Scalar>
00084 const double
00085 TimeStepNonlinearSolver<Scalar>::LinearSafetyFactor_default_ = 0.05;
00086 
00087 
00088 template<class Scalar>
00089 const std::string
00090 TimeStepNonlinearSolver<Scalar>::RMinFraction_name_ = "R Min Fraction";
00091 
00092 template<class Scalar>
00093 const double
00094 TimeStepNonlinearSolver<Scalar>::RMinFraction_default_ = 0.3;
00095 
00096 
00097 template<class Scalar>
00098 const std::string
00099 TimeStepNonlinearSolver<Scalar>::ThrownOnLinearSolveFailure_name_
00100 = "Thrown on Linear Solve Failure";
00101 
00102 template<class Scalar>
00103 const bool
00104 TimeStepNonlinearSolver<Scalar>::ThrownOnLinearSolveFailure_default_ = false;
00105 
00106 
00107 // Constructors/Intializers/Misc
00108 
00109 
00110 template <class Scalar>
00111 TimeStepNonlinearSolver<Scalar>::TimeStepNonlinearSolver()
00112   :J_is_current_(false),
00113    defaultTol_(DefaultTol_default_),
00114    defaultMaxIters_(DefaultMaxIters_default_),
00115    nonlinearSafetyFactor_(NonlinearSafetyFactor_default_),
00116    linearSafetyFactor_(LinearSafetyFactor_default_),
00117    RMinFraction_(RMinFraction_default_),
00118    throwOnLinearSolveFailure_(ThrownOnLinearSolveFailure_default_)
00119 {}
00120 
00121 
00122 // Overridden from ParameterListAcceptor
00123 
00124 
00125 template<class Scalar>
00126 void TimeStepNonlinearSolver<Scalar>::setParameterList(
00127   RCP<ParameterList> const& paramList
00128   )
00129 {
00130   using Teuchos::get;
00131   TEUCHOS_TEST_FOR_EXCEPT(is_null(paramList));
00132   paramList->validateParametersAndSetDefaults(*getValidParameters(),0);
00133   paramList_ = paramList;
00134   defaultTol_ = get<double>(*paramList_,DefaultTol_name_);
00135   defaultMaxIters_ = get<int>(*paramList_,DefaultMaxIters_name_);
00136   nonlinearSafetyFactor_ = get<double>(*paramList_,NonlinearSafetyFactor_name_);
00137   linearSafetyFactor_ = get<double>(*paramList_,LinearSafetyFactor_name_);
00138   RMinFraction_ = get<double>(*paramList_,RMinFraction_name_);
00139   throwOnLinearSolveFailure_ = get<bool>(
00140     *paramList_,ThrownOnLinearSolveFailure_name_);
00141   Teuchos::readVerboseObjectSublist(&*paramList_,this);
00142 #ifdef HAVE_RYTHMOS_DEBUG
00143   paramList_->validateParameters(*getValidParameters(),0);
00144 #endif // HAVE_RYTHMOS_DEBUG
00145 }
00146 
00147 
00148 template<class Scalar>
00149 RCP<ParameterList>
00150 TimeStepNonlinearSolver<Scalar>::getNonconstParameterList()
00151 {
00152   return paramList_;
00153 }
00154 
00155 
00156 template<class Scalar>
00157 RCP<ParameterList>
00158 TimeStepNonlinearSolver<Scalar>::unsetParameterList()
00159 {
00160   RCP<ParameterList> _paramList = paramList_;
00161   paramList_ = Teuchos::null;
00162   return _paramList;
00163 }
00164 
00165 
00166 template<class Scalar>
00167 RCP<const ParameterList>
00168 TimeStepNonlinearSolver<Scalar>::getParameterList() const
00169 {
00170   return paramList_;
00171 }
00172 
00173 
00174 template<class Scalar>
00175 RCP<const ParameterList>
00176 TimeStepNonlinearSolver<Scalar>::getValidParameters() const
00177 {
00178   using Teuchos::setDoubleParameter; using Teuchos::setIntParameter;
00179   static RCP<const ParameterList> validPL;
00180   if (is_null(validPL)) {
00181     RCP<ParameterList> pl = Teuchos::parameterList();
00182     setDoubleParameter(
00183       DefaultTol_name_, DefaultTol_default_,
00184       "The default base tolerance for the nonlinear timestep solve.\n"
00185       "This tolerance can be overridden ???",
00186       &*pl );
00187     setIntParameter(
00188       DefaultMaxIters_name_, DefaultMaxIters_default_,
00189       "The default maximum number of Newton iterations to perform.\n"
00190       "This default can be overridden ???",
00191       &*pl );
00192     setDoubleParameter(
00193       NonlinearSafetyFactor_name_, NonlinearSafetyFactor_default_,
00194       "The factor (< 1.0) to multiply tol to bound R*||dx|||.\n"
00195       "The exact nonlinear convergence test is:\n"
00196       "  R*||dx|| <= \"" + NonlinearSafetyFactor_name_ + "\" * tol.",
00197       &*pl );
00198     setDoubleParameter(
00199       LinearSafetyFactor_name_, LinearSafetyFactor_default_,
00200       "This factor multiplies the nonlinear safety factor which multiplies\n"
00201       "tol when determining the linear solve tolerence.\n"
00202       "The exact linear convergence tolerance is:\n"
00203       "  ||J*dx+f||/||f|| <= \"" + LinearSafetyFactor_name_ + "\" * "
00204       "\"" + NonlinearSafetyFactor_name_ + "\" * tol.",
00205       &*pl );
00206     setDoubleParameter(
00207       RMinFraction_name_, RMinFraction_default_,
00208       "The faction below which the R factor is not allowed to drop\n"
00209       "below each Newton iteration.  The R factor is related to the\n"
00210       "ratio of ||dx||/||dx_last|| between nonlinear iterations.",
00211       &*pl );
00212     pl->set(
00213       ThrownOnLinearSolveFailure_name_, ThrownOnLinearSolveFailure_default_,
00214       "If set to true (\"1\"), then an Thyra::CatastrophicSolveFailure\n"
00215       "exception will be thrown when a linear solve fails to meet it's tolerance."
00216       );
00217     Teuchos::setupVerboseObjectSublist(&*pl);
00218     validPL = pl;
00219   }
00220   return validPL;
00221 }
00222 
00223 
00224 // Overridden from NonlinearSolverBase
00225 
00226 
00227 template <class Scalar>
00228 void TimeStepNonlinearSolver<Scalar>::setModel(
00229   const RCP<const Thyra::ModelEvaluator<Scalar> > &model
00230   )
00231 {
00232   TEUCHOS_TEST_FOR_EXCEPT(model.get()==NULL);
00233   model_ = model;
00234   J_ = Teuchos::null;
00235   current_x_ = Teuchos::null;
00236   J_is_current_ = false;
00237 }
00238 
00239 
00240 template <class Scalar>
00241 RCP<const Thyra::ModelEvaluator<Scalar> >
00242 TimeStepNonlinearSolver<Scalar>::getModel() const
00243 {
00244   return model_;
00245 }
00246 
00247 template <class Scalar>
00248 Thyra::SolveStatus<Scalar>
00249 TimeStepNonlinearSolver<Scalar>::solve(
00250   Thyra::VectorBase<Scalar> *x,
00251   const Thyra::SolveCriteria<Scalar> *solveCriteria,
00252   Thyra::VectorBase<Scalar> *delta
00253   )
00254 {
00255   
00256   RYTHMOS_FUNC_TIME_MONITOR("Rythmos:TimeStepNonlinearSolver::solve");
00257 
00258   using std::endl;
00259   using Teuchos::incrVerbLevel;
00260   using Teuchos::describe;
00261   using Teuchos::as;
00262   using Teuchos::rcp;
00263   using Teuchos::OSTab;
00264   using Teuchos::getFancyOStream;
00265   typedef Thyra::ModelEvaluatorBase MEB;
00266   typedef Teuchos::VerboseObjectTempState<MEB> VOTSME;
00267   typedef Thyra::LinearOpWithSolveBase<Scalar> LOWSB;
00268   typedef Teuchos::VerboseObjectTempState<LOWSB> VOTSLOWSB;
00269 
00270 #ifdef HAVE_RYTHMOS_DEBUG
00271   TEUCHOS_TEST_FOR_EXCEPT(0==x);
00272   THYRA_ASSERT_VEC_SPACES(
00273     "TimeStepNonlinearSolver<Scalar>::solve(...)",
00274     *x->space(),*model_->get_x_space() );
00275   TEUCHOS_TEST_FOR_EXCEPT(
00276     0!=solveCriteria && "ToDo: Support passed in solve criteria!" );
00277 #endif
00278 
00279   const RCP<Teuchos::FancyOStream> out = this->getOStream();
00280   const Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
00281   const bool showNewtonDetails =
00282     (!is_null(out) && (as<int>(verbLevel) >= as<int>(Teuchos::VERB_MEDIUM)));
00283   const bool dumpAll =
00284     (!is_null(out) && (as<int>(verbLevel) == as<int>(Teuchos::VERB_EXTREME))); 
00285   TEUCHOS_OSTAB;
00286   VOTSME stateModel_outputTempState(model_,out,incrVerbLevel(verbLevel,-1));
00287 
00288   if (showNewtonDetails)
00289     *out
00290       << "\nEntering TimeStepNonlinearSolver::solve(...) ...\n"
00291       << "\nmodel = " << Teuchos::describe(*model_,verbLevel);
00292 
00293   if(dumpAll) {
00294     *out << "\nInitial guess:\n";
00295     *out << "\nx = " << *x;
00296   }
00297 
00298   // Initialize storage for algorithm
00299   if(!J_.get()) J_ = model_->create_W();
00300   TEUCHOS_TEST_FOR_EXCEPTION( Teuchos::is_null(J_), std::logic_error,
00301       "Error!  model->create_W() returned a null pointer!\n"
00302       );
00303   RCP<Thyra::VectorBase<Scalar> > f = createMember(model_->get_f_space());
00304   RCP<Thyra::VectorBase<Scalar> > dx = createMember(model_->get_x_space());
00305   RCP<Thyra::VectorBase<Scalar> > dx_last = createMember(model_->get_x_space());
00306   RCP<Thyra::VectorBase<Scalar> > x_curr = createMember(model_->get_x_space());
00307   if (delta != NULL)
00308     Thyra::V_S(ptr(delta),ST::zero()); // delta stores the cumulative update to x over the whole Newton solve.
00309   Thyra::assign(x_curr.ptr(),*x);
00310   J_is_current_ = false;
00311   current_x_ = Teuchos::null;
00312 
00313   // Initialize convergence criteria
00314   ScalarMag R = SMT::one();
00315   ScalarMag linearTolSafety = linearSafetyFactor_ * nonlinearSafetyFactor_;
00316   int maxIters = defaultMaxIters_;
00317   ScalarMag tol = defaultTol_;
00318   // ToDo: Get above from solveCriteria!
00319 
00320   // Do the undampened Newton iterations
00321   bool converged = false;
00322   bool sawFailedLinearSolve = false;
00323   Thyra::SolveStatus<Scalar> failedLinearSolveStatus;
00324   ScalarMag nrm_dx = SMT::nan();
00325   ScalarMag nrm_dx_last = SMT::nan();
00326   int iter = 1;
00327   for( ; iter <= maxIters; ++iter ) {
00328     if (showNewtonDetails)
00329       *out << "\n*** newtonIter = " << iter << endl;
00330     if (showNewtonDetails)
00331       *out << "\nEvaluating the model f and W ...\n";
00332     Thyra::eval_f_W( *model_, *x_curr, &*f, &*J_ );
00333     if (showNewtonDetails)
00334       *out << "\nSolving the system J*dx = -f ...\n";
00335     Thyra::V_S(dx.ptr(),ST::zero()); // Initial guess is needed!
00336     Thyra::SolveCriteria<Scalar>
00337       linearSolveCriteria(
00338         Thyra::SolveMeasureType(
00339           Thyra::SOLVE_MEASURE_NORM_RESIDUAL, Thyra::SOLVE_MEASURE_NORM_RHS
00340           ),
00341         linearTolSafety*tol
00342         );
00343     VOTSLOWSB J_outputTempState(J_,out,incrVerbLevel(verbLevel,-1));
00344     Thyra::SolveStatus<Scalar> linearSolveStatus
00345       = J_->solve(Thyra::NOTRANS, *f, dx.ptr(), Teuchos::ptr(&linearSolveCriteria) );
00346     if (showNewtonDetails)
00347       *out << "\nLinear solve status:\n" << linearSolveStatus;
00348     Thyra::Vt_S(dx.ptr(),Scalar(-ST::one()));
00349     if (dumpAll)
00350       *out << "\ndx = " << Teuchos::describe(*dx,verbLevel);
00351     if (delta != NULL) {
00352       Thyra::Vp_V(ptr(delta),*dx);
00353       if (dumpAll)
00354         *out << "\ndelta = " << Teuchos::describe(*delta,verbLevel);
00355     }
00356     // Check the linear solve
00357     if(linearSolveStatus.solveStatus != Thyra::SOLVE_STATUS_CONVERGED) {
00358       sawFailedLinearSolve = true;
00359       failedLinearSolveStatus = linearSolveStatus;
00360       if (throwOnLinearSolveFailure_) {
00361         TEUCHOS_TEST_FOR_EXCEPTION(
00362           throwOnLinearSolveFailure_, Thyra::CatastrophicSolveFailure,
00363           "Error, the linear solver did not converge!"
00364           );
00365       }
00366       if (showNewtonDetails)
00367         *out << "\nWarning, linear solve did not converge!  Continuing anyway :-)\n";
00368     }
00369     // Update the solution: x_curr = x_curr + dx
00370     Vp_V( x_curr.ptr(), *dx );
00371     if (dumpAll)
00372       *out << "\nUpdated solution x = " << Teuchos::describe(*x_curr,verbLevel);
00373     // Convergence test
00374     nrm_dx = Thyra::norm(*dx);
00375     if ( R*nrm_dx <= nonlinearSafetyFactor_*tol )
00376       converged = true;
00377     if (showNewtonDetails)
00378       *out
00379         << "\nConvergence test:\n"
00380         << "  R*||dx|| = " << R << "*" << nrm_dx
00381         << " = " << (R*nrm_dx) << "\n"
00382         << "    <= nonlinearSafetyFactor*tol = " << nonlinearSafetyFactor_ << "*" << tol
00383         << " = " << (nonlinearSafetyFactor_*tol)
00384         << " : " << ( converged ? "converged!" : " unconverged" )
00385         << endl;
00386     if(converged)
00387       break; // We have converged!!!
00388     // Update convergence criteria for the next iteration ...
00389     if(iter > 1) {
00390       const Scalar
00391         MinR = RMinFraction_*R,
00392         nrm_dx_ratio = nrm_dx/nrm_dx_last;
00393       R = std::max(MinR,nrm_dx_ratio);
00394       if (showNewtonDetails)
00395       *out
00396         << "\nUpdated R\n"
00397         << "  = max(RMinFraction*R,||dx||/||dx_last||)\n"
00398         << "  = max("<<RMinFraction_<<"*"<<R<<","<<nrm_dx<<"/"<<nrm_dx_last<<")\n"
00399         << "  = max("<<MinR<<","<<nrm_dx_ratio<<")\n"
00400         << "  = " << R << endl;
00401     }
00402     // Save to old
00403     std::swap(dx_last,dx);
00404     nrm_dx_last = nrm_dx;
00405   }
00406 
00407   // Set the solution
00408   Thyra::assign(ptr(x),*x_curr);
00409   
00410   if (dumpAll)
00411     *out << "\nFinal solution x = " << Teuchos::describe(*x,verbLevel);
00412 
00413   // Check the status
00414 
00415   Thyra::SolveStatus<Scalar> solveStatus;
00416 
00417   std::ostringstream oss;
00418   Teuchos::FancyOStream omsg(rcp(&oss,false));
00419 
00420   omsg << "Solver: " << this->description() << endl;
00421 
00422   if(converged) {
00423     solveStatus.solveStatus = Thyra::SOLVE_STATUS_CONVERGED;
00424     omsg << "CVODE status test converged!\n";
00425   }
00426   else {
00427     solveStatus.solveStatus = Thyra::SOLVE_STATUS_UNCONVERGED;
00428     omsg << "CVODE status test failed!\n";
00429   }
00430 
00431   if (sawFailedLinearSolve) {
00432     omsg << "Warning!  A failed linear solve was encountered with status:\n";
00433     OSTab tab(omsg);
00434     omsg << failedLinearSolveStatus;
00435   }
00436 
00437   omsg
00438     << "R*||dx|| = " << R << "*" << nrm_dx
00439     << " <= nonlinearSafetyFactor*tol = " << nonlinearSafetyFactor_ << "*" << tol << " : "
00440     << ( converged ? "converged!" : " unconverged" ) << endl;
00441 
00442   omsg
00443     << "Iterations = " << iter;
00444   // Above, we leave off the last newline since this is the convention for the
00445   // SolveStatus::message string!
00446 
00447   solveStatus.message = oss.str();
00448 
00449   // Update the solution state for external clients
00450   current_x_ = x->clone_v();
00451   J_is_current_ = false;
00452   // 2007/09/04: rabartl: Note, above the Jacobian J is always going to be out
00453   // of date since this algorithm computes x_curr = x_curr + dx for at least
00454   // one solve for dx = -inv(J)*f.  Therefore, J is never at the updated
00455   // x_curr, only the old x_curr!
00456 
00457   if (showNewtonDetails)
00458     *out << "\nLeaving TimeStepNonlinearSolver::solve(...) ...\n";
00459 
00460   return solveStatus;
00461 
00462 }
00463 
00464 
00465 template <class Scalar>
00466 bool TimeStepNonlinearSolver<Scalar>::supportsCloning() const
00467 {
00468   return true;
00469 }
00470 
00471 
00472 template <class Scalar>
00473 RCP<Thyra::NonlinearSolverBase<Scalar> >
00474 TimeStepNonlinearSolver<Scalar>::cloneNonlinearSolver() const
00475 {
00476   RCP<TimeStepNonlinearSolver<Scalar> >
00477     nonlinearSolver = Teuchos::rcp(new TimeStepNonlinearSolver<Scalar>);
00478   nonlinearSolver->model_ = model_; // Shallow copy is okay, model is stateless
00479   nonlinearSolver->defaultTol_ = defaultTol_;
00480   nonlinearSolver->defaultMaxIters_ = defaultMaxIters_;
00481   nonlinearSolver->nonlinearSafetyFactor_ = nonlinearSafetyFactor_;
00482   nonlinearSolver->linearSafetyFactor_ = linearSafetyFactor_;
00483   nonlinearSolver->RMinFraction_ = RMinFraction_;
00484   nonlinearSolver->throwOnLinearSolveFailure_ = throwOnLinearSolveFailure_;
00485   // Note: The specification of this virtual function in the interface class
00486   // allows us to just copy the algorithm, not the entire state so we are
00487   // done!
00488   return nonlinearSolver;
00489 }
00490 
00491 
00492 template <class Scalar>
00493 RCP<const Thyra::VectorBase<Scalar> >
00494 TimeStepNonlinearSolver<Scalar>::get_current_x() const
00495 {
00496   return current_x_;
00497 }
00498 
00499 
00500 template <class Scalar>
00501 bool TimeStepNonlinearSolver<Scalar>::is_W_current() const
00502 {
00503   return J_is_current_;
00504 }
00505 
00506 
00507 template <class Scalar>
00508 RCP<Thyra::LinearOpWithSolveBase<Scalar> >
00509 TimeStepNonlinearSolver<Scalar>::get_nonconst_W(const bool forceUpToDate)
00510 {
00511   if (is_null(J_))
00512     return Teuchos::null;
00513   if (forceUpToDate) {
00514 #ifdef HAVE_RYTHMOS_DEBUG
00515     TEUCHOS_TEST_FOR_EXCEPT(is_null(current_x_));
00516 #endif
00517     Thyra::eval_f_W<Scalar>( *model_, *current_x_, 0, &*J_ );
00518     J_is_current_ = true;
00519   }
00520   return J_;
00521 }
00522 
00523 
00524 template <class Scalar>
00525 RCP<const Thyra::LinearOpWithSolveBase<Scalar> >
00526 TimeStepNonlinearSolver<Scalar>::get_W() const
00527 {
00528   return J_;
00529 }
00530 
00531 
00532 template <class Scalar>
00533 void TimeStepNonlinearSolver<Scalar>::set_W_is_current(bool W_is_current)
00534 {
00535   J_is_current_ = W_is_current;
00536 }
00537 
00538 
00539 } // namespace Rythmos
00540 
00541 
00542 // Nonmember constructors
00543 
00544 
00545 template <class Scalar>
00546 Teuchos::RCP<Rythmos::TimeStepNonlinearSolver<Scalar> >
00547 Rythmos::timeStepNonlinearSolver()
00548 {
00549   return Teuchos::rcp(new TimeStepNonlinearSolver<Scalar>);
00550 }
00551 
00552 
00553 template <class Scalar>
00554 Teuchos::RCP<Rythmos::TimeStepNonlinearSolver<Scalar> >
00555 Rythmos::timeStepNonlinearSolver(const RCP<ParameterList> &pl)
00556 {
00557   const RCP<Rythmos::TimeStepNonlinearSolver<Scalar> >
00558     solver = timeStepNonlinearSolver<Scalar>();
00559   solver->setParameterList(pl);
00560   return solver;
00561 }
00562 
00563 
00564 // 
00565 // Explicit Instantiation macro
00566 //
00567 // Must be expanded from within the Rythmos namespace!
00568 //
00569 
00570 #define RYTHMOS_TIME_STEP_NONLINEAR_SOLVER_INSTANT(SCALAR) \
00571   \
00572   template class TimeStepNonlinearSolver< SCALAR >; \
00573   \
00574   template RCP<TimeStepNonlinearSolver< SCALAR > > timeStepNonlinearSolver(); \
00575   \
00576   template RCP<TimeStepNonlinearSolver<SCALAR > > \
00577   timeStepNonlinearSolver(const RCP<ParameterList> &pl);
00578 
00579 
00580 
00581 #endif // RYTHMOS_TIME_STEP_NONLINEAR_SOLVER_DEF_HPP
 All Classes Functions Variables Typedefs Friends