version 0.4.7
finiteelements/mechanics/materials/hyperelastic/interface.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
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 DeviatoricType = DEV;
49 using VolumetricType = VOL;
50
51 using MaterialParametersDEV = typename DEV::MaterialParameters;
52 using MaterialParametersVOL = typename VOL::MaterialParameter;
54 std::conditional_t<hasVolumetricPart, std::pair<MaterialParametersDEV, MaterialParametersVOL>,
56
58 static constexpr auto stressTag = StressTags::PK2;
60 static constexpr bool energyAcceptsVoigt = false;
61 static constexpr bool stressToVoigt = false;
62 static constexpr bool stressAcceptsVoigt = false;
63 static constexpr bool moduliToVoigt = false;
64 static constexpr bool moduliAcceptsVoigt = false;
65 static constexpr double derivativeFactorImpl = 2;
66
67 [[nodiscard]] constexpr static std::string nameImpl() noexcept {
68 if constexpr (hasVolumetricPart)
69 return "Hyperelastic (" + DEV::name() + ", " + VOL::name() + ")";
70 else
71 return "Hyperelastic (" + DEV::name() + ")";
72 }
73
74 explicit Hyperelastic(const DEV& dev)
75 requires(not hasVolumetricPart)
76 : dev_{dev},
77 vol_(VOL{MaterialParametersVOL{}, typename VOL::VolumetricFunction{}}) {}
78
79 Hyperelastic(const DEV& dev, const VOL& vol)
80 : dev_(dev),
81 vol_(vol) {}
82
84 const DEV& deviatoricFunction() const { return dev_; }
85
87 const VOL& volumetricFunction() const { return vol_; }
88
93 if constexpr (hasVolumetricPart)
94 return {dev_.materialParameters(), vol_.materialParameter()};
95 else
96 return dev_.materialParameters();
97 }
98
105 template <typename Derived>
106 ScalarType storedEnergyImpl(const Eigen::MatrixBase<Derived>& C) const {
107 static_assert(Concepts::EigenMatrixOrVoigtNotation3<Derived>);
108
109 const auto lambdas = principalStretches(C, Eigen::EigenvaluesOnly).first;
110 auto J = detF(C, lambdas);
111
112 return deviatoricEnergy(C, lambdas) + vol_.storedEnergy(J);
113 }
114
122 template <bool voigt, typename Derived>
123 StressMatrix stressesImpl(const Eigen::MatrixBase<Derived>& C) const {
124 static_assert(Concepts::EigenMatrixOrVoigtNotation3<Derived>);
125 if constexpr (!voigt) {
126 const auto [lambdas, N] = principalStretches(C);
127 auto J = detF(C, lambdas);
128
129 const auto Sdev = deviatoricStress(C, lambdas, N);
130 const auto Svol = transformVolumetricStresses(vol_.firstDerivative(J), C, J);
131
132 return Sdev + Svol;
133 } else
134 static_assert(voigt == false, "Hyperelastic does not support returning stresses in Voigt notation");
135 }
136
144 template <bool voigt, typename Derived>
145 MaterialTensor tangentModuliImpl(const Eigen::MatrixBase<Derived>& C) const {
146 static_assert(Concepts::EigenMatrixOrVoigtNotation3<Derived>);
147 if constexpr (!voigt) {
148 const auto [lambdas, N] = principalStretches(C);
149 auto J = detF(C, lambdas);
150
151 const auto moduliDev = transformDeviatoricTangentModuli(dev_.tangentModuli(lambdas), N);
152 const auto moduliVol = transformVolumetricTangentModuli(vol_.firstDerivative(J), vol_.secondDerivative(J), C, J);
153
154 return moduliDev + moduliVol;
155 } else
156 static_assert(voigt == false, "Hyperelastic does not support returning tangent moduli in Voigt notation");
157 }
158
164 template <typename STO>
165 auto rebind() const {
166 auto reboundDEV = dev_.template rebind<STO>();
167 return Hyperelastic<decltype(reboundDEV), VOL>(reboundDEV, vol_);
168 }
169
170private:
171 DEV dev_;
172 VOL vol_;
173
174 inline static constexpr auto dimensionRange() { return Dune::range(dim); }
175
176 template <typename ST>
177 Eigen::Matrix<ST, dim, dim> transformDeviatoricStresses(const Eigen::Vector<ST, dim>& principalStress,
178 const Eigen::Matrix<ST, dim, dim>& N) const {
179 return (N * principalStress.asDiagonal() * N.transpose()).eval();
180 }
181
182 template <typename ST>
183 Eigen::Matrix<ST, dim, dim> transformVolumetricStresses(ST Uprime, const auto& C, ST J) const {
184 return J * Uprime * C.inverse();
185 }
186
187 template <typename ST>
188 auto transformDeviatoricTangentModuli(const Eigen::TensorFixedSize<ST, Eigen::Sizes<dim, dim, dim, dim>>& L,
189 const Eigen::Matrix<ST, dim, dim>& N) const {
190 Eigen::TensorFixedSize<ST, Eigen::Sizes<dim, dim, dim, dim>> moduli{};
191 moduli.setZero();
192 auto indexList = std::array<Eigen::Index, 2>({dim, dim});
193
194 for (const auto i : dimensionRange())
195 for (const auto k : dimensionRange()) {
196 // First term: L[i, i, k, k] * ((N[i] ⊗ N[i]) ⊗ (N[k] ⊗ N[k]))
197 auto NiNi = tensorView(dyadic(N.col(i).eval(), N.col(i).eval()), indexList);
198 auto NkNk = tensorView(dyadic(N.col(k).eval(), N.col(k).eval()), indexList);
199
200 moduli += L(i, i, k, k) * dyadic(NiNi, NkNk);
201
202 // Second term (only if i != k): L[i, k, i, k] * (N[i] ⊗ N[k] ⊗ (N[i] ⊗ N[k] + N[k] ⊗ N[i]))
203 if (i != k) {
204 auto NiNk = tensorView(dyadic(N.col(i).eval(), N.col(k).eval()), indexList);
205 auto NkNi = tensorView(dyadic(N.col(k).eval(), N.col(i).eval()), indexList);
206
207 moduli += L(i, k, i, k) * dyadic(NiNk, NiNk + NkNi);
208 }
209 }
210
211 return moduli;
212 }
213
214 template <typename ST>
215 auto transformVolumetricTangentModuli(const ST& Uprime, const ST& Uprimeprime, const auto& C, ST J) const {
216 const auto invC = C.inverse().eval();
217 const auto CTinv = tensorView(invC, std::array<Eigen::Index, 2>({3, 3}));
218
219 Eigen::TensorFixedSize<ST, Eigen::Sizes<3, 3, 3, 3>> moduli =
220 (J * ((Uprime + J * Uprimeprime) * dyadic(CTinv, CTinv) -
221 (2 * Uprime * symTwoSlots(fourthOrderIKJL(invC, invC), {2, 3}))))
222 .eval();
223
224 return moduli;
225 }
226
227 template <typename Derived>
228 auto principalStretches(const Eigen::MatrixBase<Derived>& Craw, int options = Eigen::ComputeEigenvectors) const {
229 auto C = Impl::maybeFromVoigt(Craw);
230 return Impl::principalStretches<typename Derived::Scalar>(C, options);
231 }
232
243 template <typename Derived, typename ST>
244 ST detF(const Eigen::MatrixBase<Derived>& C, const Eigen::Vector<ST, 3>& lambda) const {
245 if constexpr (isAutoDiff) {
246 const auto detC = sqrt(C.derived().eval().determinant());
247 return detC;
248 } else {
249 const auto detC = Impl::determinantFromPrincipalValues(lambda);
250 Impl::checkPositiveOrAbort(detC);
251 return detC;
252 }
253 }
254
261 template <typename Derived, typename ST>
262 requires(std::same_as<typename Derived::Scalar, ST>)
263 auto deviatoricEnergy(const Eigen::MatrixBase<Derived>& C, const Eigen::Vector<ST, 3>& lambdasST) const {
264 if constexpr (not Concepts::AutodiffScalar<ST>) {
265 return dev_.storedEnergy(lambdasST);
266 } else if constexpr (std::is_same_v<ST, autodiff::dual>) {
267 autodiff::dual e;
268 const auto Cvec = toVoigt(C.derived());
269 const auto realCVec = autodiff::derivative<0>(Cvec);
270 const auto dualCVec = autodiff::derivative<1>(Cvec);
271
272 const auto [lambdas, N] = principalStretches(realCVec);
273
274 e.val = dev_.storedEnergy(lambdas);
275 e.grad = (transformDeviatoricStresses(dev_.stresses(lambdas), N).transpose() / 2 * fromVoigt(dualCVec)).trace();
276 return e;
277 } else if constexpr (std::is_same_v<ST, autodiff::dual2nd>) {
278 autodiff::dual2nd e;
279 const auto Cvec = toVoigt(C.derived());
280 const auto realCVec = derivative<0>(Cvec);
281 const auto dualC = fromVoigt(Cvec.unaryExpr([](auto& v) { return v.grad.val; }).eval());
282 const auto dualC2 = fromVoigt(Cvec.unaryExpr([](auto& v) { return v.val.grad; }).eval());
283 const auto [lambdas, N] = principalStretches(realCVec);
284
285 e.val = dev_.storedEnergy(lambdas);
286 e.grad.val = (transformDeviatoricStresses(dev_.stresses(lambdas), N).transpose() / 2 * dualC).trace();
287 e.val.grad = e.grad.val;
288
289 const auto Cmoduli = transformDeviatoricTangentModuli(dev_.tangentModuli(lambdas), N);
290 const Eigen::array<Eigen::IndexPair<Eigen::Index>, 2> double_contraction = {Eigen::IndexPair<Eigen::Index>(2, 0),
291 Eigen::IndexPair<Eigen::Index>(3, 1)};
292 const Eigen::array<Eigen::IndexPair<Eigen::Index>, 2> double_contraction2 = {
293 Eigen::IndexPair<Eigen::Index>(0, 0), Eigen::IndexPair<Eigen::Index>(1, 1)};
294 const auto tCdual = tensorView(dualC, std::array<Eigen::Index, 2>({3, 3}));
295 const auto tCdualT = tensorView(dualC2, std::array<Eigen::Index, 2>({3, 3}));
296 const auto prod = Cmoduli.contract(tCdual, double_contraction);
297 const Eigen::Tensor<double, 0> res = tCdualT.contract(prod, double_contraction2);
298 e.grad.grad = res(0) / 4.0; // extracting value of zero order tensor
299
300 return e;
301 } else
302 static_assert(Dune::AlwaysFalse<Derived>::value, "No fitting ScalarType.");
303 }
304
312 template <typename Derived, typename ST>
313 requires(std::same_as<typename Derived::Scalar, ST>)
314 auto deviatoricStress(const Eigen::MatrixBase<Derived>& C, const Eigen::Vector<ST, dim>& lambdasST,
315 Eigen::Matrix<ST, dim, dim> NST) const {
316 if constexpr (not Concepts::AutodiffScalar<ST>) {
317 return transformDeviatoricStresses(dev_.stresses(lambdasST), NST);
318 } else if constexpr (std::is_same_v<ST, autodiff::dual>) {
319 constexpr int nVoigtIndices = 6;
320 Eigen::Vector<autodiff::dual, nVoigtIndices> g;
321 const auto Cvec = toVoigt(C.derived());
322 const auto realCVec = derivative<0>(Cvec);
323 const auto realC = fromVoigt(realCVec);
324 const auto dualC = fromVoigt(Cvec.unaryExpr([](const auto& v) { return v.grad; }).eval());
325 const auto [lambdas, N] = principalStretches(realC);
326
327 const auto stresses = toVoigt(transformDeviatoricStresses(dev_.stresses(lambdas), N));
328 const auto Cmoduli = toVoigt(transformDeviatoricTangentModuli(dev_.tangentModuli(lambdas), N));
329 Eigen::Vector<double, nVoigtIndices> stressDirectionalDerivatrive = Cmoduli * toVoigt(dualC);
330 stressDirectionalDerivatrive.topRows<3>() /= 2.0;
331
332 for (int i = 0; i < nVoigtIndices; ++i) {
333 g[i].val = stresses[i];
334 g[i].grad = stressDirectionalDerivatrive[i];
335 }
336
337 return fromVoigt(g);
338 } else
339 static_assert(Dune::AlwaysFalse<Derived>::value, "No fitting ScalarType.");
340 }
341};
342
343} // namespace Ikarus::Materials
Helper for the Eigen::Tensor types.
helper functions used by material model implementations.
Implementation of the volumetric part of a hyperelastic material.
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:296
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
constexpr Eigen::Index toVoigt(Eigen::Index i, Eigen::Index j) noexcept
Converts 2D indices to Voigt notation index.
Definition: tensorutils.hh:182
Definition: decomposehyperelastic.hh:15
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:74
static constexpr bool stressAcceptsVoigt
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:62
static constexpr bool energyAcceptsVoigt
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:60
static constexpr auto tangentModuliTag
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:59
typename DEV::ScalarType ScalarType
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:39
DEV DeviatoricType
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:48
const DEV & deviatoricFunction() const
Returns the deviatoric function.
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:84
static constexpr bool moduliAcceptsVoigt
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:64
std::conditional_t< hasVolumetricPart, std::pair< MaterialParametersDEV, MaterialParametersVOL >, MaterialParametersDEV > MaterialParameters
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:55
StressMatrix stressesImpl(const Eigen::MatrixBase< Derived > &C) const
Computes the stresses in the Hyperelastic material model.
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:123
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:165
typename VOL::MaterialParameter MaterialParametersVOL
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:52
MaterialTensor tangentModuliImpl(const Eigen::MatrixBase< Derived > &C) const
Computes the tangent moduli in the Hyperelastic material model.
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:145
StrainMatrix StressMatrix
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:45
static constexpr bool stressToVoigt
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:61
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:106
static constexpr auto stressTag
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:58
static constexpr double derivativeFactorImpl
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:65
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:92
typename DEV::MaterialParameters MaterialParametersDEV
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:51
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:87
VOL VolumetricType
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:49
Hyperelastic(const DEV &dev, const VOL &vol)
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:79
static constexpr auto strainTag
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:57
static constexpr bool moduliToVoigt
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:63
static constexpr std::string nameImpl() noexcept
Definition: finiteelements/mechanics/materials/hyperelastic/interface.hh:67
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:113
auto stresses(const Eigen::MatrixBase< Derived > &Eraw) const
Get the stresses of the material.
Definition: finiteelements/mechanics/materials/interface.hh:213
Concept to check if the underlying scalar type is a dual type.
Definition: utils/concepts.hh:625
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.