version 0.4.4
newtonraphsonwithscalarsubsidiaryfunction.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2021-2025 The Ikarus Developers ikarus@ibb.uni-stuttgart.de
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
9#pragma once
10
11#include <type_traits>
12#include <utility>
13
21
22namespace Ikarus {
23
24template <typename F, typename LS = utils::SolverDefault, typename UF = utils::UpdateDefault>
26
28{
29 double tol{1e-8};
30 int maxIter{20};
31};
32
37template <typename LS = utils::SolverDefault, typename UF = utils::UpdateDefault>
39{
40 using LinearSolver = LS;
41 using UpdateFunction = UF;
45
46 template <typename UF2>
49 .parameters = parameters, .linearSolver = linearSolver, .updateFunction = std::forward<UF2>(updateFunction)};
50 return settings;
51 }
52
53 template <typename F>
55};
56
57// THE CTAD is broken for designated initializers in clang 16, when we drop support this can be simplified
58#ifndef DOXYGEN
61
64
65template <typename LS>
68
69template <typename LS, typename UF>
72
73template <typename UF>
76#endif
85template <typename F, typename NRConfig>
86requires traits::isSpecialization<NewtonRaphsonWithSubsidiaryFunctionConfig, std::remove_cvref_t<NRConfig>>::value
87auto createNonlinearSolver(NRConfig&& config, F&& f) {
89 using UF = std::remove_cvref_t<NRConfig>::UpdateFunction;
90 auto solverFactory = []<class F2, class LS2, class UF2>(F2&& f2, LS2&& ls, UF2&& uf) {
91 return std::make_shared<NewtonRaphsonWithSubsidiaryFunction<std::remove_cvref_t<F2>, std::remove_cvref_t<LS2>,
92 std::remove_cvref_t<UF2>>>(f2, std::forward<LS2>(ls),
93 std::forward<UF2>(uf));
94 };
95
96 if constexpr (std::remove_cvref_t<F>::nDerivatives == 2) {
97 auto solver = solverFactory(derivative(f), std::forward<NRConfig>(config).linearSolver,
98 std::forward<NRConfig>(config).updateFunction);
99 solver->setup(config.parameters);
100 return solver;
101 } else {
102 static_assert(std::remove_cvref_t<F>::nDerivatives >= 1,
103 "The number of derivatives in the differentiable function have to be more than 0");
104 auto solver =
105 solverFactory(f, std::forward<NRConfig>(config).linearSolver, std::forward<NRConfig>(config).updateFunction);
106 ;
107
108 solver->setup(std::forward<NRConfig>(config).parameters);
109 return solver;
110 }
111}
112
123template <typename F, typename LS, typename UF>
125{
126public:
128 using SignatureTraits = typename F::Traits;
129
130 using Domain = typename SignatureTraits::Domain;
131 using CorrectionType = typename SignatureTraits::template Range<0>;
132 using JacobianType = typename SignatureTraits::template Range<1>;
135
139
146 template <typename LS2 = LS, typename UF2 = UF>
148 UF2&& updateFunction = {})
149 : residualFunction_{residual},
150 jacobianFunction_{derivative(residualFunction_)},
151 linearSolver_{std::forward<LS2>(linearSolver)},
152 updateFunction_{std::forward<UF2>(updateFunction)} {}
153
159 void setup(const Settings& settings) { settings_ = settings; }
160
171 template <typename SubsidiaryType>
172 [[nodiscard(
173 "The solve method returns information of the solution process. You should store this information and check if "
174 "it was successful")]] NonLinearSolverInformation
175 solve(Domain& req, SubsidiaryType&& subsidiaryFunction, SubsidiaryArgs& subsidiaryArgs) {
176 using enum NonLinearSolverMessages;
177
178 Ikarus::NonLinearSolverInformation solverInformation{};
179 auto state = typename NewtonRaphsonWithSubsidiaryFunction::State{
180 .domain = req, .correction = correction_, .information = solverInformation};
181 this->notify(INIT, state);
182
183 solverInformation.success = true;
184
185 auto& lambda = req.parameter();
186 auto& x = req.globalSolution();
187
191
192 auto lambdaDummy = lambda;
193 auto DDummy = x;
194 x.setZero();
195 lambda = 1.0;
196 decltype(auto) rx = residualFunction_(req);
197 const auto Fext0 = (-rx).eval(); // dRdlambda(lambda)
198 lambda = lambdaDummy;
199 x = DDummy;
200
201 rx = residualFunction_(req);
202 decltype(auto) Ax = jacobianFunction_(req);
203
204 Eigen::VectorXd deltaD;
205 deltaD.resizeLike(rx);
206 deltaD.setZero();
207
208 subsidiaryArgs.dfdDD.resizeLike(Fext0);
209
210 subsidiaryFunction(subsidiaryArgs);
211 auto rNorm = sqrt(rx.dot(rx));
212 solverInformation.residualNorm = static_cast<double>(rNorm);
213 decltype(rNorm) dNorm;
214 int iter{0};
215 if constexpr (isLinearSolver)
216 linearSolver_.analyzePattern(Ax);
217
218 Eigen::MatrixX2<double> residual2d, sol2d;
219
221 while (rNorm > settings_.tol && iter < settings_.maxIter) {
222 this->notify(ITERATION_STARTED, state);
223
225 residual2d.resize(rx.rows(), 2);
226 residual2d << -rx, Fext0;
227 sol2d.resize(rx.rows(), 2);
228
229 if constexpr (isLinearSolver) {
230 linearSolver_.factorize(Ax);
231 linearSolver_.solve(sol2d, residual2d);
232 } else {
233 sol2d = linearSolver_(residual2d, Ax);
234 }
235
236 subsidiaryFunction(subsidiaryArgs);
237
238 const double deltalambda = (-subsidiaryArgs.f - subsidiaryArgs.dfdDD.dot(sol2d.col(0))) /
239 (subsidiaryArgs.dfdDD.dot(sol2d.col(1)) + subsidiaryArgs.dfdDlambda);
240 deltaD = sol2d.col(0) + deltalambda * sol2d.col(1);
241
242 this->notify(CORRECTION_UPDATED, state);
243
244 updateFunction_(x, deltaD);
245 updateFunction_(subsidiaryArgs.DD, deltaD);
246
247 lambda += deltalambda;
248 subsidiaryArgs.Dlambda += deltalambda;
249
250 dNorm = sqrt(deltaD.dot(deltaD) + deltalambda * deltalambda);
251 solverInformation.correctionNorm = static_cast<double>(dNorm);
252
253 rx = residualFunction_(req);
254 Ax = jacobianFunction_(req);
255 rNorm = sqrt(rx.dot(rx) + subsidiaryArgs.f * subsidiaryArgs.f);
256 solverInformation.residualNorm = static_cast<double>(rNorm);
257
258 this->notify(SOLUTION_CHANGED, state);
259 this->notify(CORRECTIONNORM_UPDATED, state);
260 this->notify(RESIDUALNORM_UPDATED, state);
261
262 ++iter;
263 solverInformation.iterations = iter;
264 this->notify(ITERATION_ENDED, state);
265 }
266
267 if (iter == settings_.maxIter)
268 solverInformation.success = false;
269 solverInformation.iterations = iter;
270 if (solverInformation.success)
271 this->notify(FINISHED_SUCESSFULLY, state);
272
273 return solverInformation;
274 }
275
280 auto& residual() { return residualFunction_; }
281
282private:
283 DifferentiableFunction residualFunction_;
284 typename DifferentiableFunction::Derivative jacobianFunction_;
285 std::remove_cvref_t<CorrectionType> correction_;
286 LS linearSolver_;
287 UF updateFunction_;
288 Settings settings_;
289};
300template <typename F, typename LS = utils::SolverDefault, typename UF = utils::UpdateDefault>
301auto makeNewtonRaphsonWithSubsidiaryFunction(const F& f, LS&& linearSolver = {}, UF&& updateFunction = {}) {
302 return std::make_shared<NewtonRaphsonWithSubsidiaryFunction<F, LS, UF>>(f, std::forward<LS>(linearSolver),
303 std::move(updateFunction));
304}
305
306template <typename F, typename LS = utils::SolverDefault, typename UF = utils::UpdateDefault>
307NewtonRaphsonWithSubsidiaryFunction(const F& f, LS&& linearSolver = {}, UF&& updateFunction = {})
308 -> NewtonRaphsonWithSubsidiaryFunction<F, std::remove_cvref_t<LS>, std::remove_cvref_t<UF>>;
309
310} // namespace Ikarus
State for all nonlinear solvers.
Implementation of the solver information returned by the nonlinear solvers.
Base for all nonlinear solvers.
Implementation of the observer design pattern with broadcasters.
Enums for observer messages.
Defines structures and methods related to subsidiary functions for control routines.
Definition: assemblermanipulatorbuildingblocks.hh:22
NewtonRaphsonWithSubsidiaryFunction(const F &f, LS &&linearSolver={}, UF &&updateFunction={}) -> NewtonRaphsonWithSubsidiaryFunction< F, std::remove_cvref_t< LS >, std::remove_cvref_t< UF > >
LinearSolverTemplate< double > LinearSolver
Definition: linearsolver.hh:235
::value auto createNonlinearSolver(NRConfig &&config, F &&f)
Function to create a NewtonRaphson solver instance.
Definition: newtonraphson.hh:82
NonLinearSolverMessages
Enum class defining non-linear solver-related messages.
Definition: broadcastermessages.hh:22
auto makeNewtonRaphsonWithSubsidiaryFunction(const F &f, LS &&linearSolver={}, UF &&updateFunction={})
Function to create a NewtonRaphson with subsidiary function solver instance.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:301
Structure containing arguments for subsidiary functions.
Definition: pathfollowingfunctions.hh:40
double Dlambda
The increment in the load factor.
Definition: pathfollowingfunctions.hh:43
double dfdDlambda
The derivative of the subsidiary function with respect to Dlambda.
Definition: pathfollowingfunctions.hh:46
double f
The value of the subsidiary function.
Definition: pathfollowingfunctions.hh:44
Eigen::VectorX< double > dfdDD
The derivative of the subsidiary function with respect to DD.
Definition: pathfollowingfunctions.hh:45
Eigen::VectorX< double > DD
The vector representing the solution increment.
Definition: pathfollowingfunctions.hh:42
Newton-Raphson solver with subsidiary function.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:125
NewtonRaphsonWithSubsidiaryFunctionSettings Settings
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:127
auto & residual()
Access the residual function.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:280
void setup(const Settings &settings)
Setup the Newton-Raphson solver with subsidiary function.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:159
typename F::Traits SignatureTraits
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:128
NonLinearSolverInformation solve(Domain &req, SubsidiaryType &&subsidiaryFunction, SubsidiaryArgs &subsidiaryArgs)
Solve the nonlinear system using the Newton-Raphson method with subsidiary function.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:175
static constexpr bool isLinearSolver
Type representing the update function.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:134
typename SignatureTraits::template Range< 0 > CorrectionType
Type of the correction of x += deltaX.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:131
UF UpdateFunctionType
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:137
typename SignatureTraits::template Range< 1 > JacobianType
Compile-time boolean indicating if the linear solver satisfies the non-linear solver concept.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:133
typename SignatureTraits::Domain Domain
Type representing the parameter vector of the Function.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:130
NewtonRaphsonWithSubsidiaryFunction(const DifferentiableFunction &residual, LS2 &&linearSolver={}, UF2 &&updateFunction={})
Constructor for NewtonRaphsonWithSubsidiaryFunction.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:147
F DifferentiableFunction
Type of the non-linear operator.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:138
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:28
double tol
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:29
int maxIter
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:30
Settings for the Newton-Raphson solver with subsidiary function.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:39
LS linearSolver
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:43
UF updateFunction
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:44
LS LinearSolver
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:40
NewtonRaphsonWithSubsidiaryFunctionSettings parameters
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:42
auto rebindUpdateFunction(UF2 &&updateFunction) const
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:47
UF UpdateFunction
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:41
Base for all nonlinear solvers. Defines the message interface that can be broadcasted to listeners.
Definition: nonlinearsolverbase.hh:24
State for nonlinear solvers.
Definition: nonlinearsolverstate.hh:24
const Domain & domain
Definition: nonlinearsolverstate.hh:28
Information about the result of a non-linear solver.
Definition: solverinfos.hh:21
void notify(NonLinearSolverMessages message, const State &data)
This calls all the registered functions.
Definition: broadcaster.hh:61
Default functor for solving operations.
Definition: defaultfunctions.hh:26
Concept to check if a linear solver implements all the needed functions for given vector and matrix t...
Definition: utils/concepts.hh:226
Several concepts.