12#ifndef MFEM_ELASTICITY_MAT_NEOHOOKEAN_HPP
13#define MFEM_ELASTICITY_MAT_NEOHOOKEAN_HPP
20using mfem::internal::tensor;
21using mfem::internal::make_tensor;
39template <
int dim = 3, GradientType gradient_type = GradientType::Symbolic>
42 static_assert(
dim == 3,
"NeoHookean model currently implemented only in 3D");
51 MFEM_HOST_DEVICE tensor<T, dim, dim>
52 stress(
const tensor<T, dim, dim> &dudx)
const
54 static constexpr auto I = mfem::internal::IsotropicIdentity<dim>();
56 T
p = -2.0 *
D1 * J * (J - 1);
57 auto devB = dev(dudx + transpose(dudx) + dot(dudx, transpose(dudx)));
58 auto sigma = -(
p / J) * I + 2 * (
C1 / (T) pow(J, 5.0 / 3.0)) * devB;
71 MFEM_HOST_DEVICE
static void
73 tensor<mfem::real_t, dim, dim> &dudx,
74 tensor<mfem::real_t, dim, dim> &
sigma)
89 MFEM_HOST_DEVICE tensor<mfem::real_t, dim, dim, dim, dim>
90 gradient(tensor<mfem::real_t, dim, dim> dudx)
const
92 static constexpr auto I = mfem::internal::IsotropicIdentity<dim>();
94 tensor<mfem::real_t, dim, dim> F = I + dudx;
95 tensor<mfem::real_t, dim, dim> invF = inv(F);
96 tensor<mfem::real_t, dim, dim> devB =
97 dev(dudx + transpose(dudx) + dot(dudx, transpose(dudx)));
100 return make_tensor<dim, dim, dim, dim>([&](
int i,
int j,
int k,
103 return 2 * (
D1 * J * (i == j) -
107 ((i == k) * F[j][l] + F[i][l] * (j == k) -
119 MFEM_HOST_DEVICE tensor<mfem::real_t, dim, dim>
121 const tensor<mfem::real_t, dim, dim> &ddudx)
const
127#ifdef MFEM_USE_ENZYME
147 return tensor<mfem::real_t, dim, dim> {};
150 MFEM_HOST_DEVICE tensor<mfem::real_t, dim, dim>
152 const tensor<mfem::real_t, dim, dim> &ddudx)
const
154 auto sigma =
stress(make_tensor<dim, dim>([&](
int i,
int j)
156 return mfem::internal::dual<mfem::real_t, mfem::real_t> {dudx[i][j], ddudx[i][j]};
158 return make_tensor<dim, dim>(
159 [&](
int i,
int j) {
return sigma[i][j].gradient; });
162#ifdef MFEM_USE_ENZYME
163 MFEM_HOST_DEVICE tensor<mfem::real_t, dim, dim>
165 const tensor<mfem::real_t, dim, dim> &ddudx)
const
167 tensor<mfem::real_t, dim, dim>
sigma{};
168 tensor<mfem::real_t, dim, dim> dsigma{};
175 MFEM_HOST_DEVICE tensor<mfem::real_t, dim, dim>
177 const tensor<mfem::real_t, dim, dim> &ddudx)
const
179 tensor<mfem::real_t, dim, dim, dim, dim>
gradient{};
180 tensor<mfem::real_t, dim, dim>
sigma{};
181 tensor<mfem::real_t, dim, dim> dir{};
183 for (
int i = 0; i <
dim; i++)
185 for (
int j = 0; j <
dim; j++)
198 MFEM_HOST_DEVICE tensor<mfem::real_t, dim, dim>
200 const tensor<mfem::real_t, dim, dim> &ddudx)
const
209 MFEM_HOST_DEVICE tensor<mfem::real_t, dim, dim>
211 const tensor<mfem::real_t, dim, dim> &ddu_dx)
const
213 static constexpr auto I = mfem::internal::IsotropicIdentity<dim>();
215 tensor<mfem::real_t, dim, dim> F = I + du_dx;
216 tensor<mfem::real_t, dim, dim> invFT = inv(transpose(F));
217 tensor<mfem::real_t, dim, dim> devB =
218 dev(du_dx + transpose(du_dx) + dot(du_dx, transpose(du_dx)));
224 return ((2 *
D1 * J * a1 -
mfem::real_t(4.0 / 3.0) * coef * a2) * I -
226 (2 * coef) * (dot(ddu_dx, transpose(F)) + dot(F, transpose(ddu_dx))));
real_t sigma(const Vector &x)
return_type __enzyme_autodiff(Args...)
return_type __enzyme_fwddiff(Args...)
real_t p(const Vector &x, real_t t)
MFEM_HOST_DEVICE tensor< mfem::real_t, dim, dim > action_of_gradient(const tensor< mfem::real_t, dim, dim > &dudx, const tensor< mfem::real_t, dim, dim > &ddudx) const
Apply the gradient of the stress.
MFEM_HOST_DEVICE tensor< mfem::real_t, dim, dim > action_of_gradient_symbolic(const tensor< mfem::real_t, dim, dim > &du_dx, const tensor< mfem::real_t, dim, dim > &ddu_dx) const
MFEM_HOST_DEVICE tensor< mfem::real_t, dim, dim > action_of_gradient_enzyme_rev(const tensor< mfem::real_t, dim, dim > &dudx, const tensor< mfem::real_t, dim, dim > &ddudx) const
MFEM_HOST_DEVICE tensor< mfem::real_t, dim, dim > action_of_gradient_finite_diff(const tensor< mfem::real_t, dim, dim > &dudx, const tensor< mfem::real_t, dim, dim > &ddudx) const
static MFEM_HOST_DEVICE void stress_wrapper(NeoHookeanMaterial< dim, gradient_type > *self, tensor< mfem::real_t, dim, dim > &dudx, tensor< mfem::real_t, dim, dim > &sigma)
A method to wrap the stress calculation into a static function.
MFEM_HOST_DEVICE tensor< mfem::real_t, dim, dim > action_of_gradient_dual(const tensor< mfem::real_t, dim, dim > &dudx, const tensor< mfem::real_t, dim, dim > &ddudx) const
MFEM_HOST_DEVICE tensor< mfem::real_t, dim, dim > action_of_gradient_enzyme_fwd(const tensor< mfem::real_t, dim, dim > &dudx, const tensor< mfem::real_t, dim, dim > &ddudx) const
MFEM_HOST_DEVICE tensor< T, dim, dim > stress(const tensor< T, dim, dim > &dudx) const
Compute the stress response.
MFEM_HOST_DEVICE tensor< mfem::real_t, dim, dim, dim, dim > gradient(tensor< mfem::real_t, dim, dim > dudx) const
Compute the gradient.
Implementation of the tensor class.