|
Rythmos - Transient Integration for Differential Equations
Version of the Day
|
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
1.7.6.1