00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #ifndef RYTHMOS_TIME_STEP_NONLINEAR_SOLVER_HPP
00031 #define RYTHMOS_TIME_STEP_NONLINEAR_SOLVER_HPP
00032
00033 #include "Rythmos_Types.hpp"
00034 #include "Thyra_NonlinearSolverBase.hpp"
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
00042 namespace Rythmos {
00043
00044
00055 template <class Scalar>
00056 class TimeStepNonlinearSolver : public Thyra::NonlinearSolverBase<Scalar> {
00057 public:
00058
00060 typedef Teuchos::ScalarTraits<Scalar> ST;
00062 typedef typename ST::magnitudeType ScalarMag;
00064 typedef Teuchos::ScalarTraits<ScalarMag> SMT;
00065
00068
00070 TimeStepNonlinearSolver();
00071
00073
00076
00078 void setParameterList(RCP<ParameterList> const& paramList);
00080 RCP<ParameterList> getNonconstParameterList();
00082 RCP<ParameterList> unsetParameterList();
00084 RCP<const ParameterList> getParameterList() const;
00086 RCP<const ParameterList> getValidParameters() const;
00087
00089
00092
00094 void setModel(
00095 const RCP<const Thyra::ModelEvaluator<Scalar> > &model
00096 );
00098 RCP<const Thyra::ModelEvaluator<Scalar> > getModel() const;
00100 Thyra::SolveStatus<Scalar> solve(
00101 Thyra::VectorBase<Scalar> *x,
00102 const Thyra::SolveCriteria<Scalar> *solveCriteria,
00103 Thyra::VectorBase<Scalar> *delta = NULL
00104 );
00106 bool supportsCloning() const;
00108 RCP<Thyra::NonlinearSolverBase<Scalar> >
00109 cloneNonlinearSolver() const;
00111 RCP<const Thyra::VectorBase<Scalar> > get_current_x() const;
00113 bool is_W_current() const;
00115 RCP<Thyra::LinearOpWithSolveBase<Scalar> >
00116 get_nonconst_W(const bool forceUpToDate);
00118 RCP<const Thyra::LinearOpWithSolveBase<Scalar> > get_W() const;
00120 void set_W_is_current(bool W_is_current);
00121
00123
00124 private:
00125
00126
00127
00128 RCP<ParameterList> paramList_;
00129 RCP<const Thyra::ModelEvaluator<Scalar> > model_;
00130 RCP<Thyra::LinearOpWithSolveBase<Scalar> > J_;
00131 RCP<Thyra::VectorBase<Scalar> > current_x_;
00132 bool J_is_current_;
00133
00134 double defaultTol_;
00135 int defaultMaxIters_;
00136 double nonlinearSafetyFactor_;
00137 double linearSafetyFactor_;
00138 double RMinFraction_;
00139 bool throwOnLinearSolveFailure_;
00140
00141
00142
00143 static const std::string DefaultTol_name_;
00144 static const double DefaultTol_default_;
00145
00146 static const std::string DefaultMaxIters_name_;
00147 static const int DefaultMaxIters_default_;
00148
00149 static const std::string NonlinearSafetyFactor_name_;
00150 static const double NonlinearSafetyFactor_default_;
00151
00152 static const std::string LinearSafetyFactor_name_;
00153 static const double LinearSafetyFactor_default_;
00154
00155 static const std::string RMinFraction_name_;
00156 static const double RMinFraction_default_;
00157
00158 static const std::string ThrownOnLinearSolveFailure_name_;
00159 static const bool ThrownOnLinearSolveFailure_default_;
00160
00161 };
00162
00163
00168 template <class Scalar>
00169 RCP<TimeStepNonlinearSolver<Scalar> > timeStepNonlinearSolver()
00170 {
00171 return Teuchos::rcp(new TimeStepNonlinearSolver<Scalar>);
00172 }
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 template<class Scalar>
00183 const std::string
00184 TimeStepNonlinearSolver<Scalar>::DefaultTol_name_ = "Default Tol";
00185
00186 template<class Scalar>
00187 const double
00188 TimeStepNonlinearSolver<Scalar>::DefaultTol_default_ = 1e-2;
00189
00190
00191 template<class Scalar>
00192 const std::string
00193 TimeStepNonlinearSolver<Scalar>::DefaultMaxIters_name_ = "Default Max Iters";
00194
00195 template<class Scalar>
00196 const int
00197 TimeStepNonlinearSolver<Scalar>::DefaultMaxIters_default_ = 3;
00198
00199
00200 template<class Scalar>
00201 const std::string
00202 TimeStepNonlinearSolver<Scalar>::NonlinearSafetyFactor_name_
00203 = "Nonlinear Safety Factor";
00204
00205 template<class Scalar>
00206 const double
00207 TimeStepNonlinearSolver<Scalar>::NonlinearSafetyFactor_default_ = 0.1;
00208
00209
00210 template<class Scalar>
00211 const std::string
00212 TimeStepNonlinearSolver<Scalar>::LinearSafetyFactor_name_ = "Linear Safety Factor";
00213
00214 template<class Scalar>
00215 const double
00216 TimeStepNonlinearSolver<Scalar>::LinearSafetyFactor_default_ = 0.05;
00217
00218
00219 template<class Scalar>
00220 const std::string
00221 TimeStepNonlinearSolver<Scalar>::RMinFraction_name_ = "R Min Fraction";
00222
00223 template<class Scalar>
00224 const double
00225 TimeStepNonlinearSolver<Scalar>::RMinFraction_default_ = 0.3;
00226
00227
00228 template<class Scalar>
00229 const std::string
00230 TimeStepNonlinearSolver<Scalar>::ThrownOnLinearSolveFailure_name_
00231 = "Thrown on Linear Solve Failure";
00232
00233 template<class Scalar>
00234 const bool
00235 TimeStepNonlinearSolver<Scalar>::ThrownOnLinearSolveFailure_default_ = false;
00236
00237
00238
00239
00240
00241 template <class Scalar>
00242 TimeStepNonlinearSolver<Scalar>::TimeStepNonlinearSolver()
00243 :J_is_current_(false),
00244 defaultTol_(DefaultTol_default_),
00245 defaultMaxIters_(DefaultMaxIters_default_),
00246 nonlinearSafetyFactor_(NonlinearSafetyFactor_default_),
00247 linearSafetyFactor_(LinearSafetyFactor_default_),
00248 RMinFraction_(RMinFraction_default_),
00249 throwOnLinearSolveFailure_(ThrownOnLinearSolveFailure_default_)
00250 {}
00251
00252
00253
00254
00255
00256 template<class Scalar>
00257 void TimeStepNonlinearSolver<Scalar>::setParameterList(
00258 RCP<ParameterList> const& paramList
00259 )
00260 {
00261 using Teuchos::get;
00262 TEST_FOR_EXCEPT(is_null(paramList));
00263 paramList->validateParametersAndSetDefaults(*getValidParameters(),0);
00264 paramList_ = paramList;
00265 defaultTol_ = get<double>(*paramList_,DefaultTol_name_);
00266 defaultMaxIters_ = get<int>(*paramList_,DefaultMaxIters_name_);
00267 nonlinearSafetyFactor_ = get<double>(*paramList_,NonlinearSafetyFactor_name_);
00268 linearSafetyFactor_ = get<double>(*paramList_,LinearSafetyFactor_name_);
00269 RMinFraction_ = get<double>(*paramList_,RMinFraction_name_);
00270 throwOnLinearSolveFailure_ = get<bool>(
00271 *paramList_,ThrownOnLinearSolveFailure_name_);
00272 Teuchos::readVerboseObjectSublist(&*paramList_,this);
00273 #ifdef TEUCHOS_DEBUG
00274 paramList_->validateParameters(*getValidParameters(),0);
00275 #endif // TEUCHOS_DEBUG
00276 }
00277
00278
00279 template<class Scalar>
00280 RCP<ParameterList>
00281 TimeStepNonlinearSolver<Scalar>::getNonconstParameterList()
00282 {
00283 return paramList_;
00284 }
00285
00286
00287 template<class Scalar>
00288 RCP<ParameterList>
00289 TimeStepNonlinearSolver<Scalar>::unsetParameterList()
00290 {
00291 RCP<ParameterList> _paramList = paramList_;
00292 paramList_ = Teuchos::null;
00293 return _paramList;
00294 }
00295
00296
00297 template<class Scalar>
00298 RCP<const ParameterList>
00299 TimeStepNonlinearSolver<Scalar>::getParameterList() const
00300 {
00301 return paramList_;
00302 }
00303
00304
00305 template<class Scalar>
00306 RCP<const ParameterList>
00307 TimeStepNonlinearSolver<Scalar>::getValidParameters() const
00308 {
00309 using Teuchos::setDoubleParameter; using Teuchos::setIntParameter;
00310 static RCP<const ParameterList> validPL;
00311 if (is_null(validPL)) {
00312 RCP<ParameterList> pl = Teuchos::parameterList();
00313 setDoubleParameter(
00314 DefaultTol_name_, DefaultTol_default_,
00315 "The default base tolerance for the nonlinear timestep solve.\n"
00316 "This tolerance can be overridden ???",
00317 &*pl );
00318 setIntParameter(
00319 DefaultMaxIters_name_, DefaultMaxIters_default_,
00320 "The default maximum number of Newton iterations to perform.\n"
00321 "This default can be overridden ???",
00322 &*pl );
00323 setDoubleParameter(
00324 NonlinearSafetyFactor_name_, NonlinearSafetyFactor_default_,
00325 "The factor (< 1.0) to multiply tol to bound R*||dx|||.\n"
00326 "The exact nonlinear convergence test is:\n"
00327 " R*||dx|| <= \"" + NonlinearSafetyFactor_name_ + "\" * tol.",
00328 &*pl );
00329 setDoubleParameter(
00330 LinearSafetyFactor_name_, LinearSafetyFactor_default_,
00331 "This factor multiplies the nonlinear safety factor which multiplies\n"
00332 "tol when determining the linear solve tolerence.\n"
00333 "The exact linear convergence tolerance is:\n"
00334 " ||J*dx+f||/||f|| <= \"" + LinearSafetyFactor_name_ + "\" * "
00335 "\"" + NonlinearSafetyFactor_name_ + "\" * tol.",
00336 &*pl );
00337 setDoubleParameter(
00338 RMinFraction_name_, RMinFraction_default_,
00339 "The faction below which the R factor is not allowed to drop\n"
00340 "below each Newton iteration. The R factor is related to the\n"
00341 "ratio of ||dx||/||dx_last|| between nonlinear iterations.",
00342 &*pl );
00343 pl->set(
00344 ThrownOnLinearSolveFailure_name_, ThrownOnLinearSolveFailure_default_,
00345 "If set to true (\"1\"), then an Thyra::CatastrophicSolveFailure\n"
00346 "exception will be thrown when a linear solve fails to meet it's tolerance."
00347 );
00348 Teuchos::setupVerboseObjectSublist(&*pl);
00349 validPL = pl;
00350 }
00351 return validPL;
00352 }
00353
00354
00355
00356
00357
00358 template <class Scalar>
00359 void TimeStepNonlinearSolver<Scalar>::setModel(
00360 const RCP<const Thyra::ModelEvaluator<Scalar> > &model
00361 )
00362 {
00363 TEST_FOR_EXCEPT(model.get()==NULL);
00364 model_ = model;
00365 J_ = Teuchos::null;
00366 current_x_ = Teuchos::null;
00367 J_is_current_ = false;
00368 }
00369
00370
00371 template <class Scalar>
00372 RCP<const Thyra::ModelEvaluator<Scalar> >
00373 TimeStepNonlinearSolver<Scalar>::getModel() const
00374 {
00375 return model_;
00376 }
00377
00378 template <class Scalar>
00379 Thyra::SolveStatus<Scalar>
00380 TimeStepNonlinearSolver<Scalar>::solve(
00381 Thyra::VectorBase<Scalar> *x,
00382 const Thyra::SolveCriteria<Scalar> *solveCriteria,
00383 Thyra::VectorBase<Scalar> *delta
00384 )
00385 {
00386
00387 #ifdef ENABLE_RYTHMOS_TIMERS
00388 TEUCHOS_FUNC_TIME_MONITOR("Rythmos:TimeStepNonlinearSolver::solve");
00389 #endif
00390
00391 using std::endl;
00392 using Teuchos::incrVerbLevel;
00393 using Teuchos::describe;
00394 using Teuchos::as;
00395 using Teuchos::rcp;
00396 using Teuchos::OSTab;
00397 using Teuchos::getFancyOStream;
00398 typedef Thyra::ModelEvaluatorBase MEB;
00399 typedef Teuchos::VerboseObjectTempState<MEB> VOTSME;
00400 typedef Thyra::LinearOpWithSolveBase<Scalar> LOWSB;
00401 typedef Teuchos::VerboseObjectTempState<LOWSB> VOTSLOWSB;
00402
00403 #ifdef TEUCHOS_DEBUG
00404 TEST_FOR_EXCEPT(0==x);
00405 THYRA_ASSERT_VEC_SPACES(
00406 "TimeStepNonlinearSolver<Scalar>::solve(...)",
00407 *x->space(),*model_->get_x_space() );
00408 TEST_FOR_EXCEPT(
00409 0!=solveCriteria && "ToDo: Support passed in solve criteria!" );
00410 #endif
00411
00412 const RCP<Teuchos::FancyOStream> out = this->getOStream();
00413 const Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
00414 const bool showNewtonDetails =
00415 (!is_null(out) && (as<int>(verbLevel) >= as<int>(Teuchos::VERB_MEDIUM)));
00416 const bool dumpAll =
00417 (!is_null(out) && (as<int>(verbLevel) == as<int>(Teuchos::VERB_EXTREME)));
00418 TEUCHOS_OSTAB;
00419 VOTSME stateModel_outputTempState(model_,out,incrVerbLevel(verbLevel,-1));
00420
00421 if (showNewtonDetails)
00422 *out
00423 << "\nEntering TimeStepNonlinearSolver::solve(...) ...\n"
00424 << "\nmodel = " << Teuchos::describe(*model_,verbLevel);
00425
00426 if(dumpAll) {
00427 *out << "\nInitial guess:\n";
00428 *out << "\nx = " << *x;
00429 }
00430
00431
00432 if(!J_.get()) J_ = model_->create_W();
00433 RCP<Thyra::VectorBase<Scalar> > f = createMember(model_->get_f_space());
00434 RCP<Thyra::VectorBase<Scalar> > dx = createMember(model_->get_x_space());
00435 RCP<Thyra::VectorBase<Scalar> > dx_last = createMember(model_->get_x_space());
00436 RCP<Thyra::VectorBase<Scalar> > x_curr = createMember(model_->get_x_space());
00437 if (delta != NULL)
00438 Thyra::V_S(delta,ST::zero());
00439 Thyra::assign(&*x_curr,*x);
00440 J_is_current_ = false;
00441 current_x_ = Teuchos::null;
00442
00443
00444 ScalarMag R = SMT::one();
00445 ScalarMag linearTolSafety = linearSafetyFactor_ * nonlinearSafetyFactor_;
00446 int maxIters = defaultMaxIters_;
00447 ScalarMag tol = defaultTol_;
00448
00449
00450
00451 bool converged = false;
00452 bool sawFailedLinearSolve = false;
00453 Thyra::SolveStatus<Scalar> failedLinearSolveStatus;
00454 ScalarMag nrm_dx = SMT::nan();
00455 ScalarMag nrm_dx_last = SMT::nan();
00456 int iter = 1;
00457 for( ; iter <= maxIters; ++iter ) {
00458 if (showNewtonDetails)
00459 *out << "\n*** newtonIter = " << iter << endl;
00460 if (showNewtonDetails)
00461 *out << "\nEvaluating the model f and W ...\n";
00462 Thyra::eval_f_W( *model_, *x_curr, &*f, &*J_ );
00463 if (showNewtonDetails)
00464 *out << "\nSolving the system J*dx = -f ...\n";
00465 Thyra::V_S(&*dx,ST::zero());
00466 Thyra::SolveCriteria<Scalar>
00467 linearSolveCriteria(
00468 Thyra::SolveMeasureType(
00469 Thyra::SOLVE_MEASURE_NORM_RESIDUAL, Thyra::SOLVE_MEASURE_NORM_RHS
00470 ),
00471 linearTolSafety*tol
00472 );
00473 VOTSLOWSB J_outputTempState(J_,out,incrVerbLevel(verbLevel,-1));
00474 Thyra::SolveStatus<Scalar> linearSolveStatus
00475 = Thyra::solve( *J_, Thyra::NOTRANS, *f, &*dx, &linearSolveCriteria );
00476 if (showNewtonDetails)
00477 *out << "\nLinear solve status:\n" << linearSolveStatus;
00478 Thyra::Vt_S(&*dx,Scalar(-ST::one()));
00479 if (dumpAll)
00480 *out << "\ndx = " << Teuchos::describe(*dx,verbLevel);
00481 if (delta != NULL) {
00482 Thyra::Vp_V(delta,*dx);
00483 if (dumpAll)
00484 *out << "\ndelta = " << Teuchos::describe(*delta,verbLevel);
00485 }
00486
00487 if(linearSolveStatus.solveStatus != Thyra::SOLVE_STATUS_CONVERGED) {
00488 sawFailedLinearSolve = true;
00489 failedLinearSolveStatus = linearSolveStatus;
00490 if (throwOnLinearSolveFailure_) {
00491 TEST_FOR_EXCEPTION(
00492 throwOnLinearSolveFailure_, Thyra::CatastrophicSolveFailure,
00493 "Error, the linear solver did not converge!"
00494 );
00495 }
00496 if (showNewtonDetails)
00497 *out << "\nWarning, linear solve did not converge! Continuing anyway :-)\n";
00498 }
00499
00500 Vp_V( &*x_curr, *dx );
00501 if (dumpAll)
00502 *out << "\nUpdated solution x = " << Teuchos::describe(*x_curr,verbLevel);
00503
00504 nrm_dx = Thyra::norm(*dx);
00505 if ( R*nrm_dx <= nonlinearSafetyFactor_*tol )
00506 converged = true;
00507 if (showNewtonDetails)
00508 *out
00509 << "\nConvergence test:\n"
00510 << " R*||dx|| = " << R << "*" << nrm_dx
00511 << " = " << (R*nrm_dx) << "\n"
00512 << " <= nonlinearSafetyFactor*tol = " << nonlinearSafetyFactor_ << "*" << tol
00513 << " = " << (nonlinearSafetyFactor_*tol)
00514 << " : " << ( converged ? "converged!" : " unconverged" )
00515 << endl;
00516 if(converged)
00517 break;
00518
00519 if(iter > 1) {
00520 const Scalar
00521 MinR = RMinFraction_*R,
00522 nrm_dx_ratio = nrm_dx/nrm_dx_last;
00523 R = std::max(MinR,nrm_dx_ratio);
00524 if (showNewtonDetails)
00525 *out
00526 << "\nUpdated R\n"
00527 << " = max(RMinFraction*R,||dx||/||dx_last||)\n"
00528 << " = max("<<RMinFraction_<<"*"<<R<<","<<nrm_dx<<"/"<<nrm_dx_last<<")\n"
00529 << " = max("<<MinR<<","<<nrm_dx_ratio<<")\n"
00530 << " = " << R << endl;
00531 }
00532
00533 std::swap(dx_last,dx);
00534 nrm_dx_last = nrm_dx;
00535 }
00536
00537
00538 Thyra::assign(x,*x_curr);
00539
00540 if (dumpAll)
00541 *out << "\nFinal solution x = " << Teuchos::describe(*x,verbLevel);
00542
00543
00544
00545 Thyra::SolveStatus<Scalar> solveStatus;
00546
00547 std::ostringstream oss;
00548 Teuchos::FancyOStream omsg(rcp(&oss,false));
00549
00550 omsg << "Solver: " << this->description() << endl;
00551
00552 if(converged) {
00553 solveStatus.solveStatus = Thyra::SOLVE_STATUS_CONVERGED;
00554 omsg << "CVODE status test converged!\n";
00555 }
00556 else {
00557 solveStatus.solveStatus = Thyra::SOLVE_STATUS_UNCONVERGED;
00558 omsg << "CVODE status test failed!\n";
00559 }
00560
00561 if (sawFailedLinearSolve) {
00562 omsg << "Warning! A failed linear solve was encountered with status:\n";
00563 OSTab tab(omsg);
00564 omsg << failedLinearSolveStatus;
00565 }
00566
00567 omsg
00568 << "R*||dx|| = " << R << "*" << nrm_dx
00569 << " <= nonlinearSafetyFactor*tol = " << nonlinearSafetyFactor_ << "*" << tol << " : "
00570 << ( converged ? "converged!" : " unconverged" ) << endl;
00571
00572 omsg
00573 << "Iterations = " << iter;
00574
00575
00576
00577 solveStatus.message = oss.str();
00578
00579
00580 current_x_ = x->clone_v();
00581 J_is_current_ = false;
00582
00583
00584
00585
00586
00587 if (showNewtonDetails)
00588 *out << "\nLeaving TimeStepNonlinearSolver::solve(...) ...\n";
00589
00590 return solveStatus;
00591
00592 }
00593
00594
00595 template <class Scalar>
00596 bool TimeStepNonlinearSolver<Scalar>::supportsCloning() const
00597 {
00598 return true;
00599 }
00600
00601
00602 template <class Scalar>
00603 RCP<Thyra::NonlinearSolverBase<Scalar> >
00604 TimeStepNonlinearSolver<Scalar>::cloneNonlinearSolver() const
00605 {
00606 RCP<TimeStepNonlinearSolver<Scalar> >
00607 nonlinearSolver = Teuchos::rcp(new TimeStepNonlinearSolver<Scalar>);
00608 nonlinearSolver->model_ = model_;
00609 nonlinearSolver->defaultTol_ = defaultTol_;
00610 nonlinearSolver->defaultMaxIters_ = defaultMaxIters_;
00611 nonlinearSolver->nonlinearSafetyFactor_ = nonlinearSafetyFactor_;
00612 nonlinearSolver->linearSafetyFactor_ = linearSafetyFactor_;
00613 nonlinearSolver->RMinFraction_ = RMinFraction_;
00614 nonlinearSolver->throwOnLinearSolveFailure_ = throwOnLinearSolveFailure_;
00615
00616
00617
00618 return nonlinearSolver;
00619 }
00620
00621
00622 template <class Scalar>
00623 RCP<const Thyra::VectorBase<Scalar> >
00624 TimeStepNonlinearSolver<Scalar>::get_current_x() const
00625 {
00626 return current_x_;
00627 }
00628
00629
00630 template <class Scalar>
00631 bool TimeStepNonlinearSolver<Scalar>::is_W_current() const
00632 {
00633 return J_is_current_;
00634 }
00635
00636
00637 template <class Scalar>
00638 RCP<Thyra::LinearOpWithSolveBase<Scalar> >
00639 TimeStepNonlinearSolver<Scalar>::get_nonconst_W(const bool forceUpToDate)
00640 {
00641 if (is_null(J_))
00642 return Teuchos::null;
00643 if (forceUpToDate) {
00644 #ifdef TEUCHOS_DEBUG
00645 TEST_FOR_EXCEPT(is_null(current_x_));
00646 #endif
00647 Thyra::eval_f_W<Scalar>( *model_, *current_x_, 0, &*J_ );
00648 J_is_current_ = true;
00649 }
00650 return J_;
00651 }
00652
00653
00654 template <class Scalar>
00655 RCP<const Thyra::LinearOpWithSolveBase<Scalar> >
00656 TimeStepNonlinearSolver<Scalar>::get_W() const
00657 {
00658 return J_;
00659 }
00660
00661
00662 template <class Scalar>
00663 void TimeStepNonlinearSolver<Scalar>::set_W_is_current(bool W_is_current)
00664 {
00665 J_is_current_ = W_is_current;
00666 }
00667
00668
00669 }
00670
00671
00672 #endif // RYTHMOS_TIME_STEP_NONLINEAR_SOLVER_HPP