version 0.4.4
autodifffe.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 <autodiff/forward/dual/dual.hpp>
12#include <autodiff/forward/dual/eigen.hpp>
13
16
17namespace Ikarus {
18
26template <typename FEImpl, bool forceAutoDiff = false>
27class AutoDiffFE : public FEImpl
28{
29public:
30 using RealFE = FEImpl;
31 using BasisHandler = typename RealFE::BasisHandler;
32 using Traits = typename RealFE::Traits;
33 using LocalView = typename Traits::LocalView;
34 using Element = typename Traits::Element;
35 using Requirement = typename RealFE::Requirement;
36private:
37 using Mixin = FEImpl::Mixin;
38
39public:
48 friend void calculateMatrix(const AutoDiffFE& self, const Requirement& par, const MatrixAffordance& affordance,
49 typename Traits::template MatrixType<> h) {
50 self.calculateMatrix(par, affordance, h);
51 }
52
61 friend void calculateVector(const AutoDiffFE& self, const Requirement& par, VectorAffordance affordance,
62 typename Traits::template VectorType<double> g) {
63 self.calculateVector(par, affordance, g);
64 }
65
74 template <typename MT, typename BC>
75 auto subscribeTo(BC& bc) {
76 return realFE().template subscribeTo<MT>(bc);
77 }
78
89 friend void calculateLocalSystem(const AutoDiffFE& self, const Requirement& par, const MatrixAffordance& affordanceM,
90 VectorAffordance affordanceV, typename Traits::template MatrixType<> h,
91 typename Traits::template VectorType<> g) {
92 self.calculateLocalSystem(par, affordanceM, affordanceV, h, g);
93 }
94
103 friend auto calculateScalar(const AutoDiffFE& self, const Requirement& par, ScalarAffordance affordance) {
104 return self.calculateScalar(par, affordance);
105 }
106
112 const RealFE& realFE() const { return *this; }
113
119 RealFE& realFE() { return *this; }
120
128 template <typename... Args>
129 explicit AutoDiffFE(Args&&... args)
130 : RealFE{std::forward<Args>(args)...} {}
131
132private:
133 void calculateMatrix(const Requirement& req, const MatrixAffordance& affordance,
134 typename Traits::template MatrixType<> h) const {
135 // real element implements calculateMatrix by itself, then we simply forward the call
136
137 if constexpr (requires(Eigen::VectorXd v) {
138 static_cast<const Mixin&>(std::declval<AutoDiffFE>())
139 .template calculateMatrixImpl<double>(req, affordance, h, v);
140 } and not forceAutoDiff) {
141 return Mixin::template calculateMatrixImpl<double>(req, affordance, h);
142 } else if constexpr (requires(Eigen::VectorXdual v) {
143 static_cast<const Mixin&>(std::declval<AutoDiffFE>())
144 .template calculateVectorImpl<autodiff::dual>(
145 req, vectorAffordance(affordance),
146 std::declval<typename Traits::template VectorType<autodiff::dual>>(), v);
147 }) {
148 // real element implements calculateVector by itself, therefore we only need first order derivatives
149 Eigen::VectorXdual dx(this->localView().size());
150 Eigen::VectorXdual g(this->localView().size());
151 dx.setZero();
152 auto f = [this, &req, affordance, &g](auto& x) -> auto& {
153 // Since req is const as a function argument, we can not make this lambda capture by mutable reference
154 // But we have to do this since for efficiency reason we reuse the g vector
155 // therefore, the only remaining option is to cast the const away from g
156 Eigen::VectorXdual& gref = const_cast<Eigen::VectorXdual&>(g);
157 gref.setZero();
158 Mixin::template calculateVectorImpl<autodiff::dual>(req, vectorAffordance(affordance), gref, x);
159 return g;
160 };
161 jacobian(f, autodiff::wrt(dx), at(dx), g, h);
162 } else if constexpr (requires(typename Traits::template VectorType<autodiff::dual2nd> v) {
163 static_cast<const Mixin&>(std::declval<AutoDiffFE>())
164 .template calculateScalarImpl<autodiff::dual2nd>(req, scalarAffordance(affordance), v);
165 }) {
166 // real element implements calculateScalar by itself, therefore we need second order derivatives
167 Eigen::VectorXdual2nd dx(this->localView().size());
168 Eigen::VectorXd g;
169 autodiff::dual2nd e;
170 dx.setZero();
171 auto f = [this, &req, affordance](auto& x) {
172 return Mixin::template calculateScalarImpl<autodiff::dual2nd>(req, scalarAffordance(affordance), x);
173 };
174 hessian(f, autodiff::wrt(dx), at(dx), e, g, h);
175 } else
176 static_assert(Dune::AlwaysFalse<AutoDiffFE>::value,
177 "Appropriate calculateScalarImpl or calculateVectorImpl functions are not implemented for the "
178 "chosen element.");
179 }
180
181 void calculateVector(const Requirement& req, VectorAffordance affordance,
182 typename Traits::template VectorType<> g) const {
183 // real element implements calculateVector by itself, then we simply forward the call
184 if constexpr (requires {
185 static_cast<const Mixin&>(std::declval<AutoDiffFE>())
186 .template calculateVectorImpl<double>(
187 req, affordance, std::declval<typename Traits::template VectorType<double>>(),
188 std::declval<const Eigen::VectorXd&>());
189 } and not forceAutoDiff) {
190 return Mixin::template calculateVectorImpl<double>(req, affordance, g);
191 } else if constexpr (requires {
192 static_cast<const Mixin&>(std::declval<AutoDiffFE>())
193 .template calculateScalarImpl<autodiff::dual>(req, scalarAffordance(affordance),
194 std::declval<const Eigen::VectorXdual&>());
195 }) {
196 // real element implements calculateScalar by itself but no calculateVectorImpl, therefore we need first order
197 // derivatives
198 Eigen::VectorXdual dx(this->localView().size());
199 dx.setZero();
200 autodiff::dual e;
201 auto f = [this, &req, affordance](auto& x) {
202 return Mixin::template calculateScalarImpl<autodiff::dual>(req, scalarAffordance(affordance), x);
203 };
204 gradient(f, autodiff::wrt(dx), at(dx), e, g);
205 } else
206 static_assert(Dune::AlwaysFalse<AutoDiffFE>::value,
207 "Appropriate calculateScalarImpl function is not implemented for the "
208 "chosen element.");
209 }
210
211 [[nodiscard]] double calculateScalar(const Requirement& par, ScalarAffordance affordance) const {
212 // real element implements calculateScalar by itself, then we simply forward the call
213 if constexpr (requires {
214 static_cast<const Mixin&>(std::declval<AutoDiffFE>())
215 .template calculateScalarImpl<double>(par, affordance);
216 }) {
217 // real element only implements the protected calculateScalarImpl by itself, thus we call that one.
218 return Mixin::template calculateScalarImpl<double>(par, affordance);
219 } else {
220 static_assert(Dune::AlwaysFalse<AutoDiffFE>::value,
221 "Appropriate calculateScalar and calculateScalarImpl functions are not implemented for the "
222 "chosen element.");
223 }
224 }
225
226 void calculateLocalSystem(const Requirement& req, const MatrixAffordance& affordanceM, VectorAffordance affordanceV,
227 typename Traits::template MatrixType<> h, typename Traits::template VectorType<> g) const {
228 assert(scalarAffordance(affordanceM) == scalarAffordance(affordanceV));
229 Eigen::VectorXdual2nd dx(this->localView().size());
230 dx.setZero();
231 auto f = [&](auto& x) { return Mixin::calculateScalarImpl(req, scalarAffordance(affordanceV), x); };
232 hessian(f, autodiff::wrt(dx), at(dx), g, h);
233 }
234};
235} // namespace Ikarus
Contains stl-like type traits.
Definition of the LinearElastic class for finite element mechanics computations.
Definition: assemblermanipulatorbuildingblocks.hh:22
auto vectorAffordance(MatrixAffordance affordanceM)
Definition: ferequirements.hh:177
MatrixAffordance
A strongly typed enum class representing the matrix affordance.
Definition: ferequirements.hh:64
auto scalarAffordance(MatrixAffordance affordanceM)
Definition: ferequirements.hh:186
VectorAffordance
A strongly typed enum class representing the vector affordance.
Definition: ferequirements.hh:49
ScalarAffordance
A strongly typed enum class representing the scalar affordance.
Definition: ferequirements.hh:38
AutoDiffFE class, an automatic differentiation wrapper for finite elements.
Definition: autodifffe.hh:28
AutoDiffFE(Args &&... args)
Constructor for the AutoDiffFE class. Forward the construction to the underlying element.
Definition: autodifffe.hh:129
typename RealFE::Traits Traits
Type traits for local view.
Definition: autodifffe.hh:32
friend void calculateVector(const AutoDiffFE &self, const Requirement &par, VectorAffordance affordance, typename Traits::template VectorType< double > g)
Calculate the vector associated with the finite element.
Definition: autodifffe.hh:61
friend auto calculateScalar(const AutoDiffFE &self, const Requirement &par, ScalarAffordance affordance)
Calculate the scalar value associated with the finite element.
Definition: autodifffe.hh:103
const RealFE & realFE() const
Get the reference to the base finite element.
Definition: autodifffe.hh:112
RealFE & realFE()
Get the reference to the base finite element.
Definition: autodifffe.hh:119
friend void calculateMatrix(const AutoDiffFE &self, const Requirement &par, const MatrixAffordance &affordance, typename Traits::template MatrixType<> h)
Calculate the matrix associated with the finite element.
Definition: autodifffe.hh:48
friend void calculateLocalSystem(const AutoDiffFE &self, const Requirement &par, const MatrixAffordance &affordanceM, VectorAffordance affordanceV, typename Traits::template MatrixType<> h, typename Traits::template VectorType<> g)
Calculate the local system associated with the finite element.
Definition: autodifffe.hh:89
FEImpl RealFE
Type of the base finite element.
Definition: autodifffe.hh:30
typename RealFE::BasisHandler BasisHandler
Type of the basis handler.
Definition: autodifffe.hh:31
typename Traits::LocalView LocalView
Type of the local view.
Definition: autodifffe.hh:33
typename Traits::Element Element
Type of the element.
Definition: autodifffe.hh:34
typename RealFE::Requirement Requirement
Type of the Finite Element Requirements.
Definition: autodifffe.hh:35
auto subscribeTo(BC &bc)
Subscribes the elements to listen to functions provided from the skills emitted by the given broadcas...
Definition: autodifffe.hh:75