version 0.4.1
newtonraphsonwithscalarsubsidiaryfunction.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2021-2024 The Ikarus Developers mueller@ibb.uni-stuttgart.de
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
9#pragma once
10
11#include <iosfwd>
12#include <utility>
13
20
21namespace Ikarus {
22
23template <typename NLO, typename LS = utils::SolverDefault, typename UF = utils::UpdateDefault>
25
27{
28 double tol{1e-8};
29 int maxIter{20};
30};
31
36template <typename LS = utils::SolverDefault, typename UF = utils::UpdateDefault>
38{
39 using LinearSolver = LS;
40 using UpdateFunction = UF;
44
45 template <typename UF2>
48 .parameters = parameters, .linearSolver = linearSolver, .updateFunction = std::forward<UF2>(updateFunction)};
49 return settings;
50 }
51
52 template <typename NLO>
54};
55
64template <typename NLO, typename NRConfig>
65requires traits::isSpecialization<NewtonRaphsonWithSubsidiaryFunctionConfig, std::remove_cvref_t<NRConfig>>::value
66auto createNonlinearSolver(NRConfig&& config, NLO&& nonLinearOperator) {
68 using UF = std::remove_cvref_t<NRConfig>::UpdateFunction;
69 auto solverFactory = []<class NLO2, class LS2, class UF2>(NLO2&& nlo2, LS2&& ls, UF2&& uf) {
70 return std::make_shared<NewtonRaphsonWithSubsidiaryFunction<std::remove_cvref_t<NLO2>, std::remove_cvref_t<LS2>,
71 std::remove_cvref_t<UF2>>>(nlo2, std::forward<LS2>(ls),
72 std::forward<UF2>(uf));
73 };
74
75 if constexpr (std::remove_cvref_t<NLO>::numberOfFunctions == 3) {
76 auto solver =
77 solverFactory(nonLinearOperator.template subOperator<1, 2>(), std::forward<NRConfig>(config).linearSolver,
78 std::forward<NRConfig>(config).updateFunction);
79 solver->setup(config.parameters);
80 return solver;
81 } else {
82 static_assert(std::remove_cvref_t<NLO>::numberOfFunctions > 1,
83 "The number of derivatives in the nonlinear operator have to be more than 1");
84 auto solver = solverFactory(nonLinearOperator, std::forward<NRConfig>(config).linearSolver,
85 std::forward<NRConfig>(config).updateFunction);
86 ;
87
88 solver->setup(std::forward<NRConfig>(config).parameters);
89 return solver;
90 }
91}
92
103template <typename NLO, typename LS, typename UF>
104class NewtonRaphsonWithSubsidiaryFunction : public IObservable<NonLinearSolverMessages>
105{
106public:
109 static constexpr bool isLinearSolver =
111
113 using ValueType = typename NLO::template ParameterValue<0>;
116 using NonLinearOperator = NLO;
117
125 template <typename LS2 = LS, typename UF2 = UF>
126 explicit NewtonRaphsonWithSubsidiaryFunction(const NLO& nonLinearOperator, LS2&& linearSolver = {},
127 UF2&& updateFunction = {})
128 : nonLinearOperator_{nonLinearOperator},
129 linearSolver_{std::forward<LS2>(linearSolver)},
130 updateFunction_{std::forward<UF2>(updateFunction)} {}
131
137 void setup(const Settings& settings) { settings_ = settings; }
138
139#ifndef DOXYGEN
140 struct NoPredictor
141 {
142 };
143#endif
144
155 template <typename SolutionType = NoPredictor, typename SubsidiaryType>
156 requires std::is_same_v<SolutionType, NoPredictor> ||
157 std::is_convertible_v<SolutionType, std::remove_cvref_t<typename NLO::ValueType>>
158 [[nodiscard(
159 "The solve method returns information of the solution process. You should store this information and check if "
160 "it was successful")]] NonLinearSolverInformation
161 solve(SubsidiaryType&& subsidiaryFunction, SubsidiaryArgs& subsidiaryArgs,
162 const SolutionType& dxPredictor = NoPredictor{}) {
164
166 Ikarus::NonLinearSolverInformation solverInformation;
167 solverInformation.success = true;
168 auto& x = nonLinearOperator().firstParameter(); // x = D (Displacements)
169 if constexpr (not std::is_same_v<SolutionType, NoPredictor>)
170 updateFunction_(x, dxPredictor);
171 auto& lambda = nonLinearOperator().lastParameter();
172
176
177 auto lambdaDummy = lambda;
178 auto DDummy = x;
179 x.setZero();
180 lambda = 1.0;
181 nonLinearOperator().template update<0>();
182 const auto Fext0 = (-nonLinearOperator().value()).eval(); // dRdlambda(lambda)
183 lambda = lambdaDummy;
184 x = DDummy;
185
186 Eigen::MatrixX2<double> residual2d, sol2d;
187 nonLinearOperator().updateAll();
188 const auto& rx = nonLinearOperator().value();
189 const auto& Ax = nonLinearOperator().derivative();
190
191 Eigen::VectorXd deltaD;
192 deltaD.resizeLike(rx);
193 deltaD.setZero();
194
195 subsidiaryArgs.dfdDD.resizeLike(Fext0);
196
197 subsidiaryFunction(subsidiaryArgs);
198 auto rNorm = sqrt(rx.dot(rx));
199 decltype(rNorm) dNorm;
200 int iter{0};
201 if constexpr (isLinearSolver)
202 linearSolver_.analyzePattern(Ax);
203
205 while (rNorm > settings_.tol && iter < settings_.maxIter) {
207
209 residual2d.resize(rx.rows(), 2);
210 residual2d << -rx, Fext0;
211 sol2d.resize(rx.rows(), 2);
212
213 if constexpr (isLinearSolver) {
214 linearSolver_.factorize(Ax);
215 linearSolver_.solve(sol2d, residual2d);
216 } else {
217 sol2d = linearSolver(residual2d, Ax);
218 }
219
220 subsidiaryFunction(subsidiaryArgs);
221
222 const double deltalambda = (-subsidiaryArgs.f - subsidiaryArgs.dfdDD.dot(sol2d.col(0))) /
223 (subsidiaryArgs.dfdDD.dot(sol2d.col(1)) + subsidiaryArgs.dfdDlambda);
224 deltaD = sol2d.col(0) + deltalambda * sol2d.col(1);
225
226 updateFunction_(x, deltaD);
227 updateFunction_(subsidiaryArgs.DD, deltaD);
228
229 lambda += deltalambda;
230 subsidiaryArgs.Dlambda += deltalambda;
231
232 dNorm = sqrt(deltaD.dot(deltaD) + deltalambda * deltalambda);
233 nonLinearOperator().updateAll();
234 rNorm = sqrt(rx.dot(rx) + subsidiaryArgs.f * subsidiaryArgs.f);
235
236 this->notify(NonLinearSolverMessages::SOLUTION_CHANGED, static_cast<double>(lambda));
237 this->notify(NonLinearSolverMessages::CORRECTIONNORM_UPDATED, static_cast<double>(dNorm));
238 this->notify(NonLinearSolverMessages::RESIDUALNORM_UPDATED, static_cast<double>(rNorm));
240
241 ++iter;
242 }
243
244 if (iter == settings_.maxIter)
245 solverInformation.success = false;
246 solverInformation.iterations = iter;
247 solverInformation.residualNorm = rNorm;
248 solverInformation.correctionNorm = dNorm;
249 if (solverInformation.success)
251
252 return solverInformation;
253 }
254
259 auto& nonLinearOperator() { return nonLinearOperator_; }
260
261private:
262 NLO nonLinearOperator_;
263 LS linearSolver_;
264 UF updateFunction_;
265 Settings settings_;
266};
277template <typename NLO, typename LS = utils::SolverDefault, typename UF = utils::UpdateDefault>
278auto makeNewtonRaphsonWithSubsidiaryFunction(const NLO& nonLinearOperator, LS&& linearSolver = {},
279 UF&& updateFunction = {}) {
280 return std::make_shared<NewtonRaphsonWithSubsidiaryFunction<NLO, LS, UF>>(
281 nonLinearOperator, std::forward<LS>(linearSolver), std::move(updateFunction));
282}
283
284template <typename NLO, typename LS = utils::SolverDefault, typename UF = utils::UpdateDefault>
285NewtonRaphsonWithSubsidiaryFunction(const NLO& nonLinearOperator, LS&& linearSolver = {}, UF&& updateFunction = {})
286 -> NewtonRaphsonWithSubsidiaryFunction<NLO, std::remove_cvref_t<LS>, std::remove_cvref_t<UF>>;
287
288} // namespace Ikarus
Several concepts.
Defines structures and methods related to subsidiary functions for control routines.
Enums for observer messages.
Implementation of the observer design pattern.
Implementation of the Newton-Raphson method for solving nonlinear equations.
Definition: assemblermanipulatorbuildingblocks.hh:22
LinearSolverTemplate< double > LinearSolver
Definition: linearsolver.hh:235
::value auto createNonlinearSolver(NRConfig &&config, NLO &&nonLinearOperator)
Function to create a NewtonRaphson solver instance.
Definition: newtonraphson.hh:65
NewtonRaphsonWithSubsidiaryFunction(const NLO &nonLinearOperator, LS &&linearSolver={}, UF &&updateFunction={}) -> NewtonRaphsonWithSubsidiaryFunction< NLO, std::remove_cvref_t< LS >, std::remove_cvref_t< UF > >
auto makeNewtonRaphsonWithSubsidiaryFunction(const NLO &nonLinearOperator, LS &&linearSolver={}, UF &&updateFunction={})
Function to create a NewtonRaphson with subsidiary function solver instance.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:278
Structure containing arguments for subsidiary functions.
Definition: pathfollowingfunctions.hh:39
double Dlambda
The increment in the load factor.
Definition: pathfollowingfunctions.hh:42
double dfdDlambda
The derivative of the subsidiary function with respect to Dlambda.
Definition: pathfollowingfunctions.hh:45
double f
The value of the subsidiary function.
Definition: pathfollowingfunctions.hh:43
Eigen::VectorX< double > dfdDD
The derivative of the subsidiary function with respect to DD.
Definition: pathfollowingfunctions.hh:44
Eigen::VectorX< double > DD
The vector representing the solution increment.
Definition: pathfollowingfunctions.hh:41
Newton-Raphson solver with subsidiary function.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:105
UF UpdateFunctionType
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:115
typename NLO::template ParameterValue< 0 > ValueType
Type representing the update function.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:114
NewtonRaphsonWithSubsidiaryFunction(const NLO &nonLinearOperator, LS2 &&linearSolver={}, UF2 &&updateFunction={})
Constructor for NewtonRaphsonWithSubsidiaryFunction.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:126
static constexpr bool isLinearSolver
Type representing the parameter vector of the nonlinear operator.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:109
NewtonRaphsonWithSubsidiaryFunctionSettings Settings
Compile-time boolean indicating if the linear solver satisfies the non-linear solver concept.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:108
auto & nonLinearOperator()
Access the nonlinear operator.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:259
NonLinearSolverInformation solve(SubsidiaryType &&subsidiaryFunction, SubsidiaryArgs &subsidiaryArgs, const SolutionType &dxPredictor=NoPredictor{})
Solve the nonlinear system using the Newton-Raphson method with subsidiary function.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:161
void setup(const Settings &settings)
Setup the Newton-Raphson solver with subsidiary function.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:137
NLO NonLinearOperator
Type of the non-linear operator.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:116
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:27
double tol
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:28
int maxIter
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:29
Settings for the Newton-Raphson solver with subsidiary function.
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:38
LS linearSolver
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:42
UF updateFunction
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:43
LS LinearSolver
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:39
NewtonRaphsonWithSubsidiaryFunctionSettings parameters
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:41
auto rebindUpdateFunction(UF2 &&updateFunction) const
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:46
UF UpdateFunction
Definition: newtonraphsonwithscalarsubsidiaryfunction.hh:40
Information about the result of a non-linear solver.
Definition: solverinfos.hh:19
double correctionNorm
Definition: solverinfos.hh:28
int iterations
Definition: solverinfos.hh:29
double residualNorm
Definition: solverinfos.hh:27
bool success
Definition: solverinfos.hh:26
Generic observable interface for the Observer design pattern. See for a description of the design pa...
Definition: observer.hh:129
void notify(NonLinearSolverMessages message)
Notify observers about a specific message type.
Concept to check if a linear solver implements all the needed functions for given vector and matrix t...
Definition: concepts.hh:215