12#include <autodiff/forward/dual/dual.hpp>
13#include <autodiff/forward/dual/eigen.hpp>
33template <
typename DEV,
typename VOL = NoVolumetricPart>
36 static_assert(std::is_same_v<DEV, Deviatoric<typename DEV::DeviatoricFunction>>);
37 static_assert(std::is_same_v<VOL, Volumetric<typename VOL::VolumetricFunction>>);
43 static constexpr int dim = 3;
46 using MaterialTensor = Eigen::TensorFixedSize<ScalarType, Eigen::Sizes<dim, dim, dim, dim>>;
54 std::conditional_t<hasVolumetricPart, std::pair<MaterialParametersDEV, MaterialParametersVOL>,
67 [[nodiscard]]
constexpr static std::string
nameImpl() noexcept {
69 return "Hyperelastic (" + DEV::name() +
", " + VOL::name() +
")";
71 return "Hyperelastic (" + DEV::name() +
")";
94 return {dev_.materialParameters(), vol_.materialParameter()};
96 return dev_.materialParameters();
105 template <
typename Derived>
107 static_assert(Concepts::EigenMatrixOrVoigtNotation3<Derived>);
109 const auto lambdas = principalStretches(C, Eigen::EigenvaluesOnly).first;
110 auto J = detF(C, lambdas);
112 return deviatoricEnergy(C, lambdas) + vol_.storedEnergy(J);
122 template <
bool voigt,
typename Derived>
124 static_assert(Concepts::EigenMatrixOrVoigtNotation3<Derived>);
125 if constexpr (!voigt) {
126 const auto [lambdas, N] = principalStretches(C);
127 auto J = detF(C, lambdas);
129 const auto Sdev = deviatoricStress(C, lambdas, N);
130 const auto Svol = transformVolumetricStresses(vol_.firstDerivative(J), C, J);
134 static_assert(voigt ==
false,
"Hyperelastic does not support returning stresses in Voigt notation");
144 template <
bool voigt,
typename Derived>
146 static_assert(Concepts::EigenMatrixOrVoigtNotation3<Derived>);
147 if constexpr (!voigt) {
148 const auto [lambdas, N] = principalStretches(C);
149 auto J = detF(C, lambdas);
151 const auto moduliDev = transformDeviatoricTangentModuli(dev_.tangentModuli(lambdas), N);
152 const auto moduliVol = transformVolumetricTangentModuli(vol_.firstDerivative(J), vol_.secondDerivative(J), C, J);
154 return moduliDev + moduliVol;
156 static_assert(voigt ==
false,
"Hyperelastic does not support returning tangent moduli in Voigt notation");
164 template <
typename STO>
166 auto reboundDEV = dev_.template rebind<STO>();
174 inline static constexpr auto dimensionRange() {
return Dune::range(
dim); }
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();
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();
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{};
192 auto indexList = std::array<Eigen::Index, 2>({
dim,
dim});
194 for (
const auto i : dimensionRange())
195 for (
const auto k : dimensionRange()) {
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);
200 moduli += L(i, i, k, k) *
dyadic(NiNi, NkNk);
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);
207 moduli += L(i, k, i, k) *
dyadic(NiNk, NiNk + NkNi);
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}));
219 Eigen::TensorFixedSize<ST, Eigen::Sizes<3, 3, 3, 3>> moduli =
220 (J * ((Uprime + J * Uprimeprime) *
dyadic(CTinv, CTinv) -
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);
243 template <
typename Derived,
typename ST>
244 ST detF(
const Eigen::MatrixBase<Derived>& C,
const Eigen::Vector<ST, 3>& lambda)
const {
246 const auto detC = sqrt(C.derived().eval().determinant());
249 const auto detC = Impl::determinantFromPrincipalValues(lambda);
250 Impl::checkPositiveOrAbort(detC);
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>) {
268 const auto Cvec =
toVoigt(C.derived());
269 const auto realCVec = autodiff::derivative<0>(Cvec);
270 const auto dualCVec = autodiff::derivative<1>(Cvec);
272 const auto [lambdas, N] = principalStretches(realCVec);
274 e.val = dev_.storedEnergy(lambdas);
275 e.grad = (transformDeviatoricStresses(dev_.stresses(lambdas), N).transpose() / 2 *
fromVoigt(dualCVec)).trace();
277 }
else if constexpr (std::is_same_v<ST, autodiff::dual2nd>) {
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);
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;
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;
302 static_assert(Dune::AlwaysFalse<Derived>::value,
"No fitting ScalarType.");
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);
324 const auto dualC =
fromVoigt(Cvec.unaryExpr([](
const auto& v) { return v.grad; }).eval());
325 const auto [lambdas, N] = principalStretches(realC);
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;
332 for (
int i = 0; i < nVoigtIndices; ++i) {
334 g[i].grad = stressDirectionalDerivatrive[i];
339 static_assert(Dune::AlwaysFalse<Derived>::value,
"No fitting ScalarType.");
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.