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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
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   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 RYTHMOS_DEBUG
00143   paramList_->validateParameters(*getValidParameters(),0);
00144 #endif // 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   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 #ifdef ENABLE_RYTHMOS_TIMERS
00257   TEUCHOS_FUNC_TIME_MONITOR("Rythmos:TimeStepNonlinearSolver::solve");
00258 #endif
00259 
00260   using std::endl;
00261   using Teuchos::incrVerbLevel;
00262   using Teuchos::describe;
00263   using Teuchos::as;
00264   using Teuchos::rcp;
00265   using Teuchos::OSTab;
00266   using Teuchos::getFancyOStream;
00267   typedef Thyra::ModelEvaluatorBase MEB;
00268   typedef Teuchos::VerboseObjectTempState<MEB> VOTSME;
00269   typedef Thyra::LinearOpWithSolveBase<Scalar> LOWSB;
00270   typedef Teuchos::VerboseObjectTempState<LOWSB> VOTSLOWSB;
00271 
00272 #ifdef RYTHMOS_DEBUG
00273   TEST_FOR_EXCEPT(0==x);
00274   THYRA_ASSERT_VEC_SPACES(
00275     "TimeStepNonlinearSolver<Scalar>::solve(...)",
00276     *x->space(),*model_->get_x_space() );
00277   TEST_FOR_EXCEPT(
00278     0!=solveCriteria && "ToDo: Support passed in solve criteria!" );
00279 #endif
00280 
00281   const RCP<Teuchos::FancyOStream> out = this->getOStream();
00282   const Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
00283   const bool showNewtonDetails =
00284     (!is_null(out) && (as<int>(verbLevel) >= as<int>(Teuchos::VERB_MEDIUM)));
00285   const bool dumpAll =
00286     (!is_null(out) && (as<int>(verbLevel) == as<int>(Teuchos::VERB_EXTREME))); 
00287   TEUCHOS_OSTAB;
00288   VOTSME stateModel_outputTempState(model_,out,incrVerbLevel(verbLevel,-1));
00289 
00290   if (showNewtonDetails)
00291     *out
00292       << "\nEntering TimeStepNonlinearSolver::solve(...) ...\n"
00293       << "\nmodel = " << Teuchos::describe(*model_,verbLevel);
00294 
00295   if(dumpAll) {
00296     *out << "\nInitial guess:\n";
00297     *out << "\nx = " << *x;
00298   }
00299 
00300   // Initialize storage for algorithm
00301   if(!J_.get()) J_ = model_->create_W();
00302   TEST_FOR_EXCEPTION( Teuchos::is_null(J_), std::logic_error,
00303       "Error!  model->create_W() returned a null pointer!\n"
00304       );
00305   RCP<Thyra::VectorBase<Scalar> > f = createMember(model_->get_f_space());
00306   RCP<Thyra::VectorBase<Scalar> > dx = createMember(model_->get_x_space());
00307   RCP<Thyra::VectorBase<Scalar> > dx_last = createMember(model_->get_x_space());
00308   RCP<Thyra::VectorBase<Scalar> > x_curr = createMember(model_->get_x_space());
00309   if (delta != NULL)
00310     Thyra::V_S(ptr(delta),ST::zero()); // delta stores the cumulative update to x over the whole Newton solve.
00311   Thyra::assign(x_curr.ptr(),*x);
00312   J_is_current_ = false;
00313   current_x_ = Teuchos::null;
00314 
00315   // Initialize convergence criteria
00316   ScalarMag R = SMT::one();
00317   ScalarMag linearTolSafety = linearSafetyFactor_ * nonlinearSafetyFactor_;
00318   int maxIters = defaultMaxIters_;
00319   ScalarMag tol = defaultTol_;
00320   // ToDo: Get above from solveCriteria!
00321 
00322   // Do the undampened Newton iterations
00323   bool converged = false;
00324   bool sawFailedLinearSolve = false;
00325   Thyra::SolveStatus<Scalar> failedLinearSolveStatus;
00326   ScalarMag nrm_dx = SMT::nan();
00327   ScalarMag nrm_dx_last = SMT::nan();
00328   int iter = 1;
00329   for( ; iter <= maxIters; ++iter ) {
00330     if (showNewtonDetails)
00331       *out << "\n*** newtonIter = " << iter << endl;
00332     if (showNewtonDetails)
00333       *out << "\nEvaluating the model f and W ...\n";
00334     Thyra::eval_f_W( *model_, *x_curr, &*f, &*J_ );
00335     if (showNewtonDetails)
00336       *out << "\nSolving the system J*dx = -f ...\n";
00337     Thyra::V_S(dx.ptr(),ST::zero()); // Initial guess is needed!
00338     Thyra::SolveCriteria<Scalar>
00339       linearSolveCriteria(
00340         Thyra::SolveMeasureType(
00341           Thyra::SOLVE_MEASURE_NORM_RESIDUAL, Thyra::SOLVE_MEASURE_NORM_RHS
00342           ),
00343         linearTolSafety*tol
00344         );
00345     VOTSLOWSB J_outputTempState(J_,out,incrVerbLevel(verbLevel,-1));
00346     Thyra::SolveStatus<Scalar> linearSolveStatus
00347       = J_->solve(Thyra::NOTRANS, *f, dx.ptr(), Teuchos::ptr(&linearSolveCriteria) );
00348     if (showNewtonDetails)
00349       *out << "\nLinear solve status:\n" << linearSolveStatus;
00350     Thyra::Vt_S(dx.ptr(),Scalar(-ST::one()));
00351     if (dumpAll)
00352       *out << "\ndx = " << Teuchos::describe(*dx,verbLevel);
00353     if (delta != NULL) {
00354       Thyra::Vp_V(ptr(delta),*dx);
00355       if (dumpAll)
00356         *out << "\ndelta = " << Teuchos::describe(*delta,verbLevel);
00357     }
00358     // Check the linear solve
00359     if(linearSolveStatus.solveStatus != Thyra::SOLVE_STATUS_CONVERGED) {
00360       sawFailedLinearSolve = true;
00361       failedLinearSolveStatus = linearSolveStatus;
00362       if (throwOnLinearSolveFailure_) {
00363         TEST_FOR_EXCEPTION(
00364           throwOnLinearSolveFailure_, Thyra::CatastrophicSolveFailure,
00365           "Error, the linear solver did not converge!"
00366           );
00367       }
00368       if (showNewtonDetails)
00369         *out << "\nWarning, linear solve did not converge!  Continuing anyway :-)\n";
00370     }
00371     // Update the solution: x_curr = x_curr + dx
00372     Vp_V( x_curr.ptr(), *dx );
00373     if (dumpAll)
00374       *out << "\nUpdated solution x = " << Teuchos::describe(*x_curr,verbLevel);
00375     // Convergence test
00376     nrm_dx = Thyra::norm(*dx);
00377     if ( R*nrm_dx <= nonlinearSafetyFactor_*tol )
00378       converged = true;
00379     if (showNewtonDetails)
00380       *out
00381         << "\nConvergence test:\n"
00382         << "  R*||dx|| = " << R << "*" << nrm_dx
00383         << " = " << (R*nrm_dx) << "\n"
00384         << "    <= nonlinearSafetyFactor*tol = " << nonlinearSafetyFactor_ << "*" << tol
00385         << " = " << (nonlinearSafetyFactor_*tol)
00386         << " : " << ( converged ? "converged!" : " unconverged" )
00387         << endl;
00388     if(converged)
00389       break; // We have converged!!!
00390     // Update convergence criteria for the next iteration ...
00391     if(iter > 1) {
00392       const Scalar
00393         MinR = RMinFraction_*R,
00394         nrm_dx_ratio = nrm_dx/nrm_dx_last;
00395       R = std::max(MinR,nrm_dx_ratio);
00396       if (showNewtonDetails)
00397       *out
00398         << "\nUpdated R\n"
00399         << "  = max(RMinFraction*R,||dx||/||dx_last||)\n"
00400         << "  = max("<<RMinFraction_<<"*"<<R<<","<<nrm_dx<<"/"<<nrm_dx_last<<")\n"
00401         << "  = max("<<MinR<<","<<nrm_dx_ratio<<")\n"
00402         << "  = " << R << endl;
00403     }
00404     // Save to old
00405     std::swap(dx_last,dx);
00406     nrm_dx_last = nrm_dx;
00407   }
00408 
00409   // Set the solution
00410   Thyra::assign(ptr(x),*x_curr);
00411   
00412   if (dumpAll)
00413     *out << "\nFinal solution x = " << Teuchos::describe(*x,verbLevel);
00414 
00415   // Check the status
00416 
00417   Thyra::SolveStatus<Scalar> solveStatus;
00418 
00419   std::ostringstream oss;
00420   Teuchos::FancyOStream omsg(rcp(&oss,false));
00421 
00422   omsg << "Solver: " << this->description() << endl;
00423 
00424   if(converged) {
00425     solveStatus.solveStatus = Thyra::SOLVE_STATUS_CONVERGED;
00426     omsg << "CVODE status test converged!\n";
00427   }
00428   else {
00429     solveStatus.solveStatus = Thyra::SOLVE_STATUS_UNCONVERGED;
00430     omsg << "CVODE status test failed!\n";
00431   }
00432 
00433   if (sawFailedLinearSolve) {
00434     omsg << "Warning!  A failed linear solve was encountered with status:\n";
00435     OSTab tab(omsg);
00436     omsg << failedLinearSolveStatus;
00437   }
00438 
00439   omsg
00440     << "R*||dx|| = " << R << "*" << nrm_dx
00441     << " <= nonlinearSafetyFactor*tol = " << nonlinearSafetyFactor_ << "*" << tol << " : "
00442     << ( converged ? "converged!" : " unconverged" ) << endl;
00443 
00444   omsg
00445     << "Iterations = " << iter;
00446   // Above, we leave off the last newline since this is the convention for the
00447   // SolveStatus::message string!
00448 
00449   solveStatus.message = oss.str();
00450 
00451   // Update the solution state for external clients
00452   current_x_ = x->clone_v();
00453   J_is_current_ = false;
00454   // 2007/09/04: rabartl: Note, above the Jacobian J is always going to be out
00455   // of date since this algorithm computes x_curr = x_curr + dx for at least
00456   // one solve for dx = -inv(J)*f.  Therefore, J is never at the updated
00457   // x_curr, only the old x_curr!
00458 
00459   if (showNewtonDetails)
00460     *out << "\nLeaving TimeStepNonlinearSolver::solve(...) ...\n";
00461 
00462   return solveStatus;
00463 
00464 }
00465 
00466 
00467 template <class Scalar>
00468 bool TimeStepNonlinearSolver<Scalar>::supportsCloning() const
00469 {
00470   return true;
00471 }
00472 
00473 
00474 template <class Scalar>
00475 RCP<Thyra::NonlinearSolverBase<Scalar> >
00476 TimeStepNonlinearSolver<Scalar>::cloneNonlinearSolver() const
00477 {
00478   RCP<TimeStepNonlinearSolver<Scalar> >
00479     nonlinearSolver = Teuchos::rcp(new TimeStepNonlinearSolver<Scalar>);
00480   nonlinearSolver->model_ = model_; // Shallow copy is okay, model is stateless
00481   nonlinearSolver->defaultTol_ = defaultTol_;
00482   nonlinearSolver->defaultMaxIters_ = defaultMaxIters_;
00483   nonlinearSolver->nonlinearSafetyFactor_ = nonlinearSafetyFactor_;
00484   nonlinearSolver->linearSafetyFactor_ = linearSafetyFactor_;
00485   nonlinearSolver->RMinFraction_ = RMinFraction_;
00486   nonlinearSolver->throwOnLinearSolveFailure_ = throwOnLinearSolveFailure_;
00487   // Note: The specification of this virtual function in the interface class
00488   // allows us to just copy the algorithm, not the entire state so we are
00489   // done!
00490   return nonlinearSolver;
00491 }
00492 
00493 
00494 template <class Scalar>
00495 RCP<const Thyra::VectorBase<Scalar> >
00496 TimeStepNonlinearSolver<Scalar>::get_current_x() const
00497 {
00498   return current_x_;
00499 }
00500 
00501 
00502 template <class Scalar>
00503 bool TimeStepNonlinearSolver<Scalar>::is_W_current() const
00504 {
00505   return J_is_current_;
00506 }
00507 
00508 
00509 template <class Scalar>
00510 RCP<Thyra::LinearOpWithSolveBase<Scalar> >
00511 TimeStepNonlinearSolver<Scalar>::get_nonconst_W(const bool forceUpToDate)
00512 {
00513   if (is_null(J_))
00514     return Teuchos::null;
00515   if (forceUpToDate) {
00516 #ifdef RYTHMOS_DEBUG
00517     TEST_FOR_EXCEPT(is_null(current_x_));
00518 #endif
00519     Thyra::eval_f_W<Scalar>( *model_, *current_x_, 0, &*J_ );
00520     J_is_current_ = true;
00521   }
00522   return J_;
00523 }
00524 
00525 
00526 template <class Scalar>
00527 RCP<const Thyra::LinearOpWithSolveBase<Scalar> >
00528 TimeStepNonlinearSolver<Scalar>::get_W() const
00529 {
00530   return J_;
00531 }
00532 
00533 
00534 template <class Scalar>
00535 void TimeStepNonlinearSolver<Scalar>::set_W_is_current(bool W_is_current)
00536 {
00537   J_is_current_ = W_is_current;
00538 }
00539 
00540 
00541 } // namespace Rythmos
00542 
00543 
00544 // Nonmember constructors
00545 
00546 
00547 template <class Scalar>
00548 Teuchos::RCP<Rythmos::TimeStepNonlinearSolver<Scalar> >
00549 Rythmos::timeStepNonlinearSolver()
00550 {
00551   return Teuchos::rcp(new TimeStepNonlinearSolver<Scalar>);
00552 }
00553 
00554 
00555 template <class Scalar>
00556 Teuchos::RCP<Rythmos::TimeStepNonlinearSolver<Scalar> >
00557 Rythmos::timeStepNonlinearSolver(const RCP<ParameterList> &pl)
00558 {
00559   const RCP<Rythmos::TimeStepNonlinearSolver<Scalar> >
00560     solver = timeStepNonlinearSolver<Scalar>();
00561   solver->setParameterList(pl);
00562   return solver;
00563 }
00564 
00565 
00566 // 
00567 // Explicit Instantiation macro
00568 //
00569 // Must be expanded from within the Rythmos namespace!
00570 //
00571 
00572 #define RYTHMOS_TIME_STEP_NONLINEAR_SOLVER_INSTANT(SCALAR) \
00573   \
00574   template class TimeStepNonlinearSolver< SCALAR >; \
00575   \
00576   template RCP<TimeStepNonlinearSolver< SCALAR > > timeStepNonlinearSolver(); \
00577   \
00578   template RCP<TimeStepNonlinearSolver<SCALAR > > \
00579   timeStepNonlinearSolver(const RCP<ParameterList> &pl);
00580 
00581 
00582 
00583 #endif // RYTHMOS_TIME_STEP_NONLINEAR_SOLVER_DEF_HPP
 All Classes Functions Variables Typedefs Friends