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