version 3.10-dev
nonlinear/newtonsolver.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3//
4// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
12#ifndef DUMUX_NEWTON_SOLVER_HH
13#define DUMUX_NEWTON_SOLVER_HH
14
15#include <cmath>
16#include <memory>
17#include <iostream>
18#include <type_traits>
19#include <algorithm>
20#include <numeric>
21
22#include <dune/common/timer.hh>
23#include <dune/common/exceptions.hh>
24#include <dune/common/parallel/mpicommunication.hh>
25#include <dune/common/parallel/mpihelper.hh>
26#include <dune/common/std/type_traits.hh>
27#include <dune/common/indices.hh>
28#include <dune/common/hybridutilities.hh>
29
30#include <dune/istl/bvector.hh>
31#include <dune/istl/multitypeblockvector.hh>
32
40
41#include <dumux/io/format.hh>
42
45
48
50
51// Helper boolean that states if the assembler exports grid variables
52template<class Assembler> using AssemblerGridVariablesType = typename Assembler::GridVariables;
53template<class Assembler>
54inline constexpr bool assemblerExportsGridVariables
55 = Dune::Std::is_detected_v<AssemblerGridVariablesType, Assembler>;
56
57// helper struct to define the variables on which the privarswitch should operate
58template<class Assembler, bool exportsGridVars = assemblerExportsGridVariables<Assembler>>
59struct PriVarSwitchVariablesType { using Type = typename Assembler::GridVariables; };
60
61// if assembler does not export them, use an empty class. These situations either mean
62// that there is no privarswitch, or, it is handled by a derived implementation.
63template<class Assembler>
64struct PriVarSwitchVariablesType<Assembler, false>
65{ using Type = struct EmptyGridVariables {}; };
66
67// Helper alias to deduce the variables types used in the privarswitch adapter
68template<class Assembler>
71
74{
75 template<class Assembler>
76 auto operator()(Assembler&& a)
77 -> decltype(a.assembleJacobianAndResidual(std::declval<const typename Assembler::SolutionVector&>(),
78 std::declval<const PartialReassembler<Assembler>*>()))
79 {}
80};
81
82// helpers to implement max relative shift
83template<class C> using dynamicIndexAccess = decltype(std::declval<C>()[0]);
84template<class C> using staticIndexAccess = decltype(std::declval<C>()[Dune::Indices::_0]);
85template<class C> static constexpr auto hasDynamicIndexAccess = Dune::Std::is_detected<dynamicIndexAccess, C>{};
86template<class C> static constexpr auto hasStaticIndexAccess = Dune::Std::is_detected<staticIndexAccess, C>{};
87
88template<class V, class Scalar, class Reduce, class Transform>
89auto hybridInnerProduct(const V& v1, const V& v2, Scalar init, Reduce&& r, Transform&& t)
90-> std::enable_if_t<hasDynamicIndexAccess<V>(), Scalar>
91{
92 return std::inner_product(v1.begin(), v1.end(), v2.begin(), init, std::forward<Reduce>(r), std::forward<Transform>(t));
93}
94
95template<class V, class Scalar, class Reduce, class Transform>
96auto hybridInnerProduct(const V& v1, const V& v2, Scalar init, Reduce&& r, Transform&& t)
97-> std::enable_if_t<hasStaticIndexAccess<V>() && !hasDynamicIndexAccess<V>(), Scalar>
98{
99 using namespace Dune::Hybrid;
100 forEach(std::make_index_sequence<V::N()>{}, [&](auto i){
101 init = r(init, hybridInnerProduct(v1[Dune::index_constant<i>{}], v2[Dune::index_constant<i>{}], init, std::forward<Reduce>(r), std::forward<Transform>(t)));
102 });
103 return init;
104}
105
106// Maximum relative shift at a degree of freedom.
107// For (primary variables) values below 1.0 we use
108// an absolute shift.
109template<class Scalar, class V>
110auto maxRelativeShift(const V& v1, const V& v2)
111-> std::enable_if_t<Dune::IsNumber<V>::value, Scalar>
112{
113 using std::abs; using std::max;
114 return abs(v1 - v2)/max<Scalar>(1.0, abs(v1 + v2)*0.5);
115}
116
117// Maximum relative shift for generic vector types.
118// Recursively calls maxRelativeShift until Dune::IsNumber is true.
119template<class Scalar, class V>
120auto maxRelativeShift(const V& v1, const V& v2)
121-> std::enable_if_t<!Dune::IsNumber<V>::value, Scalar>
122{
123 return hybridInnerProduct(v1, v2, Scalar(0.0),
124 [](const auto& a, const auto& b){ using std::max; return max(a, b); },
125 [](const auto& a, const auto& b){ return maxRelativeShift<Scalar>(a, b); }
126 );
127}
128
129template<class To, class From>
130void assign(To& to, const From& from)
131{
132 if constexpr (hasStaticIndexAccess<To>() && hasStaticIndexAccess<To>() && !hasDynamicIndexAccess<From>() && !hasDynamicIndexAccess<From>())
133 {
134 using namespace Dune::Hybrid;
135 forEach(std::make_index_sequence<To::N()>{}, [&](auto i){
136 assign(to[Dune::index_constant<i>{}], from[Dune::index_constant<i>{}]);
137 });
138 }
139
140 else if constexpr (std::is_assignable<To&, From>::value)
141 to = from;
142
143 else if constexpr (hasDynamicIndexAccess<To>() && hasDynamicIndexAccess<From>())
144 for (decltype(to.size()) i = 0; i < to.size(); ++i)
145 assign(to[i], from[i]);
146
147 else if constexpr (hasDynamicIndexAccess<To>() && Dune::IsNumber<From>::value)
148 {
149 assert(to.size() == 1);
150 assign(to[0], from);
151 }
152
153 else if constexpr (Dune::IsNumber<To>::value && hasDynamicIndexAccess<From>())
154 {
155 assert(from.size() == 1);
156 assign(to, from[0]);
157 }
158
159 else
160 DUNE_THROW(Dune::Exception, "Values are not assignable to each other!");
161}
162
163} // end namespace Dumux::Detail::Newton
164
165namespace Dumux {
166
177template <class Assembler, class LinearSolver,
178 class Reassembler = PartialReassembler<Assembler>,
179 class Comm = Dune::Communication<Dune::MPIHelper::MPICommunicator> >
180class NewtonSolver : public PDESolver<Assembler, LinearSolver>
181{
183
184protected:
186 using SolutionVector = typename Backend::DofVector;
187 using ResidualVector = typename Assembler::ResidualType;
189private:
190 using Scalar = typename Assembler::Scalar;
191 using JacobianMatrix = typename Assembler::JacobianMatrix;
194
195 // enable models with primary variable switch
196 // TODO: Always use ParentType::Variables once we require assemblers to export variables
197 static constexpr bool assemblerExportsVariables = Detail::PDESolver::assemblerExportsVariables<Assembler>;
198 using PriVarSwitchVariables
199 = std::conditional_t<assemblerExportsVariables,
200 typename ParentType::Variables,
203
204public:
205 using typename ParentType::Variables;
206 using Communication = Comm;
207
208 NewtonSolver(std::shared_ptr<Assembler> assembler,
209 std::shared_ptr<LinearSolver> linearSolver,
210 const Communication& comm = Dune::MPIHelper::getCommunication(),
211 const std::string& paramGroup = "",
212 const std::string& paramGroupName = "Newton",
213 int verbosity = 2)
215 , endIterMsgStream_(std::ostringstream::out)
216 , comm_(comm)
217 , paramGroup_(paramGroup)
218 , solverName_(paramGroupName)
219 , priVarSwitchAdapter_(std::make_unique<PrimaryVariableSwitchAdapter>(paramGroup))
220 {
221 verbosity_ = comm_.rank() == 0 ? getParamFromGroup<int>(paramGroup, solverName_ + ".Verbosity", verbosity) : 0;
222
223 initParams_(paramGroup);
224
225 // set the linear system (matrix & residual) in the assembler
226 this->assembler().setLinearSystem();
227
228 // set a different default for the linear solver residual reduction
229 // within the Newton the linear solver doesn't need to solve too exact
230 this->linearSolver().setResidualReduction(getParamFromGroup<Scalar>(paramGroup, "LinearSolver.ResidualReduction", 1e-6));
231
232 // initialize the partial reassembler
233 if (enablePartialReassembly_)
234 partialReassembler_ = std::make_unique<Reassembler>(this->assembler());
235 }
236
238 const Communication& comm() const
239 { return comm_; }
240
248 void setMaxRelativeShift(Scalar tolerance)
249 { shiftTolerance_ = tolerance; }
250
257 void setMaxAbsoluteResidual(Scalar tolerance)
258 { residualTolerance_ = tolerance; }
259
266 void setResidualReduction(Scalar tolerance)
267 { reductionTolerance_ = tolerance; }
268
279 void setTargetSteps(int targetSteps)
280 { targetSteps_ = targetSteps; }
281
288 void setMinSteps(int minSteps)
289 { minSteps_ = minSteps; }
290
297 void setMaxSteps(int maxSteps)
298 { maxSteps_ = maxSteps; }
299
307 void solve(Variables& vars, TimeLoop& timeLoop) override
308 {
309 if constexpr (!assemblerExportsVariables)
310 {
311 if (this->assembler().isStationaryProblem())
312 DUNE_THROW(Dune::InvalidStateException, "Using time step control with stationary problem makes no sense!");
313 }
314
315 // try solving the non-linear system
316 for (std::size_t i = 0; i <= maxTimeStepDivisions_; ++i)
317 {
318 // linearize & solve
319 const bool converged = solve_(vars);
320
321 if (converged)
322 return;
323
324 else if (!converged && i < maxTimeStepDivisions_)
325 {
326 if constexpr (assemblerExportsVariables)
327 DUNE_THROW(Dune::NotImplemented, "Time step reset for new assembly methods");
328 else
329 {
330 // set solution to previous solution & reset time step
331 Backend::update(vars, this->assembler().prevSol());
332 this->assembler().resetTimeStep(Backend::dofs(vars));
333
334 if (verbosity_ >= 1)
335 {
336 const auto dt = timeLoop.timeStepSize();
337 std::cout << Fmt::format("{} solver did not converge with dt = {} seconds. ", solverName_, dt)
338 << Fmt::format("Retrying with time step of dt = {} seconds.\n", dt*retryTimeStepReductionFactor_);
339 }
340
341 // try again with dt = dt * retryTimeStepReductionFactor_
342 timeLoop.setTimeStepSize(timeLoop.timeStepSize() * retryTimeStepReductionFactor_);
343 }
344 }
345
346 else
347 {
348 DUNE_THROW(NumericalProblem,
349 Fmt::format("{} solver didn't converge after {} time-step divisions; dt = {}.\n",
350 solverName_, maxTimeStepDivisions_, timeLoop.timeStepSize()));
351 }
352 }
353 }
354
361 void solve(Variables& vars) override
362 {
363 const bool converged = solve_(vars);
364 if (!converged)
365 DUNE_THROW(NumericalProblem,
366 Fmt::format("{} solver didn't converge after {} iterations.\n", solverName_, numSteps_));
367 }
368
377 bool apply(Variables& vars) override
378 {
379 return solve_(vars);
380 }
381
388 virtual void newtonBegin(Variables& initVars)
389 {
390 numSteps_ = 0;
391
392 if constexpr (hasPriVarsSwitch<PriVarSwitchVariables>)
393 {
394 if constexpr (assemblerExportsVariables)
395 priVarSwitchAdapter_->initialize(Backend::dofs(initVars), initVars);
396 else // this assumes assembly with solution (i.e. Variables=SolutionVector)
397 priVarSwitchAdapter_->initialize(initVars, this->assembler().gridVariables());
398 }
399
400
401 const auto& initSol = Backend::dofs(initVars);
402
403 // write the initial residual if a convergence writer was set
404 if (convergenceWriter_)
405 {
406 this->assembler().assembleResidual(initVars);
407
408 // dummy vector, there is no delta before solving the linear system
409 ResidualVector delta = LinearAlgebraNativeBackend::zeros(Backend::size(initSol));
410 convergenceWriter_->write(initSol, delta, this->assembler().residual());
411 }
412
413 if (enablePartialReassembly_)
414 {
415 partialReassembler_->resetColors();
416 resizeDistanceFromLastLinearization_(initSol, distanceFromLastLinearization_);
417 }
418 }
419
426 virtual bool newtonProceed(const Variables &varsCurrentIter, bool converged)
427 {
428 if (numSteps_ < minSteps_)
429 return true;
430 else if (converged)
431 return false; // we are below the desired tolerance
432 else if (numSteps_ >= maxSteps_)
433 {
434 // We have exceeded the allowed number of steps. If the
435 // maximum relative shift was reduced by a factor of at least 4,
436 // we proceed even if we are above the maximum number of steps.
437 if (enableShiftCriterion_)
438 return shift_*4.0 < lastShift_;
439 else
440 return reduction_*4.0 < lastReduction_;
441 }
442
443 return true;
444 }
445
449 virtual void newtonBeginStep(const Variables& vars)
450 {
452 if (numSteps_ == 0)
453 {
454 lastReduction_ = 1.0;
455 }
456 else
457 {
459 }
460 }
461
467 virtual void assembleLinearSystem(const Variables& vars)
468 {
469 assembleLinearSystem_(this->assembler(), vars);
470
471 if (enablePartialReassembly_)
472 partialReassembler_->report(comm_, endIterMsgStream_);
473 }
474
487 {
488 bool converged = false;
489
490 try
491 {
492 if (numSteps_ == 0)
493 initialResidual_ = this->linearSolver().norm(this->assembler().residual());
494
495 // solve by calling the appropriate implementation depending on whether the linear solver
496 // is capable of handling MultiType matrices or not
497 converged = solveLinearSystem_(deltaU);
498 }
499 catch (const Dune::Exception &e)
500 {
501 if (verbosity_ >= 1)
502 std::cout << solverName_ << ": Caught exception from the linear solver: \"" << e.what() << "\"\n";
503
504 converged = false;
505 }
506
507 // make sure all processes converged
508 int convergedRemote = converged;
509 if (comm_.size() > 1)
510 convergedRemote = comm_.min(converged);
511
512 if (!converged)
513 {
514 DUNE_THROW(NumericalProblem, "Linear solver did not converge");
515 ++numLinearSolverBreakdowns_;
516 }
517 else if (!convergedRemote)
518 {
519 DUNE_THROW(NumericalProblem, "Linear solver did not converge on a remote process");
520 ++numLinearSolverBreakdowns_; // we keep correct count for process 0
521 }
522 }
523
542 const SolutionVector& uLastIter,
543 const ResidualVector& deltaU)
544 {
545 if (useLineSearch_)
546 lineSearchUpdate_(vars, uLastIter, deltaU);
547
548 else if (useChop_)
549 choppedUpdate_(vars, uLastIter, deltaU);
550
551 else
552 {
553 auto uCurrentIter = uLastIter;
554 Backend::axpy(-1.0, deltaU, uCurrentIter);
555 solutionChanged_(vars, uCurrentIter);
556
557 if (enableResidualCriterion_)
559 }
560
561 if (enableShiftCriterion_ || enablePartialReassembly_)
562 newtonComputeShift_(Backend::dofs(vars), uLastIter);
563
564 if (enablePartialReassembly_) {
565 // Determine the threshold 'eps' that is used for the partial reassembly.
566 // Every entity where the primary variables exhibit a relative shift
567 // summed up since the last linearization above 'eps' will be colored
568 // red yielding a reassembly.
569 // The user can provide three parameters to influence the threshold:
570 // 'minEps' by 'Newton.ReassemblyMinThreshold' (1e-1*shiftTolerance_ default)
571 // 'maxEps' by 'Newton.ReassemblyMaxThreshold' (1e2*shiftTolerance_ default)
572 // 'omega' by 'Newton.ReassemblyShiftWeight' (1e-3 default)
573 // The threshold is calculated from the currently achieved maximum
574 // relative shift according to the formula
575 // eps = max( minEps, min(maxEps, omega*shift) ).
576 // Increasing/decreasing 'minEps' leads to less/more reassembly if
577 // 'omega*shift' is small, i.e., for the last Newton iterations.
578 // Increasing/decreasing 'maxEps' leads to less/more reassembly if
579 // 'omega*shift' is large, i.e., for the first Newton iterations.
580 // Increasing/decreasing 'omega' leads to more/less first and last
581 // iterations in this sense.
582 using std::max;
583 using std::min;
584 auto reassemblyThreshold = max(reassemblyMinThreshold_,
585 min(reassemblyMaxThreshold_,
586 shift_*reassemblyShiftWeight_));
587
588 auto actualDeltaU = uLastIter;
589 actualDeltaU -= Backend::dofs(vars);
590 updateDistanceFromLastLinearization_(uLastIter, actualDeltaU);
591 partialReassembler_->computeColors(this->assembler(),
592 distanceFromLastLinearization_,
593 reassemblyThreshold);
594
595 // set the discrepancy of the red entities to zero
596 for (unsigned int i = 0; i < distanceFromLastLinearization_.size(); i++)
597 if (partialReassembler_->dofColor(i) == EntityColor::red)
598 distanceFromLastLinearization_[i] = 0;
599 }
600 }
601
608 virtual void newtonEndStep(Variables &vars,
609 const SolutionVector &uLastIter)
610 {
611 if constexpr (hasPriVarsSwitch<PriVarSwitchVariables>)
612 {
613 if constexpr (assemblerExportsVariables)
614 priVarSwitchAdapter_->invoke(Backend::dofs(vars), vars);
615 else // this assumes assembly with solution (i.e. Variables=SolutionVector)
616 priVarSwitchAdapter_->invoke(vars, this->assembler().gridVariables());
617 }
618
619 ++numSteps_;
620
621 if (verbosity_ >= 1)
622 {
623 if (enableDynamicOutput_)
624 std::cout << '\r'; // move cursor to beginning of line
625
626 const auto width = Fmt::formatted_size("{}", maxSteps_);
627 std::cout << Fmt::format("{} iteration {:{}} done", solverName_, numSteps_, width);
628
629 if (enableShiftCriterion_)
630 std::cout << Fmt::format(", maximum relative shift = {:.4e}", shift_);
631 if (enableResidualCriterion_ || enableAbsoluteResidualCriterion_)
632 std::cout << Fmt::format(", residual = {:.4e}, residual reduction = {:.4e}", residualNorm_, reduction_);
633
634 std::cout << endIterMsgStream_.str() << "\n";
635 }
636 endIterMsgStream_.str("");
637
638 // When the Newton iterations are done: ask the model to check whether it makes sense
639 // TODO: how do we realize this? -> do this here in the Newton solver
640 // model_().checkPlausibility();
641 }
642
647 virtual void newtonEnd() {}
648
653 virtual bool newtonConverged() const
654 {
655 // in case the model has a priVar switch and some some primary variables
656 // actually switched their state in the last iteration, enforce another iteration
657 if (priVarSwitchAdapter_->switched())
658 return false;
659
660 if (enableShiftCriterion_ && !enableResidualCriterion_)
661 {
662 return shift_ <= shiftTolerance_;
663 }
664 else if (!enableShiftCriterion_ && enableResidualCriterion_)
665 {
666 if(enableAbsoluteResidualCriterion_)
667 return residualNorm_ <= residualTolerance_;
668 else
669 return reduction_ <= reductionTolerance_;
670 }
671 else if (satisfyResidualAndShiftCriterion_)
672 {
673 if(enableAbsoluteResidualCriterion_)
674 return shift_ <= shiftTolerance_
675 && residualNorm_ <= residualTolerance_;
676 else
677 return shift_ <= shiftTolerance_
678 && reduction_ <= reductionTolerance_;
679 }
680 else if(enableShiftCriterion_ && enableResidualCriterion_)
681 {
682 if(enableAbsoluteResidualCriterion_)
683 return shift_ <= shiftTolerance_
684 || residualNorm_ <= residualTolerance_;
685 else
686 return shift_ <= shiftTolerance_
687 || reduction_ <= reductionTolerance_;
688 }
689 else
690 {
691 return shift_ <= shiftTolerance_
692 || reduction_ <= reductionTolerance_
693 || residualNorm_ <= residualTolerance_;
694 }
695
696 return false;
697 }
698
703 virtual void newtonFail(Variables& u) {}
704
709 virtual void newtonSucceed() {}
710
714 void report(std::ostream& sout = std::cout) const
715 {
716 sout << '\n'
717 << solverName_ << " statistics\n"
718 << "----------------------------------------------\n"
719 << "-- Total iterations: " << totalWastedIter_ + totalSucceededIter_ << '\n'
720 << "-- Total wasted iterations: " << totalWastedIter_ << '\n'
721 << "-- Total succeeded iterations: " << totalSucceededIter_ << '\n'
722 << "-- Average iterations per solve: " << std::setprecision(3) << double(totalSucceededIter_) / double(numConverged_) << '\n'
723 << "-- Number of linear solver breakdowns: " << numLinearSolverBreakdowns_ << '\n'
724 << std::endl;
725 }
726
731 {
732 totalWastedIter_ = 0;
733 totalSucceededIter_ = 0;
734 numConverged_ = 0;
735 numLinearSolverBreakdowns_ = 0;
736 }
737
741 void reportParams(std::ostream& sout = std::cout) const
742 {
743 sout << "\n" << solverName_ << " solver configured with the following options and parameters:\n";
744 // options
745 if (useLineSearch_) sout << " -- " << solverName_ << ".UseLineSearch = true\n";
746 if (useChop_) sout << " -- " << solverName_ << ".EnableChop = true\n";
747 if (enablePartialReassembly_) sout << " -- " << solverName_ << ".EnablePartialReassembly = true\n";
748 if (enableAbsoluteResidualCriterion_) sout << " -- " << solverName_ << ".EnableAbsoluteResidualCriterion = true\n";
749 if (enableShiftCriterion_) sout << " -- " << solverName_ << ".EnableShiftCriterion = true (relative shift convergence criterion)\n";
750 if (enableResidualCriterion_) sout << " -- " << solverName_ << ".EnableResidualCriterion = true\n";
751 if (satisfyResidualAndShiftCriterion_) sout << " -- " << solverName_ << ".SatisfyResidualAndShiftCriterion = true\n";
752 // parameters
753 if (enableShiftCriterion_) sout << " -- " << solverName_ << ".MaxRelativeShift = " << shiftTolerance_ << '\n';
754 if (enableAbsoluteResidualCriterion_) sout << " -- " << solverName_ << ".MaxAbsoluteResidual = " << residualTolerance_ << '\n';
755 if (enableResidualCriterion_) sout << " -- " << solverName_ << ".ResidualReduction = " << reductionTolerance_ << '\n';
756 sout << " -- " << solverName_ << ".MinSteps = " << minSteps_ << '\n';
757 sout << " -- " << solverName_ << ".MaxSteps = " << maxSteps_ << '\n';
758 sout << " -- " << solverName_ << ".TargetSteps = " << targetSteps_ << '\n';
759 if (enablePartialReassembly_)
760 {
761 sout << " -- " << solverName_ << ".ReassemblyMinThreshold = " << reassemblyMinThreshold_ << '\n';
762 sout << " -- " << solverName_ << ".ReassemblyMaxThreshold = " << reassemblyMaxThreshold_ << '\n';
763 sout << " -- " << solverName_ << ".ReassemblyShiftWeight = " << reassemblyShiftWeight_ << '\n';
764 }
765 sout << " -- " << solverName_ << ".RetryTimeStepReductionFactor = " << retryTimeStepReductionFactor_ << '\n';
766 sout << " -- " << solverName_ << ".MaxTimeStepDivisions = " << maxTimeStepDivisions_ << '\n';
767 sout << std::endl;
768 }
769
778 Scalar suggestTimeStepSize(Scalar oldTimeStep) const
779 {
780 // be aggressive reducing the time-step size but
781 // conservative when increasing it. the rationale is
782 // that we want to avoid failing in the next Newton
783 // iteration which would require another linearization
784 // of the problem.
785 if (numSteps_ > targetSteps_) {
786 Scalar percent = Scalar(numSteps_ - targetSteps_)/targetSteps_;
787 return oldTimeStep/(1.0 + percent);
788 }
789
790 Scalar percent = Scalar(targetSteps_ - numSteps_)/targetSteps_;
791 return oldTimeStep*(1.0 + percent/1.2);
792 }
793
797 void setVerbosity(int val)
798 { verbosity_ = val; }
799
803 int verbosity() const
804 { return verbosity_ ; }
805
809 void setUseLineSearch(bool val = true)
810 { useLineSearch_ = val; }
811
815 bool useLineSearch() const
816 { return useLineSearch_; }
817
821 const std::string& paramGroup() const
822 { return paramGroup_; }
823
827 void attachConvergenceWriter(std::shared_ptr<ConvergenceWriter> convWriter)
828 { convergenceWriter_ = convWriter; }
829
834 { convergenceWriter_ = nullptr; }
835
840 { return retryTimeStepReductionFactor_; }
841
845 void setRetryTimeStepReductionFactor(const Scalar factor)
846 { retryTimeStepReductionFactor_ = factor; }
847
848protected:
849
855 virtual void solutionChanged_(Variables& vars, const SolutionVector& uCurrentIter)
856 {
857 Backend::update(vars, uCurrentIter);
858
859 if constexpr (!assemblerExportsVariables)
860 this->assembler().updateGridVariables(Backend::dofs(vars));
861 }
862
864 {
865 // we assume that the assembler works on solution vectors
866 // if it doesn't export the variables type
867 if constexpr (!assemblerExportsVariables)
868 this->assembler().assembleResidual(Backend::dofs(vars));
869 else
870 this->assembler().assembleResidual(vars);
871
872 residualNorm_ = this->linearSolver().norm(this->assembler().residual());
873
875 }
876
878 { return enableResidualCriterion_; }
879
888
889 // residual criterion variables
894
895 // shift criterion variables
896 Scalar shift_;
898
900 std::ostringstream endIterMsgStream_;
901
902
903private:
904
909 bool solve_(Variables& vars)
910 {
911 try
912 {
913 // newtonBegin may manipulate the solution
914 newtonBegin(vars);
915
916 // the given solution is the initial guess
917 auto uLastIter = Backend::dofs(vars);
918 ResidualVector deltaU = LinearAlgebraNativeBackend::zeros(Backend::size(Backend::dofs(vars)));
919 Detail::Newton::assign(deltaU, Backend::dofs(vars));
920
921 // setup timers
922 Dune::Timer assembleTimer(false);
923 Dune::Timer solveTimer(false);
924 Dune::Timer updateTimer(false);
925
926 // execute the method as long as the solver thinks
927 // that we should do another iteration
928 bool converged = false;
929 while (newtonProceed(vars, converged))
930 {
931 // notify the solver that we're about to start
932 // a new iteration
933 newtonBeginStep(vars);
934
935 // make the current solution to the old one
936 if (numSteps_ > 0)
937 uLastIter = Backend::dofs(vars);
938
939 if (verbosity_ >= 1 && enableDynamicOutput_)
940 std::cout << "Assemble: r(x^k) = dS/dt + div F - q; M = grad r"
941 << std::flush;
942
944 // assemble
946
947 // linearize the problem at the current solution
948 assembleTimer.start();
950 assembleTimer.stop();
951
953 // linear solve
955
956 // Clear the current line using an ansi escape
957 // sequence. for an explanation see
958 // http://en.wikipedia.org/wiki/ANSI_escape_code
959 const char clearRemainingLine[] = { 0x1b, '[', 'K', 0 };
960
961 if (verbosity_ >= 1 && enableDynamicOutput_)
962 std::cout << "\rSolve: M deltax^k = r"
963 << clearRemainingLine << std::flush;
964
965 // solve the resulting linear equation system
966 solveTimer.start();
967
968 // set the delta vector to zero before solving the linear system!
969 deltaU = 0;
970
971 solveLinearSystem(deltaU);
972 solveTimer.stop();
973
975 // update
977 if (verbosity_ >= 1 && enableDynamicOutput_)
978 std::cout << "\rUpdate: x^(k+1) = x^k - deltax^k"
979 << clearRemainingLine << std::flush;
980
981 updateTimer.start();
982 // update the current solution (i.e. uOld) with the delta
983 // (i.e. u). The result is stored in u
984 newtonUpdate(vars, uLastIter, deltaU);
985 updateTimer.stop();
986
987 // tell the solver that we're done with this iteration
988 newtonEndStep(vars, uLastIter);
989
990 // if a convergence writer was specified compute residual and write output
991 if (convergenceWriter_)
992 {
993 this->assembler().assembleResidual(vars);
994 convergenceWriter_->write(Backend::dofs(vars), deltaU, this->assembler().residual());
995 }
996
997 // detect if the method has converged
998 converged = newtonConverged();
999 }
1000
1001 // tell solver we are done
1002 newtonEnd();
1003
1004 // reset state if Newton failed
1005 if (!newtonConverged())
1006 {
1007 totalWastedIter_ += numSteps_;
1008 newtonFail(vars);
1009 return false;
1010 }
1011
1012 totalSucceededIter_ += numSteps_;
1013 numConverged_++;
1014
1015 // tell solver we converged successfully
1016 newtonSucceed();
1017
1018 if (verbosity_ >= 1) {
1019 const auto elapsedTot = assembleTimer.elapsed() + solveTimer.elapsed() + updateTimer.elapsed();
1020 std::cout << Fmt::format("Assemble/solve/update time: {:.2g}({:.2f}%)/{:.2g}({:.2f}%)/{:.2g}({:.2f}%)\n",
1021 assembleTimer.elapsed(), 100*assembleTimer.elapsed()/elapsedTot,
1022 solveTimer.elapsed(), 100*solveTimer.elapsed()/elapsedTot,
1023 updateTimer.elapsed(), 100*updateTimer.elapsed()/elapsedTot);
1024 }
1025 return true;
1026
1027 }
1028 catch (const NumericalProblem &e)
1029 {
1030 if (verbosity_ >= 1)
1031 std::cout << solverName_ << ": Caught exception: \"" << e.what() << "\"\n";
1032
1033 totalWastedIter_ += numSteps_;
1034
1035 newtonFail(vars);
1036 return false;
1037 }
1038 }
1039
1041 template<class A>
1042 auto assembleLinearSystem_(const A& assembler, const Variables& vars)
1043 -> typename std::enable_if_t<decltype(isValid(Detail::Newton::supportsPartialReassembly())(assembler))::value, void>
1044 {
1045 this->assembler().assembleJacobianAndResidual(vars, partialReassembler_.get());
1046 }
1047
1049 template<class A>
1050 auto assembleLinearSystem_(const A& assembler, const Variables& vars)
1051 -> typename std::enable_if_t<!decltype(isValid(Detail::Newton::supportsPartialReassembly())(assembler))::value, void>
1052 {
1053 this->assembler().assembleJacobianAndResidual(vars);
1054 }
1055
1063 [[deprecated("Use computeShift_(u1, u2) instead")]]
1064 virtual void newtonUpdateShift_(const SolutionVector &uLastIter,
1065 const ResidualVector &deltaU)
1066 {
1067 auto uNew = uLastIter;
1068 Backend::axpy(-1.0, deltaU, uNew);
1069 newtonComputeShift_(uLastIter, uNew);
1070 }
1071
1076 virtual void newtonComputeShift_(const SolutionVector &u1,
1077 const SolutionVector &u2)
1078 {
1079 shift_ = Detail::Newton::maxRelativeShift<Scalar>(u1, u2);
1080 if (comm_.size() > 1)
1081 shift_ = comm_.max(shift_);
1082 }
1083
1084 virtual void lineSearchUpdate_(Variables &vars,
1085 const SolutionVector &uLastIter,
1086 const ResidualVector &deltaU)
1087 {
1088 Scalar lambda = 1.0;
1089 auto uCurrentIter = uLastIter;
1090
1091 while (true)
1092 {
1093 Backend::axpy(-lambda, deltaU, uCurrentIter);
1094 solutionChanged_(vars, uCurrentIter);
1095
1096 computeResidualReduction_(vars);
1097
1098 if (reduction_ < lastReduction_ || lambda <= lineSearchMinRelaxationFactor_)
1099 {
1100 endIterMsgStream_ << Fmt::format(", residual reduction {:.4e}->{:.4e}@lambda={:.4f}", lastReduction_, reduction_, lambda);
1101 return;
1102 }
1103
1104 // try with a smaller update and reset solution
1105 lambda *= 0.5;
1106 uCurrentIter = uLastIter;
1107 }
1108 }
1109
1111 virtual void choppedUpdate_(Variables& vars,
1112 const SolutionVector& uLastIter,
1113 const ResidualVector& deltaU)
1114 {
1115 DUNE_THROW(Dune::NotImplemented,
1116 "Chopped " << solverName_ << " solver update strategy not implemented.");
1117 }
1118
1124 virtual bool solveLinearSystem_(ResidualVector& deltaU)
1125 {
1126 assert(this->checkSizesOfSubMatrices(this->assembler().jacobian()) && "Matrix blocks have wrong sizes!");
1127
1128 return this->linearSolver().solve(
1129 this->assembler().jacobian(),
1130 deltaU,
1131 this->assembler().residual()
1132 );
1133 }
1134
1136 void initParams_(const std::string& group = "")
1137 {
1138 useLineSearch_ = getParamFromGroup<bool>(group, solverName_ + ".UseLineSearch", false);
1139 lineSearchMinRelaxationFactor_ = getParamFromGroup<Scalar>(group, solverName_ + ".LineSearchMinRelaxationFactor", 0.125);
1140 useChop_ = getParamFromGroup<bool>(group, solverName_ + ".EnableChop", false);
1141 if(useLineSearch_ && useChop_)
1142 DUNE_THROW(Dune::InvalidStateException, "Use either linesearch OR chop!");
1143
1144 enableAbsoluteResidualCriterion_ = getParamFromGroup<bool>(group, solverName_ + ".EnableAbsoluteResidualCriterion", false);
1145 enableShiftCriterion_ = getParamFromGroup<bool>(group, solverName_ + ".EnableShiftCriterion", true);
1146 enableResidualCriterion_ = getParamFromGroup<bool>(group, solverName_ + ".EnableResidualCriterion", false) || enableAbsoluteResidualCriterion_;
1147 satisfyResidualAndShiftCriterion_ = getParamFromGroup<bool>(group, solverName_ + ".SatisfyResidualAndShiftCriterion", false);
1148 enableDynamicOutput_ = getParamFromGroup<bool>(group, solverName_ + ".EnableDynamicOutput", true);
1149
1150 if (!enableShiftCriterion_ && !enableResidualCriterion_)
1151 {
1152 DUNE_THROW(Dune::NotImplemented,
1153 "at least one of " << solverName_ << ".EnableShiftCriterion or "
1154 << solverName_ << ".EnableResidualCriterion has to be set to true");
1155 }
1156
1157 setMaxRelativeShift(getParamFromGroup<Scalar>(group, solverName_ + ".MaxRelativeShift", 1e-8));
1158 setMaxAbsoluteResidual(getParamFromGroup<Scalar>(group, solverName_ + ".MaxAbsoluteResidual", 1e-5));
1159 setResidualReduction(getParamFromGroup<Scalar>(group, solverName_ + ".ResidualReduction", 1e-5));
1160 setTargetSteps(getParamFromGroup<int>(group, solverName_ + ".TargetSteps", 10));
1161 setMinSteps(getParamFromGroup<int>(group, solverName_ + ".MinSteps", 2));
1162 setMaxSteps(getParamFromGroup<int>(group, solverName_ + ".MaxSteps", 18));
1163
1164 enablePartialReassembly_ = getParamFromGroup<bool>(group, solverName_ + ".EnablePartialReassembly", false);
1165 reassemblyMinThreshold_ = getParamFromGroup<Scalar>(group, solverName_ + ".ReassemblyMinThreshold", 1e-1*shiftTolerance_);
1166 reassemblyMaxThreshold_ = getParamFromGroup<Scalar>(group, solverName_ + ".ReassemblyMaxThreshold", 1e2*shiftTolerance_);
1167 reassemblyShiftWeight_ = getParamFromGroup<Scalar>(group, solverName_ + ".ReassemblyShiftWeight", 1e-3);
1168
1169 maxTimeStepDivisions_ = getParamFromGroup<std::size_t>(group, solverName_ + ".MaxTimeStepDivisions", 10);
1170 retryTimeStepReductionFactor_ = getParamFromGroup<Scalar>(group, solverName_ + ".RetryTimeStepReductionFactor", 0.5);
1171
1172 numSteps_ = 0;
1173
1174 // output a parameter report
1175 if (verbosity_ >= 2)
1176 reportParams();
1177 }
1178
1179 template<class SolA, class SolB>
1180 void updateDistanceFromLastLinearization_(const SolA& u, const SolB& uDelta)
1181 {
1182 if constexpr (Dune::IsNumber<SolA>::value)
1183 {
1184 auto nextPriVars = u;
1185 nextPriVars -= uDelta;
1186
1187 // add the current relative shift for this degree of freedom
1188 auto shift = Detail::Newton::maxRelativeShift<Scalar>(u, nextPriVars);
1189 distanceFromLastLinearization_[0] += shift;
1190 }
1191 else
1192 {
1193 for (std::size_t i = 0; i < u.size(); ++i)
1194 {
1195 const auto& currentPriVars(u[i]);
1196 auto nextPriVars(currentPriVars);
1197 nextPriVars -= uDelta[i];
1198
1199 // add the current relative shift for this degree of freedom
1200 auto shift = Detail::Newton::maxRelativeShift<Scalar>(currentPriVars, nextPriVars);
1201 distanceFromLastLinearization_[i] += shift;
1202 }
1203 }
1204 }
1205
1206 template<class ...ArgsA, class...ArgsB>
1207 void updateDistanceFromLastLinearization_(const Dune::MultiTypeBlockVector<ArgsA...>& uLastIter,
1209 {
1210 DUNE_THROW(Dune::NotImplemented, "Reassembly for MultiTypeBlockVector");
1211 }
1212
1213 template<class Sol>
1214 void resizeDistanceFromLastLinearization_(const Sol& u, std::vector<Scalar>& dist)
1215 {
1216 dist.assign(Backend::size(u), 0.0);
1217 }
1218
1219 template<class ...Args>
1220 void resizeDistanceFromLastLinearization_(const Dune::MultiTypeBlockVector<Args...>& u,
1221 std::vector<Scalar>& dist)
1222 {
1223 DUNE_THROW(Dune::NotImplemented, "Reassembly for MultiTypeBlockVector");
1224 }
1225
1227 Communication comm_;
1228
1230 int verbosity_;
1231
1232 Scalar shiftTolerance_;
1233 Scalar reductionTolerance_;
1234 Scalar residualTolerance_;
1235
1236 // time step control
1237 std::size_t maxTimeStepDivisions_;
1238 Scalar retryTimeStepReductionFactor_;
1239
1240 // further parameters
1241 bool useLineSearch_;
1242 Scalar lineSearchMinRelaxationFactor_;
1243 bool useChop_;
1244 bool enableAbsoluteResidualCriterion_;
1245 bool enableShiftCriterion_;
1246 bool enableResidualCriterion_;
1247 bool satisfyResidualAndShiftCriterion_;
1248 bool enableDynamicOutput_;
1249
1251 std::string paramGroup_;
1253 std::string solverName_;
1254
1255 // infrastructure for partial reassembly
1256 bool enablePartialReassembly_;
1257 std::unique_ptr<Reassembler> partialReassembler_;
1258 std::vector<Scalar> distanceFromLastLinearization_;
1259 Scalar reassemblyMinThreshold_;
1260 Scalar reassemblyMaxThreshold_;
1261 Scalar reassemblyShiftWeight_;
1262
1263 // statistics for the optional report
1264 std::size_t totalWastedIter_ = 0;
1265 std::size_t totalSucceededIter_ = 0;
1266 std::size_t numConverged_ = 0;
1267 std::size_t numLinearSolverBreakdowns_ = 0;
1268
1270 std::unique_ptr<PrimaryVariableSwitchAdapter> priVarSwitchAdapter_;
1271
1273 std::shared_ptr<ConvergenceWriter> convergenceWriter_ = nullptr;
1274};
1275
1276} // end namespace Dumux
1277
1278#endif
Definition: variablesbackend.hh:187
Base class for linear solvers.
Definition: solver.hh:27
An implementation of a Newton solver.
Definition: nonlinear/newtonsolver.hh:181
Comm Communication
Definition: nonlinear/newtonsolver.hh:206
virtual void newtonFail(Variables &u)
Called if the Newton method broke down. This method is called after newtonEnd()
Definition: nonlinear/newtonsolver.hh:703
int maxSteps_
maximum number of iterations we do before giving up
Definition: nonlinear/newtonsolver.hh:885
void setMaxSteps(int maxSteps)
Set the number of iterations after which the Newton method gives up.
Definition: nonlinear/newtonsolver.hh:297
typename Assembler::ResidualType ResidualVector
Definition: nonlinear/newtonsolver.hh:187
void solveLinearSystem(ResidualVector &deltaU)
Solve the linear system of equations .
Definition: nonlinear/newtonsolver.hh:486
void setResidualReduction(Scalar tolerance)
Set the maximum acceptable residual norm reduction.
Definition: nonlinear/newtonsolver.hh:266
void reportParams(std::ostream &sout=std::cout) const
Report the options and parameters this Newton is configured with.
Definition: nonlinear/newtonsolver.hh:741
int targetSteps_
optimal number of iterations we want to achieve
Definition: nonlinear/newtonsolver.hh:881
const std::string & paramGroup() const
Returns the parameter group.
Definition: nonlinear/newtonsolver.hh:821
void setRetryTimeStepReductionFactor(const Scalar factor)
Set the factor for reducing the time step after a Newton iteration has failed.
Definition: nonlinear/newtonsolver.hh:845
Scalar reduction_
Definition: nonlinear/newtonsolver.hh:890
Scalar retryTimeStepReductionFactor() const
Return the factor for reducing the time step after a Newton iteration has failed.
Definition: nonlinear/newtonsolver.hh:839
bool useLineSearch() const
Return whether line search is enabled or not.
Definition: nonlinear/newtonsolver.hh:815
int numSteps_
actual number of steps done so far
Definition: nonlinear/newtonsolver.hh:887
int verbosity() const
Return the verbosity level.
Definition: nonlinear/newtonsolver.hh:803
void setMinSteps(int minSteps)
Set the number of minimum iterations for the Newton method.
Definition: nonlinear/newtonsolver.hh:288
void newtonUpdate(Variables &vars, const SolutionVector &uLastIter, const ResidualVector &deltaU)
Update the current solution with a delta vector.
Definition: nonlinear/newtonsolver.hh:541
int minSteps_
minimum number of iterations we do
Definition: nonlinear/newtonsolver.hh:883
virtual void newtonBegin(Variables &initVars)
Called before the Newton method is applied to an non-linear system of equations.
Definition: nonlinear/newtonsolver.hh:388
virtual void assembleLinearSystem(const Variables &vars)
Assemble the linear system of equations .
Definition: nonlinear/newtonsolver.hh:467
bool enableResidualCriterion() const
Definition: nonlinear/newtonsolver.hh:877
virtual bool newtonProceed(const Variables &varsCurrentIter, bool converged)
Returns true if another iteration should be done.
Definition: nonlinear/newtonsolver.hh:426
void solve(Variables &vars, TimeLoop &timeLoop) override
Run the Newton method to solve a non-linear system. Does time step control when the Newton fails to c...
Definition: nonlinear/newtonsolver.hh:307
virtual void newtonEndStep(Variables &vars, const SolutionVector &uLastIter)
Indicates that one Newton iteration was finished.
Definition: nonlinear/newtonsolver.hh:608
NewtonSolver(std::shared_ptr< Assembler > assembler, std::shared_ptr< LinearSolver > linearSolver, const Communication &comm=Dune::MPIHelper::getCommunication(), const std::string &paramGroup="", const std::string &paramGroupName="Newton", int verbosity=2)
Definition: nonlinear/newtonsolver.hh:208
virtual void solutionChanged_(Variables &vars, const SolutionVector &uCurrentIter)
Update solution-dependent quantities like grid variables after the solution has changed.
Definition: nonlinear/newtonsolver.hh:855
void report(std::ostream &sout=std::cout) const
output statistics / report
Definition: nonlinear/newtonsolver.hh:714
void solve(Variables &vars) override
Run the Newton method to solve a non-linear system. The solver is responsible for all the strategic d...
Definition: nonlinear/newtonsolver.hh:361
bool apply(Variables &vars) override
Run the Newton method to solve a non-linear system. The solver is responsible for all the strategic d...
Definition: nonlinear/newtonsolver.hh:377
virtual void newtonSucceed()
Called if the Newton method ended successfully This method is called after newtonEnd()
Definition: nonlinear/newtonsolver.hh:709
void attachConvergenceWriter(std::shared_ptr< ConvergenceWriter > convWriter)
Attach a convergence writer to write out intermediate results after each iteration.
Definition: nonlinear/newtonsolver.hh:827
Scalar initialResidual_
Definition: nonlinear/newtonsolver.hh:893
Scalar lastReduction_
Definition: nonlinear/newtonsolver.hh:892
void setUseLineSearch(bool val=true)
Specify whether line search is enabled or not.
Definition: nonlinear/newtonsolver.hh:809
virtual void newtonBeginStep(const Variables &vars)
Indicates the beginning of a Newton iteration.
Definition: nonlinear/newtonsolver.hh:449
std::ostringstream endIterMsgStream_
message stream to be displayed at the end of iterations
Definition: nonlinear/newtonsolver.hh:900
void setVerbosity(int val)
Specify the verbosity level.
Definition: nonlinear/newtonsolver.hh:797
typename Backend::DofVector SolutionVector
Definition: nonlinear/newtonsolver.hh:186
const Communication & comm() const
the communicator for parallel runs
Definition: nonlinear/newtonsolver.hh:238
void resetReport()
reset the statistics
Definition: nonlinear/newtonsolver.hh:730
void setMaxAbsoluteResidual(Scalar tolerance)
Set the maximum acceptable absolute residual for declaring convergence.
Definition: nonlinear/newtonsolver.hh:257
virtual void newtonEnd()
Called if the Newton method ended (not known yet if we failed or succeeded)
Definition: nonlinear/newtonsolver.hh:647
void setTargetSteps(int targetSteps)
Set the number of iterations at which the Newton method should aim at.
Definition: nonlinear/newtonsolver.hh:279
virtual bool newtonConverged() const
Returns true if the error of the solution is below the tolerance.
Definition: nonlinear/newtonsolver.hh:653
Scalar suggestTimeStepSize(Scalar oldTimeStep) const
Suggest a new time-step size based on the old time-step size.
Definition: nonlinear/newtonsolver.hh:778
void detachConvergenceWriter()
Detach the convergence writer to stop the output.
Definition: nonlinear/newtonsolver.hh:833
void setMaxRelativeShift(Scalar tolerance)
Set the maximum acceptable difference of any primary variable between two iterations for declaring co...
Definition: nonlinear/newtonsolver.hh:248
Scalar shift_
Definition: nonlinear/newtonsolver.hh:896
void computeResidualReduction_(const Variables &vars)
Definition: nonlinear/newtonsolver.hh:863
Scalar residualNorm_
Definition: nonlinear/newtonsolver.hh:891
Scalar lastShift_
Definition: nonlinear/newtonsolver.hh:897
Exception thrown if a fixable numerical problem occurs.
Definition: exceptions.hh:27
A high-level interface for a PDESolver.
Definition: common/pdesolver.hh:61
const LinearSolver & linearSolver() const
Access the linear solver.
Definition: common/pdesolver.hh:133
const Assembler & assembler() const
Access the assembler.
Definition: common/pdesolver.hh:121
Detail::PDESolver::AssemblerVariables< Assembler > Variables
export the type of variables that represent a numerical solution
Definition: common/pdesolver.hh:71
detects which entries in the Jacobian have to be recomputed
Definition: partialreassembler.hh:420
An adapter for the Newton to manage models with primary variable switch.
Definition: primaryvariableswitchadapter.hh:44
virtual void setTimeStepSize(Scalar dt)=0
Set the current time step size to a given value.
virtual Scalar timeStepSize() const =0
Returns the suggested time step length .
Definition: variablesbackend.hh:34
Defines a high-level interface for a PDESolver.
Manages the handling of time dependent problems.
Some exceptions thrown in DuMux
Formatting based on the fmt-library which implements std::format of C++20.
@ red
distance from last linearization is above the tolerance
constexpr auto isValid(const Expression &t)
A function that creates a test functor to do class member introspection at compile time.
Definition: isvalid.hh:81
A helper function for class member function introspection.
A helper class that converts a Dune::MultiTypeBlockMatrix into a plain Dune::BCRSMatrix.
Definition: nonlinear/newtonsolver.hh:49
static constexpr auto hasStaticIndexAccess
Definition: nonlinear/newtonsolver.hh:86
auto maxRelativeShift(const V &v1, const V &v2) -> std::enable_if_t< Dune::IsNumber< V >::value, Scalar >
Definition: nonlinear/newtonsolver.hh:110
void assign(To &to, const From &from)
Definition: nonlinear/newtonsolver.hh:130
decltype(std::declval< C >()[0]) dynamicIndexAccess
Definition: nonlinear/newtonsolver.hh:83
auto hybridInnerProduct(const V &v1, const V &v2, Scalar init, Reduce &&r, Transform &&t) -> std::enable_if_t< hasDynamicIndexAccess< V >(), Scalar >
Definition: nonlinear/newtonsolver.hh:89
decltype(std::declval< C >()[Dune::Indices::_0]) staticIndexAccess
Definition: nonlinear/newtonsolver.hh:84
typename Assembler::GridVariables AssemblerGridVariablesType
Definition: nonlinear/newtonsolver.hh:52
static constexpr auto hasDynamicIndexAccess
Definition: nonlinear/newtonsolver.hh:85
typename PriVarSwitchVariablesType< Assembler, assemblerExportsGridVariables< Assembler > >::Type PriVarSwitchVariables
Definition: nonlinear/newtonsolver.hh:70
constexpr bool assemblerExportsGridVariables
Definition: nonlinear/newtonsolver.hh:55
Definition: adapt.hh:17
This class provides the infrastructure to write the convergence behaviour of the newton method into a...
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
Detects which entries in the Jacobian have to be recomputed.
An adapter for the Newton to manage models with primary variable switch.
A convergence writer interface Provide an interface that show the minimal requirements a convergence ...
Definition: nonlinear/newtonconvergencewriter.hh:32
EmptyGridVariables {} Type
Definition: nonlinear/newtonsolver.hh:65
Definition: nonlinear/newtonsolver.hh:59
typename Assembler::GridVariables Type
Definition: nonlinear/newtonsolver.hh:59
helper struct detecting if an assembler supports partial reassembly
Definition: nonlinear/newtonsolver.hh:74
auto operator()(Assembler &&a) -> decltype(a.assembleJacobianAndResidual(std::declval< const typename Assembler::SolutionVector & >(), std::declval< const PartialReassembler< Assembler > * >()))
Definition: nonlinear/newtonsolver.hh:76
Backends for operations on different solution vector types or more generic variable classes to be use...
Type traits to be used with vector types.