27 #ifndef EWOMS_NEWTON_METHOD_HH 28 #define EWOMS_NEWTON_METHOD_HH 30 #include <dune/common/classname.hh> 31 #include <dune/common/parallel/mpihelper.hh> 33 #include <dune/istl/istlexception.hh> 35 #include <opm/common/Exceptions.hpp> 37 #include <opm/material/densead/Math.hpp> 41 #include <opm/models/nonlinear/newtonmethodparams.hpp> 42 #include <opm/models/nonlinear/newtonmethodproperties.hh> 63 template <
class TypeTag>
79 template<
class TypeTag>
83 template<
class TypeTag>
98 template <
class TypeTag>
116 using Communicator =
typename Dune::MPIHelper::MPICommunicator;
117 using CollectiveCommunication =
typename Dune::Communication<typename Dune::MPIHelper::MPICommunicator>;
121 : simulator_(simulator)
122 , endIterMsgStream_(std::ostringstream::out)
125 , linearSolver_(simulator)
126 , comm_(
Dune::MPIHelper::getCommunicator())
127 , convergenceWriter_(asImp_())
137 LinearSolverBackend::registerParameters();
161 {
return simulator_.problem(); }
167 {
return simulator_.problem(); }
173 {
return simulator_.model(); }
179 {
return simulator_.model(); }
186 {
return params_.tolerance_; }
193 { params_.tolerance_ = value; }
203 const SolutionVector& currentSolution,
204 const GlobalEqVector& solutionUpdate,
205 const GlobalEqVector& currentResidual)
207 asImp_().update_(nextSolution, currentSolution, solutionUpdate, currentResidual);
218 const bool istty = isatty(fileno(stdout));
223 const char* clearRemainingLine =
"\n";
225 static const char ansiClear[] = { 0x1b,
'[',
'K',
'\r', 0 };
226 clearRemainingLine = ansiClear;
230 prePostProcessTimer_.
halt();
231 linearizeTimer_.
halt();
235 SolutionVector& nextSolution =
model().solution(0);
236 SolutionVector currentSolution(nextSolution);
237 GlobalEqVector solutionUpdate(nextSolution.size());
239 Linearizer& linearizer =
model().linearizer();
241 TimerGuard prePostProcessTimerGuard(prePostProcessTimer_);
244 prePostProcessTimer_.
start();
245 asImp_().begin_(nextSolution);
246 prePostProcessTimer_.
stop();
249 TimerGuard innerPrePostProcessTimerGuard(prePostProcessTimer_);
250 TimerGuard linearizeTimerGuard(linearizeTimer_);
261 prePostProcessTimer_.
start();
262 asImp_().beginIteration_();
263 prePostProcessTimer_.
stop();
266 currentSolution = nextSolution;
269 std::cout <<
"Linearize: r(x^k) = dS/dt + div F - q; M = grad r" 270 << clearRemainingLine
275 linearizeTimer_.
start();
276 asImp_().linearizeDomain_();
277 asImp_().linearizeAuxiliaryEquations_();
278 linearizeTimer_.
stop();
281 auto& residual = linearizer.residual();
282 const auto& jacobian = linearizer.jacobian();
283 linearSolver_.prepare(jacobian, residual);
284 linearSolver_.setResidual(residual);
285 linearSolver_.getResidual(residual);
291 updateTimer_.
start();
292 asImp_().preSolve_(currentSolution, residual);
297 std::cout << clearRemainingLine << std::flush;
301 prePostProcessTimer_.
start();
302 asImp_().endIteration_(nextSolution, currentSolution);
303 prePostProcessTimer_.
stop();
310 std::cout <<
"Solve: M deltax^k = r" 311 << clearRemainingLine
318 linearSolver_.setMatrix(jacobian);
319 solutionUpdate = 0.0;
320 const bool conv = linearSolver_.solve(solutionUpdate);
326 std::cout <<
"Newton: Linear solver did not converge\n" << std::flush;
329 prePostProcessTimer_.
start();
331 prePostProcessTimer_.
stop();
338 std::cout <<
"Update: x^(k+1) = x^k - deltax^k" 339 << clearRemainingLine
345 updateTimer_.
start();
346 asImp_().postSolve_(currentSolution,
349 asImp_().update_(nextSolution, currentSolution, solutionUpdate, residual);
354 std::cout << clearRemainingLine
359 prePostProcessTimer_.
start();
360 asImp_().endIteration_(nextSolution, currentSolution);
361 prePostProcessTimer_.
stop();
364 catch (
const Dune::Exception& e)
367 std::cout <<
"Newton method caught exception: \"" 368 << e.what() <<
"\"\n" << std::flush;
371 prePostProcessTimer_.
start();
373 prePostProcessTimer_.
stop();
377 catch (
const NumericalProblem& e)
380 std::cout <<
"Newton method caught exception: \"" 381 << e.what() <<
"\"\n" << std::flush;
384 prePostProcessTimer_.
start();
386 prePostProcessTimer_.
stop();
393 std::cout << clearRemainingLine
398 prePostProcessTimer_.
start();
400 prePostProcessTimer_.
stop();
408 std::cout <<
"Linearization/solve/update time: " 415 <<
"\n" << std::flush;
421 prePostProcessTimer_.
start();
423 prePostProcessTimer_.
stop();
428 prePostProcessTimer_.
start();
429 asImp_().succeeded_();
430 prePostProcessTimer_.
stop();
449 const int nit =
problem().iterationContext().iteration();
450 if (lastSolveFailed_ || nit > params_.targetIterations_) {
451 const int overshoot = lastSolveFailed_ ? params_.targetIterations_ : nit - params_.targetIterations_;
452 Scalar percent = Scalar(overshoot) / params_.targetIterations_;
453 Scalar nextDt = std::max(
problem().minTimeStepSize(),
454 oldDt / (Scalar{1.0} + percent));
458 Scalar percent = Scalar(params_.targetIterations_ - nit) / params_.targetIterations_;
459 Scalar nextDt = std::max(
problem().minTimeStepSize(),
460 oldDt*(Scalar{1.0} + percent / Scalar{1.2}));
469 {
return endIterMsgStream_; }
476 { linearSolver_.eraseMatrix(); }
482 {
return linearSolver_; }
488 {
return linearSolver_; }
490 const Timer& prePostProcessTimer()
const 491 {
return prePostProcessTimer_; }
493 const Timer& linearizeTimer()
const 494 {
return linearizeTimer_; }
496 const Timer& solveTimer()
const 497 {
return solveTimer_; }
499 const Timer& updateTimer()
const 500 {
return updateTimer_; }
507 {
return params_.verbose_ && (comm_.rank() == 0); }
517 lastSolveFailed_ =
false;
519 problem().resetIterationForNewTimestep();
521 if (params_.writeConvergence_) {
522 convergenceWriter_.beginTimeStep();
532 endIterMsgStream_.str(
"");
533 const auto& comm = simulator_.gridView().comm();
534 bool succeeded =
true;
538 catch (
const std::exception& e) {
541 std::cout <<
"rank " << simulator_.gridView().comm().rank()
542 <<
" caught an exception while pre-processing the problem:" << e.what()
543 <<
"\n" << std::flush;
546 succeeded = comm.min(succeeded);
549 throw NumericalProblem(
"pre processing of the problem failed");
560 {
model().linearizer().linearizeDomain(); }
562 void linearizeAuxiliaryEquations_()
564 model().linearizer().linearizeAuxiliaryEquations();
565 model().linearizer().finalize();
568 void preSolve_(
const SolutionVector&,
569 const GlobalEqVector& currentResidual)
571 const auto& constraintsMap =
model().linearizer().constraintsMap();
573 Scalar newtonMaxError = params_.maxError_;
578 for (
unsigned dofIdx = 0; dofIdx < currentResidual.size(); ++dofIdx) {
580 if (dofIdx >=
model().numGridDof() ||
model().dofTotalVolume(dofIdx) <= 0.0) {
585 if (enableConstraints_()) {
586 if (constraintsMap.count(dofIdx) > 0) {
591 const auto& r = currentResidual[dofIdx];
592 for (
unsigned eqIdx = 0; eqIdx < r.size(); ++eqIdx) {
593 error_ = max(std::abs(r[eqIdx] *
model().eqWeight(dofIdx, eqIdx)), error_);
598 error_ = comm_.max(error_);
602 if (error_ > newtonMaxError) {
603 throw NumericalProblem(
"Newton: Error " + std::to_string(
double(error_)) +
604 " is larger than maximum allowed error of " +
605 std::to_string(
double(newtonMaxError)));
622 const GlobalEqVector&,
623 GlobalEqVector& solutionUpdate)
627 const auto& comm = simulator_.gridView().comm();
628 for (
unsigned i = 0; i < simulator_.model().numAuxiliaryModules(); ++i) {
629 bool succeeded =
true;
631 simulator_.model().auxiliaryModule(i)->postSolve(solutionUpdate);
633 catch (
const std::exception& e) {
636 std::cout <<
"rank " << simulator_.gridView().comm().rank()
637 <<
" caught an exception while post processing an auxiliary module:" << e.what()
638 <<
"\n" << std::flush;
641 succeeded = comm.min(succeeded);
644 throw NumericalProblem(
"post processing of an auxilary equation failed");
664 const SolutionVector& currentSolution,
665 const GlobalEqVector& solutionUpdate,
666 const GlobalEqVector& currentResidual)
668 const auto& constraintsMap =
model().linearizer().constraintsMap();
672 asImp_().writeConvergence_(currentSolution, solutionUpdate);
675 if (!std::isfinite(solutionUpdate.one_norm())) {
676 throw NumericalProblem(
"Non-finite update!");
679 std::size_t numGridDof =
model().numGridDof();
680 for (
unsigned dofIdx = 0; dofIdx < numGridDof; ++dofIdx) {
681 if (enableConstraints_()) {
682 if (constraintsMap.count(dofIdx) > 0) {
683 const auto& constraints = constraintsMap.at(dofIdx);
684 asImp_().updateConstraintDof_(dofIdx,
685 nextSolution[dofIdx],
689 asImp_().updatePrimaryVariables_(dofIdx,
690 nextSolution[dofIdx],
691 currentSolution[dofIdx],
692 solutionUpdate[dofIdx],
693 currentResidual[dofIdx]);
697 asImp_().updatePrimaryVariables_(dofIdx,
698 nextSolution[dofIdx],
699 currentSolution[dofIdx],
700 solutionUpdate[dofIdx],
701 currentResidual[dofIdx]);
706 std::size_t numDof =
model().numTotalDof();
707 for (std::size_t dofIdx = numGridDof; dofIdx < numDof; ++dofIdx) {
708 nextSolution[dofIdx] = currentSolution[dofIdx];
709 nextSolution[dofIdx] -= solutionUpdate[dofIdx];
717 PrimaryVariables& nextValue,
718 const Constraints& constraints)
719 { nextValue = constraints; }
725 PrimaryVariables& nextValue,
726 const PrimaryVariables& currentValue,
727 const EqVector& update,
730 nextValue = currentValue;
741 const GlobalEqVector& solutionUpdate)
743 if (params_.writeConvergence_) {
744 convergenceWriter_.beginIteration();
745 convergenceWriter_.writeFields(currentSolution, solutionUpdate);
746 convergenceWriter_.endIteration();
757 const SolutionVector&)
761 const auto& comm = simulator_.gridView().comm();
762 bool succeeded =
true;
766 catch (
const std::exception& e) {
769 std::cout <<
"rank " << simulator_.gridView().comm().rank()
770 <<
" caught an exception while letting the problem post-process:" << e.what()
771 <<
"\n" << std::flush;
774 succeeded = comm.min(succeeded);
777 throw NumericalProblem(
"post processing of the problem failed");
781 std::cout <<
"Newton iteration " <<
problem().iterationContext().iteration() <<
"" 782 <<
" error: " << error_
792 if (
problem().iterationContext().iteration() < 1) {
800 else if (
problem().iterationContext().iteration() >= params_.maxIterations_) {
805 return error_ * 4.0 < lastError_;
817 if (params_.writeConvergence_) {
818 convergenceWriter_.endTimeStep();
828 { lastSolveFailed_ =
true; }
838 static bool enableConstraints_()
839 {
return getPropValue<TypeTag, Properties::EnableConstraints>(); }
841 Simulator& simulator_;
843 Timer prePostProcessTimer_;
844 Timer linearizeTimer_;
848 std::ostringstream endIterMsgStream_;
852 NewtonMethodParams<Scalar> params_;
855 bool lastSolveFailed_ =
false;
857 LinearSolverBackend linearSolver_;
861 CollectiveCommunication comm_;
865 ConvergenceWriter convergenceWriter_;
868 Implementation& asImp_()
869 {
return *
static_cast<Implementation *
>(
this); }
871 const Implementation& asImp_()
const 872 {
return *
static_cast<const Implementation *
>(
this); }
void beginIteration_()
Indicates the beginning of a Newton iteration.
Definition: newtonmethod.hh:529
void succeeded_()
Called if the Newton method was successful.
Definition: newtonmethod.hh:835
void updatePrimaryVariables_(unsigned, PrimaryVariables &nextValue, const PrimaryVariables ¤tValue, const EqVector &update, const EqVector &)
Update a single primary variables object.
Definition: newtonmethod.hh:724
A convergence writer for the Newton method which does nothing.
Definition: nullconvergencewriter.hh:50
void failed_()
Called if the Newton method broke down.
Definition: newtonmethod.hh:827
bool verbose_() const
Returns true if the Newton method ought to be chatty.
Definition: newtonmethod.hh:506
The multi-dimensional Newton method.
Definition: newtonmethod.hh:64
static void registerParameters()
Register all run-time parameters for the Newton method.
Definition: newtonmethod.hh:135
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(...))
Definition: propertysystem.hh:233
Specifies the type of the actual Newton method.
Definition: fvbaseproblem.hh:54
const Problem & problem() const
Returns a reference to the object describing the current physical problem.
Definition: newtonmethod.hh:166
LinearSolverBackend & linearSolver()
Returns the linear solver backend object for external use.
Definition: newtonmethod.hh:481
void start()
Start counting the time resources used by the simulation.
Definition: timer.cpp:46
void end_()
Indicates that we're done solving the non-linear system of equations.
Definition: newtonmethod.hh:815
Definition: fvbaseprimaryvariables.hh:161
void endIteration_(const SolutionVector &, const SolutionVector &)
Indicates that one Newton iteration was finished.
Definition: newtonmethod.hh:756
Problem & problem()
Returns a reference to the object describing the current physical problem.
Definition: newtonmethod.hh:160
Model & model()
Returns a reference to the numeric model.
Definition: newtonmethod.hh:172
The type tag on which the default properties for the Newton method are attached.
Definition: newtonmethod.hh:74
void begin_(const SolutionVector &)
Called before the Newton method is applied to an non-linear system of equations.
Definition: newtonmethod.hh:515
const LinearSolverBackend & linearSolver() const
Returns the linear solver backend object for external use.
Definition: newtonmethod.hh:487
Scalar suggestTimeStepSize(Scalar oldDt) const
Suggest a new time-step size based on the old time-step size.
Definition: newtonmethod.hh:443
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
static void registerParameters()
Registers the parameters in parameter system.
Definition: newtonmethodparams.cpp:36
Declare the properties used by the infrastructure code of the finite volume discretizations.
A convergence writer for the Newton method which does nothing.
void updateConstraintDof_(unsigned, PrimaryVariables &nextValue, const Constraints &constraints)
Update the primary variables for a degree of freedom which is constraint.
Definition: newtonmethod.hh:716
bool apply()
Run the Newton method.
Definition: newtonmethod.hh:216
Specifies the type of the class which writes out the Newton convergence.
Definition: newtonmethodproperties.hh:40
void linearizeDomain_()
Linearize the global non-linear system of equations associated with the spatial domain.
Definition: newtonmethod.hh:559
Scalar tolerance() const
Return the current tolerance at which the Newton method considers itself to be converged.
Definition: newtonmethod.hh:185
double realTimeElapsed() const
Return the real time [s] elapsed during the periods the timer was active since the last reset...
Definition: timer.cpp:90
void setTolerance(Scalar value)
Set the current tolerance at which the Newton method considers itself to be converged.
Definition: newtonmethod.hh:192
void writeConvergence_(const SolutionVector ¤tSolution, const GlobalEqVector &solutionUpdate)
Write the convergence behaviour of the newton method to disk.
Definition: newtonmethod.hh:740
A simple class which makes sure that a timer gets stopped if an exception is thrown.
Definition: timerguard.hh:41
Provides an encapsulation to measure the system time.
Definition: timer.hpp:45
bool converged() const
Returns true if the error of the solution is below the tolerance.
Definition: newtonmethod.hh:154
void applyUpdate(SolutionVector &nextSolution, const SolutionVector ¤tSolution, const GlobalEqVector &solutionUpdate, const GlobalEqVector ¤tResidual)
Public wrapper for applying a Newton update to a solution vector.
Definition: newtonmethod.hh:202
bool proceed_() const
Returns true iff another Newton iteration should be done.
Definition: newtonmethod.hh:790
const Model & model() const
Returns a reference to the numeric model.
Definition: newtonmethod.hh:178
Provides an encapsulation to measure the system time.
void update_(SolutionVector &nextSolution, const SolutionVector ¤tSolution, const GlobalEqVector &solutionUpdate, const GlobalEqVector ¤tResidual)
Update the current solution with a delta vector.
Definition: newtonmethod.hh:663
void eraseMatrix()
Causes the solve() method to discared the structure of the linear system of equations the next time i...
Definition: newtonmethod.hh:475
std::ostringstream & endIterMsg()
Message that should be printed for the user after the end of an iteration.
Definition: newtonmethod.hh:468
void finishInit()
Finialize the construction of the object.
Definition: newtonmethod.hh:147
A simple class which makes sure that a timer gets stopped if an exception is thrown.
void postSolve_(const SolutionVector &, const GlobalEqVector &, GlobalEqVector &solutionUpdate)
Update the error of the solution given the previous iteration.
Definition: newtonmethod.hh:621
void halt()
Stop the measurement reset all timing values.
Definition: timer.cpp:75
Manages the initializing and running of time dependent problems.
Definition: simulator.hh:83
double stop()
Stop counting the time resources.
Definition: timer.cpp:52
Definition: blackoilmodel.hh:75
Declares the properties required by the black oil model.