12#ifndef DUMUX_NONLINEAR_LEASTSQUARES_HH
13#define DUMUX_NONLINEAR_LEASTSQUARES_HH
19#include <dune/common/exceptions.hh>
20#include <dune/istl/bvector.hh>
21#include <dune/istl/matrix.hh>
22#if HAVE_SUITESPARSE_CHOLMOD
23#include <dune/istl/cholmod.hh>
25#include <dune/istl/io.hh>
35template<
class Variables>
40 virtual bool apply(Variables& vars) = 0;
49template<
class T,
class F>
54 using JacobianMatrix = Dune::Matrix<T>;
55 using ResidualType = Dune::BlockVector<T>;
56 using SolutionVector = Dune::BlockVector<T>;
57 using Variables = Dune::BlockVector<T>;
65 Assembler(
const F& f,
const SolutionVector& x0, std::size_t residualSize)
66 : prevSol_(x0), f_(f), solSize_(x0.size()), residualSize_(residualSize)
67 , JT_(solSize_, residualSize_), regularizedJTJ_(solSize_, solSize_)
68 , residual_(residualSize_), projectedResidual_(solSize_)
75 void setLinearSystem()
77 std::cout <<
"Setting up linear system with " << solSize_ <<
" variables and "
78 << residualSize_ <<
" residuals." << std::endl;
81 regularizedJTJ_ = 0.0;
83 projectedResidual_ = 0.0;
87 JacobianMatrix& jacobian() {
return regularizedJTJ_; }
90 ResidualType& residual() {
return projectedResidual_; }
93 void setLambda(
const T lambda) { lambda_ = lambda; }
94 T lambda() {
return lambda_; }
97 void assembleResidual(
const SolutionVector& x)
99 projectedResidual_ = 0.0;
103 for (
auto rowIt = JT_.begin(); rowIt != JT_.end(); ++rowIt)
105 const auto paramIdx = rowIt.index();
106 const auto residual = f_(x);
108 const auto eps = baseEpsilon_;
109 p[paramIdx] = x[paramIdx] + eps;
110 auto deflectedResidual = f_(p);
111 deflectedResidual -= residual;
112 deflectedResidual /= eps;
113 for (
auto colIt = rowIt->begin(); colIt != rowIt->end(); ++colIt)
114 *colIt += deflectedResidual[colIt.index()];
116 projectedResidual_[paramIdx] = residual * deflectedResidual;
121 std::cout << std::endl <<
"J^T = " << std::endl;
122 Dune::printmatrix(std::cout, JT_,
"",
"");
127 void assembleJacobianAndResidual(
const SolutionVector& x)
131 regularizedJTJ_ = 0.0;
132 for (
auto rowIt = regularizedJTJ_.begin(); rowIt != regularizedJTJ_.end(); ++rowIt)
134 for (
auto colIt = rowIt->begin(); colIt != rowIt->end(); ++colIt)
136 for (
int j = 0; j < residualSize_; ++j)
137 *colIt += JT_[rowIt.index()][j]*JT_[colIt.index()][j];
139 if (rowIt.index() == colIt.index())
141 *colIt += lambda_*(*colIt);
144 *colIt = 1e-6*lambda_;
151 std::cout << std::endl <<
"J^T J + λ diag(J^T J) = " << std::endl;
152 Dune::printmatrix(std::cout, regularizedJTJ_,
"",
"");
157 T computeMeanSquaredError(
const SolutionVector& x)
const
158 {
return f_(x).two_norm2(); }
161 const SolutionVector& prevSol()
const
165 SolutionVector prevSol_;
167 std::size_t solSize_, residualSize_;
170 JacobianMatrix regularizedJTJ_;
171 ResidualType residual_;
172 ResidualType projectedResidual_;
174 Scalar lambda_ = 0.0;
177 bool printMatrix_ =
false;
180#if HAVE_SUITESPARSE_CHOLMOD
181template<
class Matrix,
class Vector>
182class CholmodLinearSolver
185 void setResidualReduction(
double residualReduction) {}
187 bool solve(
const Matrix& A, Vector& x,
const Vector& b)
const
189 Dune::Cholmod<Vector> solver;
191 Dune::InverseOperatorResult r;
194 solver.apply(xCopy, bCopy, r);
195 checkResult_(xCopy, r);
197 DUNE_THROW(NumericalProblem,
"Linear solver did not converge.");
202 auto norm(
const Vector& residual)
const
203 {
return residual.two_norm(); }
206 void checkResult_(Vector& x, Dune::InverseOperatorResult& result)
const
208 flatVectorForEach(x, [&](
auto&& entry, std::size_t){
209 using std::isnan, std::isinf;
210 if (isnan(entry) || isinf(entry))
211 result.converged =
false;
229template<
class Assembler,
class LinearSolver>
233 using Scalar =
typename Assembler::Scalar;
234 using Variables =
typename Assembler::Variables;
235 using SolutionVector =
typename Assembler::SolutionVector;
236 using ResidualVector =
typename Assembler::ResidualType;
239 using ParentType::ParentType;
262 bool apply(Variables& vars)
override
265 for (std::size_t i = 0; i <= maxLambdaDivisions_; ++i)
273 else if (!converged && i < maxLambdaDivisions_)
276 std::cout << Fmt::format(
"LevenbergMarquardt solver did not converge with λ = {:.2e}. ",
ParentType::assembler().lambda())
288 std::cout << Fmt::format(
"Choose best solution so far with a MSE of {:.4e}", minResidual_) << std::endl;
298 void newtonEndStep(Variables &vars,
const SolutionVector &uLastIter)
override
339 bestSol_ = uLastIter;
344 const SolutionVector& uLastIter,
345 const ResidualVector& deltaU)
override
348 auto uCurrentIter = uLastIter;
352 Backend::axpy(-alpha_, deltaU, uCurrentIter);
368 uCurrentIter = uLastIter;
372 Scalar minResidual_ = std::numeric_limits<Scalar>::max();
373 SolutionVector bestSol_;
374 std::size_t maxLambdaDivisions_ = 10;
378#if HAVE_SUITESPARSE_CHOLMOD
379template<
class T,
class F>
380class NonlinearLeastSquaresSolver :
public Solver<typename Optimization::Detail::Assembler<T, F>::Variables>
382 using Assembler = Optimization::Detail::Assembler<T, F>;
383 using LinearSolver = Optimization::Detail::CholmodLinearSolver<typename Assembler::JacobianMatrix, typename Assembler::ResidualType>;
386 using Variables =
typename Assembler::Variables;
388 NonlinearLeastSquaresSolver(
const F& f,
const Dune::BlockVector<T>& x0, std::size_t size)
389 : solver_(std::make_unique<Optimizer>(std::make_shared<Assembler>(f, x0, size), std::make_shared<
LinearSolver>(), 2))
392 bool apply(Variables& vars)
override
393 {
return solver_->apply(vars); }
396 std::unique_ptr<Optimizer> solver_;
404#if HAVE_SUITESPARSE_CHOLMOD
416template<
class T,
class F>
417auto makeNonlinearLeastSquaresSolver(
const F& f,
const Dune::BlockVector<T>& x0, std::size_t size)
418-> std::unique_ptr<Solver<Dune::BlockVector<T>>>
419{
return std::make_unique<Optimization::Detail::NonlinearLeastSquaresSolver<T, F>>(f, x0, size); }
Base class for linear solvers.
Definition solver.hh:27
An implementation of a Newton solver. The comprehensive documentation is in Newton solver,...
Definition nonlinear/newtonsolver.hh:183
const std::string & paramGroup() const
Definition nonlinear/newtonsolver.hh:822
Scalar reduction_
Definition nonlinear/newtonsolver.hh:891
int numSteps_
Definition nonlinear/newtonsolver.hh:888
int verbosity() const
Definition nonlinear/newtonsolver.hh:804
virtual void newtonEndStep(Variables &vars, const SolutionVector &uLastIter)
Definition nonlinear/newtonsolver.hh:609
virtual void solutionChanged_(Variables &vars, const SolutionVector &uCurrentIter)
Definition nonlinear/newtonsolver.hh:856
bool apply(Variables &vars) override
Definition nonlinear/newtonsolver.hh:378
Scalar initialResidual_
Definition nonlinear/newtonsolver.hh:894
Scalar lastReduction_
Definition nonlinear/newtonsolver.hh:893
void setUseLineSearch(bool val=true)
Definition nonlinear/newtonsolver.hh:810
std::ostringstream endIterMsgStream_
Definition nonlinear/newtonsolver.hh:901
VariablesBackend< typename ParentType::Variables > Backend
Definition nonlinear/newtonsolver.hh:187
void setMaxRelativeShift(Scalar tolerance)
Definition nonlinear/newtonsolver.hh:249
Scalar residualNorm_
Definition nonlinear/newtonsolver.hh:892
A nonlinear least squares solver with model parameters and observations.
Definition leastsquares.hh:231
bool apply(Variables &vars) override
Solve the nonlinear least squares problem.
Definition leastsquares.hh:262
LevenbergMarquardt(std::shared_ptr< Assembler > assembler, std::shared_ptr< LinearSolver > linearSolver, int verbosity=0)
Definition leastsquares.hh:241
void lineSearchUpdate_(Variables &vars, const SolutionVector &uLastIter, const ResidualVector &deltaU) override
Definition leastsquares.hh:343
void newtonEndStep(Variables &vars, const SolutionVector &uLastIter) override
Definition leastsquares.hh:298
a solver base class
Definition leastsquares.hh:37
virtual ~Solver()=default
virtual bool apply(Variables &vars)=0
const LinearSolver & linearSolver() const
Definition common/pdesolver.hh:133
const Assembler & assembler() const
Definition common/pdesolver.hh:121
Some exceptions thrown in DuMux
T getParamFromGroup(Args &&... args)
A free function to get a parameter from the parameter tree singleton with a model group.
Definition parameters.hh:149
Definition leastsquares.hh:220
Definition leastsquares.hh:32
Reference implementation of a Newton solver.
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.