version 0.4.1
finiteelements/mechanics/materials/hyperelastic/interface.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2021-2025 The Ikarus Developers mueller@ibb.uni-stuttgart.de
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
10#pragma once
11
12#include <autodiff/forward/dual/dual.hpp>
13#include <autodiff/forward/dual/eigen.hpp>
14
21
22namespace Ikarus::Materials {
23
33template <typename DEV, typename VOL = NoVolumetricPart>
34struct Hyperelastic : public Material<Hyperelastic<DEV, VOL>>
35{
36 static_assert(std::is_same_v<DEV, Deviatoric<typename DEV::DeviatoricFunction>>);
37 static_assert(std::is_same_v<VOL, Volumetric<typename VOL::VolumetricFunction>>);
38
39 using ScalarType = typename DEV::ScalarType;
40 static constexpr bool hasVolumetricPart = not std::same_as<VOL, NoVolumetricPart>;
42
43 static constexpr int dim = 3;
44 using StrainMatrix = Eigen::Matrix<ScalarType, dim, dim>;
46 using MaterialTensor = Eigen::TensorFixedSize<ScalarType, Eigen::Sizes<dim, dim, dim, dim>>;
47
48 using MaterialParametersDEV = typename DEV::MaterialParameters;
49 using MaterialParametersVOL = typename VOL::MaterialParameter;
51 std::conditional_t<hasVolumetricPart, std::pair<MaterialParametersDEV, MaterialParametersVOL>,
53
55 static constexpr auto stressTag = StressTags::PK2;
57 static constexpr bool energyAcceptsVoigt = false;
58 static constexpr bool stressToVoigt = false;
59 static constexpr bool stressAcceptsVoigt = false;
60 static constexpr bool moduliToVoigt = false;
61 static constexpr bool moduliAcceptsVoigt = false;
62 static constexpr double derivativeFactorImpl = 2;
63
64 [[nodiscard]] constexpr static std::string nameImpl() noexcept {
65 if constexpr (hasVolumetricPart)
66 return "Hyperelastic (" + DEV::name() + ", " + VOL::name() + ")";
67 else
68 return "Hyperelastic (" + DEV::name() + ")";
69 }
70
71 explicit Hyperelastic(const DEV& dev)
72 requires(not hasVolumetricPart)
73 : dev_{dev},
74 vol_(VOL{MaterialParametersVOL{}, typename VOL::VolumetricFunction{}}) {}
75
76 Hyperelastic(const DEV& dev, const VOL& vol)
77 : dev_(dev),
78 vol_(vol) {}
79
81 const DEV& deviatoricFunction() const { return dev_; }
82
84 const VOL& volumetricFunction() const { return vol_; }
85
90 if constexpr (hasVolumetricPart)
91 return {dev_.materialParameters(), vol_.materialParameter()};
92 else
93 return dev_.materialParameters();
94 }
95
102 template <typename Derived>
103 ScalarType storedEnergyImpl(const Eigen::MatrixBase<Derived>& C) const {
104 static_assert(Concepts::EigenMatrixOrVoigtNotation3<Derived>);
105
106 const auto lambdas = principalStretches(C, Eigen::EigenvaluesOnly).first;
107 auto J = detF(C, lambdas);
108
109 return deviatoricEnergy(C, lambdas) + vol_.storedEnergy(J);
110 }
111
119 template <bool voigt, typename Derived>
120 StressMatrix stressesImpl(const Eigen::MatrixBase<Derived>& C) const {
121 static_assert(Concepts::EigenMatrixOrVoigtNotation3<Derived>);
122 if constexpr (!voigt) {
123 const auto [lambdas, N] = principalStretches(C);
124 auto J = detF(C, lambdas);
125
126 const auto Sdev = deviatoricStress(C, lambdas, N);
127 const auto Svol = transformVolumetricStresses(vol_.firstDerivative(J), C, J);
128
129 return Sdev + Svol;
130 } else
131 static_assert(voigt == false, "Hyperelastic does not support returning stresses in Voigt notation");
132 }
133
141 template <bool voigt, typename Derived>
142 MaterialTensor tangentModuliImpl(const Eigen::MatrixBase<Derived>& C) const {
143 static_assert(Concepts::EigenMatrixOrVoigtNotation3<Derived>);
144 if constexpr (!voigt) {
145 const auto [lambdas, N] = principalStretches(C);
146 auto J = detF(C, lambdas);
147
148 const auto moduliDev = transformDeviatoricTangentModuli(dev_.tangentModuli(lambdas), N);
149 const auto moduliVol = transformVolumetricTangentModuli(vol_.firstDerivative(J), vol_.secondDerivative(J), C, J);
150
151 return moduliDev + moduliVol;
152 } else
153 static_assert(voigt == false, "Hyperelastic does not support returning tangent moduli in Voigt notation");
154 }
155
161 template <typename STO>
162 auto rebind() const {
163 auto reboundDEV = dev_.template rebind<STO>();
164 return Hyperelastic<decltype(reboundDEV), VOL>(reboundDEV, vol_);
165 }
166
167private:
168 DEV dev_;
169 VOL vol_;
170
171 inline static constexpr auto dimensionRange() { return Dune::range(dim); }
172
173 template <typename ST>
174 Eigen::Matrix<ST, dim, dim> transformDeviatoricStresses(const Eigen::Vector<ST, dim>& principalStress,
175 const Eigen::Matrix<ST, dim, dim>& N) const {
176 return (N * principalStress.asDiagonal() * N.transpose()).eval();
177 }
178
179 template <typename ST>
180 Eigen::Matrix<ST, dim, dim> transformVolumetricStresses(ST Uprime, const auto& C, ST J) const {
181 return J * Uprime * C.inverse();
182 }
183
184 template <typename ST>
185 auto transformDeviatoricTangentModuli(const Eigen::TensorFixedSize<ST, Eigen::Sizes<dim, dim, dim, dim>>& L,
186 const Eigen::Matrix<ST, dim, dim>& N) const {
187 Eigen::TensorFixedSize<ST, Eigen::Sizes<dim, dim, dim, dim>> moduli{};
188 moduli.setZero();
189 auto indexList = std::array<Eigen::Index, 2>({dim, dim});
190
191 for (const auto i : dimensionRange())
192 for (const auto k : dimensionRange()) {
193 // First term: L[i, i, k, k] * ((N[i] ⊗ N[i]) ⊗ (N[k] ⊗ N[k]))
194 auto NiNi = tensorView(dyadic(N.col(i).eval(), N.col(i).eval()), indexList);
195 auto NkNk = tensorView(dyadic(N.col(k).eval(), N.col(k).eval()), indexList);
196
197 moduli += L(i, i, k, k) * dyadic(NiNi, NkNk);
198
199 // Second term (only if i != k): L[i, k, i, k] * (N[i] ⊗ N[k] ⊗ (N[i] ⊗ N[k] + N[k] ⊗ N[i]))
200 if (i != k) {
201 auto NiNk = tensorView(dyadic(N.col(i).eval(), N.col(k).eval()), indexList);
202 auto NkNi = tensorView(dyadic(N.col(k).eval(), N.col(i).eval()), indexList);
203
204 moduli += L(i, k, i, k) * dyadic(NiNk, NiNk + NkNi);
205 }
206 }
207
208 return moduli;
209 }
210
211 template <typename ST>
212 auto transformVolumetricTangentModuli(const ST& Uprime, const ST& Uprimeprime, const auto& C, ST J) const {
213 const auto invC = C.inverse().eval();
214 const auto CTinv = tensorView(invC, std::array<Eigen::Index, 2>({3, 3}));
215
216 Eigen::TensorFixedSize<ST, Eigen::Sizes<3, 3, 3, 3>> moduli =
217 (J * ((Uprime + J * Uprimeprime) * dyadic(CTinv, CTinv) -
218 (2 * Uprime * symTwoSlots(fourthOrderIKJL(invC, invC), {2, 3}))))
219 .eval();
220
221 return moduli;
222 }
223
224 template <typename Derived>
225 auto principalStretches(const Eigen::MatrixBase<Derived>& Craw, int options = Eigen::ComputeEigenvectors) const {
226 auto C = Impl::maybeFromVoigt(Craw);
227 return Impl::principalStretches<typename Derived::Scalar>(C, options);
228 }
229
240 template <typename Derived, typename ST>
241 ST detF(const Eigen::MatrixBase<Derived>& C, const Eigen::Vector<ST, 3>& lambda) const {
242 if constexpr (isAutoDiff) {
243 const auto detC = sqrt(C.derived().eval().determinant());
244 return detC;
245 } else {
246 const auto detC = Impl::determinantFromPrincipalValues(lambda);
247 Impl::checkPositiveOrAbort(detC);
248 return detC;
249 }
250 }
251
258 template <typename Derived, typename ST>
259 requires(std::same_as<typename Derived::Scalar, ST>)
260 auto deviatoricEnergy(const Eigen::MatrixBase<Derived>& C, const Eigen::Vector<ST, 3>& lambdasST) const {
261 if constexpr (not Concepts::AutodiffScalar<ST>) {
262 return dev_.storedEnergy(lambdasST);
263 } else if constexpr (std::is_same_v<ST, autodiff::dual>) {
264 autodiff::dual e;
265 const auto Cvec = toVoigt(C.derived());
266 const auto realCVec = autodiff::derivative<0>(Cvec);
267 const auto dualCVec = autodiff::derivative<1>(Cvec);
268
269 const auto [lambdas, N] = principalStretches(realCVec);
270
271 e.val = dev_.storedEnergy(lambdas);
272 e.grad = (transformDeviatoricStresses(dev_.stresses(lambdas), N).transpose() / 2 * fromVoigt(dualCVec)).trace();
273 return e;
274 } else if constexpr (std::is_same_v<ST, autodiff::dual2nd>) {
275 autodiff::dual2nd e;
276 const auto Cvec = toVoigt(C.derived());
277 const auto realCVec = derivative<0>(Cvec);
278 const auto dualC = fromVoigt(Cvec.unaryExpr([](auto& v) { return v.grad.val; }).eval());
279 const auto dualC2 = fromVoigt(Cvec.unaryExpr([](auto& v) { return v.val.grad; }).eval());
280 const auto [lambdas, N] = principalStretches(realCVec);
281
282 e.val = dev_.storedEnergy(lambdas);
283 e.grad.val = (transformDeviatoricStresses(dev_.stresses(lambdas), N).transpose() / 2 * dualC).trace();
284 e.val.grad = e.grad.val;
285
286 const auto Cmoduli = transformDeviatoricTangentModuli(dev_.tangentModuli(lambdas), N);
287 const Eigen::array<Eigen::IndexPair<Eigen::Index>, 2> double_contraction = {Eigen::IndexPair<Eigen::Index>(2, 0),
288 Eigen::IndexPair<Eigen::Index>(3, 1)};
289 const Eigen::array<Eigen::IndexPair<Eigen::Index>, 2> double_contraction2 = {
290 Eigen::IndexPair<Eigen::Index>(0, 0), Eigen::IndexPair<Eigen::Index>(1, 1)};
291 const auto tCdual = tensorView(dualC, std::array<Eigen::Index, 2>({3, 3}));
292 const auto tCdualT = tensorView(dualC2, std::array<Eigen::Index, 2>({3, 3}));
293 const auto prod = Cmoduli.contract(tCdual, double_contraction);
294 const Eigen::Tensor<double, 0> res = tCdualT.contract(prod, double_contraction2);
295 e.grad.grad = res(0) / 4.0; // extracting value of zero order tensor
296
297 return e;
298 } else
299 static_assert(Dune::AlwaysFalse<Derived>::value, "No fitting ScalarType.");
300 }
301
309 template <typename Derived, typename ST>
310 requires(std::same_as<typename Derived::Scalar, ST>)
311 auto deviatoricStress(const Eigen::MatrixBase<Derived>& C, const Eigen::Vector<ST, dim>& lambdasST,
312 Eigen::Matrix<ST, dim, dim> NST) const {
313 if constexpr (not Concepts::AutodiffScalar<ST>) {
314 return transformDeviatoricStresses(dev_.stresses(lambdasST), NST);
315 } else if constexpr (std::is_same_v<ST, autodiff::dual>) {
316 constexpr int nVoigtIndices = 6;
317 Eigen::Vector<autodiff::dual, nVoigtIndices> g;
318 const auto Cvec = toVoigt(C.derived());
319 const auto realCVec = derivative<0>(Cvec);
320 const auto realC = fromVoigt(realCVec);
321 const auto dualC = fromVoigt(Cvec.unaryExpr([](const auto& v) { return v.grad; }).eval());
322 const auto [lambdas, N] = principalStretches(realC);
323
324 const auto stresses = toVoigt(transformDeviatoricStresses(dev_.stresses(lambdas), N));
325 const auto Cmoduli = toVoigt(transformDeviatoricTangentModuli(dev_.tangentModuli(lambdas), N));
326 Eigen::Vector<double, nVoigtIndices> stressDirectionalDerivatrive = Cmoduli * toVoigt(dualC);
327 stressDirectionalDerivatrive.topRows<3>() /= 2.0;
328
329 for (int i = 0; i < nVoigtIndices; ++i) {
330 g[i].val = stresses[i];
331 g[i].grad = stressDirectionalDerivatrive[i];
332 }
333
334 return fromVoigt(g);
335 } else
336 static_assert(Dune::AlwaysFalse<Derived>::value, "No fitting ScalarType.");
337 }
338};
339
340} // namespace Ikarus::Materials
Helper for the Eigen::Tensor types.
Implementation of the volumetric part of a hyperelastic material.
helper functions used by material model implementations.
constexpr Eigen::Index toVoigt(Eigen::Index i, Eigen::Index j) noexcept
Converts 2D indices to Voigt notation index.
Definition: tensorutils.hh:179
Eigen::Tensor< typename Derived::Scalar, rank > tensorView(const Eigen::EigenBase< Derived > &matrix, const std::array< T, rank > &dims)
View an Eigen matrix as an Eigen Tensor with specified dimensions.
Definition: tensorutils.hh:32
auto fourthOrderIKJL(const Eigen::MatrixBase< AType > &A, const Eigen::MatrixBase< BType > &B)
Computes the IKJL product of two matrices.
Definition: tensorutils.hh:135
auto dyadic(const auto &A_ij, const auto &B_kl)
Computes the dyadic product of two Eigen tensors.
Definition: tensorutils.hh:47
auto fromVoigt(const Eigen::Matrix< ST, size, 1, Options, maxSize, 1 > &EVoigt, bool isStrain=true)
Converts a vector given in Voigt notation to a matrix.
Definition: tensorutils.hh:284
auto symTwoSlots(const Eigen::TensorFixedSize< ScalarType, Eigen::Sizes< dim, dim, dim, dim > > &t, const std::array< size_t, 2 > &slots)
Creates a symmetric fourth-order tensor in the two specified slots of the input tensor.
Definition: tensorutils.hh:158
Definition: arrudaboyce.hh:27
Implementation of a general Hyperelastic Material material model.
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:35
Hyperelastic(const DEV &dev)
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:71
static constexpr bool stressAcceptsVoigt
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:59
static constexpr bool energyAcceptsVoigt
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:57
static constexpr auto tangentModuliTag
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:56
typename DEV::ScalarType ScalarType
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:39
const DEV & deviatoricFunction() const
Returns the deviatoric function.
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:81
static constexpr bool moduliAcceptsVoigt
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:61
std::conditional_t< hasVolumetricPart, std::pair< MaterialParametersDEV, MaterialParametersVOL >, MaterialParametersDEV > MaterialParameters
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:52
StressMatrix stressesImpl(const Eigen::MatrixBase< Derived > &C) const
Computes the stresses in the Hyperelastic material model.
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:120
static constexpr int dim
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:43
auto rebind() const
Rebinds the material to a different scalar type.
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:162
typename VOL::MaterialParameter MaterialParametersVOL
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:49
MaterialTensor tangentModuliImpl(const Eigen::MatrixBase< Derived > &C) const
Computes the tangent moduli in the Hyperelastic material model.
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:142
StrainMatrix StressMatrix
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:45
static constexpr bool stressToVoigt
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:58
ScalarType storedEnergyImpl(const Eigen::MatrixBase< Derived > &C) const
Computes the total stored energy in the Hyperelastic material model.
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:103
static constexpr auto stressTag
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:55
static constexpr double derivativeFactorImpl
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:62
Eigen::Matrix< ScalarType, dim, dim > StrainMatrix
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:44
const MaterialParameters materialParametersImpl() const
Returns the material parameters stored in the deviatoric part of the material.
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:89
typename DEV::MaterialParameters MaterialParametersDEV
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:48
static constexpr bool isAutoDiff
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:41
static constexpr bool hasVolumetricPart
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:40
const VOL & volumetricFunction() const
Returns the volumetric function.
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:84
Hyperelastic(const DEV &dev, const VOL &vol)
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:76
static constexpr auto strainTag
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:54
static constexpr bool moduliToVoigt
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:60
static constexpr std::string nameImpl() noexcept
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:64
Eigen::TensorFixedSize< ScalarType, Eigen::Sizes< dim, dim, dim, dim > > MaterialTensor
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:46
Interface classf or materials.
Definition: finiteelements/mechanics/materials/interface.hh:80
auto stresses(const Eigen::MatrixBase< Derived > &Eraw) const
Get the stresses of the material.
Definition: finiteelements/mechanics/materials/interface.hh:160
Concept to check if the underlying scalar type is a dual type.
Definition: utils/concepts.hh:606
Contains the Material interface class and related template functions for material properties.
Implementation of the interface for the deviatoric part of a hyperelastic material.
Header file including concepts for hyperelastic material models.