xref: /libCEED/examples/solids/qfunctions/finite-strain-neo-hookean.h (revision d4cc18453651bd0f94c1a2e078b2646a92dafdcc)
1*9ba83ac0SJeremy L Thompson // Copyright (c) 2017-2026, Lawrence Livermore National Security, LLC and other CEED contributors.
2c8565611SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3c8565611SJeremy L Thompson //
4c8565611SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
5c8565611SJeremy L Thompson //
6c8565611SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
7c8565611SJeremy L Thompson 
8c8565611SJeremy L Thompson /// @file
9c8565611SJeremy L Thompson /// Hyperelasticity, finite strain for solid mechanics example using PETSc
10c8565611SJeremy L Thompson 
11c0b5abf0SJeremy L Thompson #include <ceed/types.h>
12c0b5abf0SJeremy L Thompson #ifndef CEED_RUNNING_JIT_PASS
13c8565611SJeremy L Thompson #include <math.h>
14c0b5abf0SJeremy L Thompson #endif
15c8565611SJeremy L Thompson 
16c8565611SJeremy L Thompson #ifndef PHYSICS_STRUCT
17c8565611SJeremy L Thompson #define PHYSICS_STRUCT
18c8565611SJeremy L Thompson typedef struct Physics_private *Physics;
19c8565611SJeremy L Thompson struct Physics_private {
20c8565611SJeremy L Thompson   CeedScalar nu;  // Poisson's ratio
21c8565611SJeremy L Thompson   CeedScalar E;   // Young's Modulus
22c8565611SJeremy L Thompson };
23c8565611SJeremy L Thompson #endif
24c8565611SJeremy L Thompson 
25c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
26c8565611SJeremy L Thompson // Series approximation of log1p()
27c8565611SJeremy L Thompson //  log1p() is not vectorized in libc
28c8565611SJeremy L Thompson //
29c8565611SJeremy L Thompson //  The series expansion is accurate to 1e-7 in the range sqrt(2)/2 < J < sqrt(2), with machine precision accuracy near J=1.
30c8565611SJeremy L Thompson //  The initialization extends this range to 0.35 ~= sqrt(2)/4 < J < sqrt(2)*2 ~= 2.83, which should be sufficient for applications of the Neo-Hookean
31c8565611SJeremy L Thompson //  model.
32c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
33c8565611SJeremy L Thompson #ifndef LOG1P_SERIES_SHIFTED
34c8565611SJeremy L Thompson #define LOG1P_SERIES_SHIFTED
log1p_series_shifted(CeedScalar x)35c8565611SJeremy L Thompson CEED_QFUNCTION_HELPER CeedScalar log1p_series_shifted(CeedScalar x) {
36c8565611SJeremy L Thompson   const CeedScalar left = sqrt(2.) / 2 - 1, right = sqrt(2.) - 1;
37c8565611SJeremy L Thompson   CeedScalar       sum = 0;
38c8565611SJeremy L Thompson   if (1) {           // Disable if the smaller range sqrt(2)/2 < J < sqrt(2) is sufficient
39c8565611SJeremy L Thompson     if (x < left) {  // Replace if with while for arbitrary range (may hurt vectorization)
40c8565611SJeremy L Thompson       sum -= log(2.) / 2;
41c8565611SJeremy L Thompson       x = 1 + 2 * x;
42c8565611SJeremy L Thompson     } else if (right < x) {
43c8565611SJeremy L Thompson       sum += log(2.) / 2;
44c8565611SJeremy L Thompson       x = (x - 1) / 2;
45c8565611SJeremy L Thompson     }
46c8565611SJeremy L Thompson   }
47c8565611SJeremy L Thompson   CeedScalar       y  = x / (2. + x);
48c8565611SJeremy L Thompson   const CeedScalar y2 = y * y;
49c8565611SJeremy L Thompson   sum += y;
50c8565611SJeremy L Thompson   y *= y2;
51c8565611SJeremy L Thompson   sum += y / 3;
52c8565611SJeremy L Thompson   y *= y2;
53c8565611SJeremy L Thompson   sum += y / 5;
54c8565611SJeremy L Thompson   y *= y2;
55c8565611SJeremy L Thompson   sum += y / 7;
56c8565611SJeremy L Thompson   return 2 * sum;
57c8565611SJeremy L Thompson }
58c8565611SJeremy L Thompson #endif
59c8565611SJeremy L Thompson 
60c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
61c8565611SJeremy L Thompson // Compute det F - 1
62c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
63c8565611SJeremy L Thompson #ifndef DETJM1
64c8565611SJeremy L Thompson #define DETJM1
computeJM1(const CeedScalar grad_u[3][3])65c8565611SJeremy L Thompson CEED_QFUNCTION_HELPER CeedScalar computeJM1(const CeedScalar grad_u[3][3]) {
66c8565611SJeremy L Thompson   return grad_u[0][0] * (grad_u[1][1] * grad_u[2][2] - grad_u[1][2] * grad_u[2][1]) +
67c8565611SJeremy L Thompson          grad_u[0][1] * (grad_u[1][2] * grad_u[2][0] - grad_u[1][0] * grad_u[2][2]) +
68c8565611SJeremy L Thompson          grad_u[0][2] * (grad_u[1][0] * grad_u[2][1] - grad_u[2][0] * grad_u[1][1]) + grad_u[0][0] + grad_u[1][1] + grad_u[2][2] +
69c8565611SJeremy L Thompson          grad_u[0][0] * grad_u[1][1] + grad_u[0][0] * grad_u[2][2] + grad_u[1][1] * grad_u[2][2] - grad_u[0][1] * grad_u[1][0] -
70c8565611SJeremy L Thompson          grad_u[0][2] * grad_u[2][0] - grad_u[1][2] * grad_u[2][1];
71c8565611SJeremy L Thompson }
72c8565611SJeremy L Thompson #endif
73c8565611SJeremy L Thompson 
74c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
75c8565611SJeremy L Thompson // Compute matrix^(-1), where matrix is symetric, returns array of 6
76c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
77c8565611SJeremy L Thompson #ifndef MatinvSym
78c8565611SJeremy L Thompson #define MatinvSym
computeMatinvSym(const CeedScalar A[3][3],const CeedScalar detA,CeedScalar Ainv[6])79c8565611SJeremy L Thompson CEED_QFUNCTION_HELPER int computeMatinvSym(const CeedScalar A[3][3], const CeedScalar detA, CeedScalar Ainv[6]) {
80c8565611SJeremy L Thompson   // Compute A^(-1) : A-Inverse
81c8565611SJeremy L Thompson   CeedScalar B[6] = {
82c8565611SJeremy L Thompson       A[1][1] * A[2][2] - A[1][2] * A[2][1], /* *NOPAD* */
83c8565611SJeremy L Thompson       A[0][0] * A[2][2] - A[0][2] * A[2][0], /* *NOPAD* */
84c8565611SJeremy L Thompson       A[0][0] * A[1][1] - A[0][1] * A[1][0], /* *NOPAD* */
85c8565611SJeremy L Thompson       A[0][2] * A[1][0] - A[0][0] * A[1][2], /* *NOPAD* */
86c8565611SJeremy L Thompson       A[0][1] * A[1][2] - A[0][2] * A[1][1], /* *NOPAD* */
87c8565611SJeremy L Thompson       A[0][2] * A[2][1] - A[0][1] * A[2][2]  /* *NOPAD* */
88c8565611SJeremy L Thompson   };
89c8565611SJeremy L Thompson   for (CeedInt m = 0; m < 6; m++) Ainv[m] = B[m] / (detA);
90c8565611SJeremy L Thompson 
91c8565611SJeremy L Thompson   return CEED_ERROR_SUCCESS;
92c8565611SJeremy L Thompson }
93c8565611SJeremy L Thompson #endif
94c8565611SJeremy L Thompson 
95c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
96c8565611SJeremy L Thompson // Common computations between FS and dFS
97c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
commonFS(const CeedScalar lambda,const CeedScalar mu,const CeedScalar grad_u[3][3],CeedScalar Swork[6],CeedScalar Cinvwork[6],CeedScalar * logJ)98c8565611SJeremy L Thompson CEED_QFUNCTION_HELPER int commonFS(const CeedScalar lambda, const CeedScalar mu, const CeedScalar grad_u[3][3], CeedScalar Swork[6],
99c8565611SJeremy L Thompson                                    CeedScalar Cinvwork[6], CeedScalar *logJ) {
100c8565611SJeremy L Thompson   // E - Green-Lagrange strain tensor
101c8565611SJeremy L Thompson   //     E = 1/2 (grad_u + grad_u^T + grad_u^T*grad_u)
102c8565611SJeremy L Thompson   const CeedInt indj[6] = {0, 1, 2, 1, 0, 0}, indk[6] = {0, 1, 2, 2, 2, 1};
103c8565611SJeremy L Thompson   CeedScalar    E2work[6];
104c8565611SJeremy L Thompson   for (CeedInt m = 0; m < 6; m++) {
105c8565611SJeremy L Thompson     E2work[m] = grad_u[indj[m]][indk[m]] + grad_u[indk[m]][indj[m]];
106c8565611SJeremy L Thompson     for (CeedInt n = 0; n < 3; n++) E2work[m] += grad_u[n][indj[m]] * grad_u[n][indk[m]];
107c8565611SJeremy L Thompson   }
108c8565611SJeremy L Thompson   CeedScalar E2[3][3] = {
109c8565611SJeremy L Thompson       {E2work[0], E2work[5], E2work[4]},
110c8565611SJeremy L Thompson       {E2work[5], E2work[1], E2work[3]},
111c8565611SJeremy L Thompson       {E2work[4], E2work[3], E2work[2]}
112c8565611SJeremy L Thompson   };
113c8565611SJeremy L Thompson   // J-1
114c8565611SJeremy L Thompson   const CeedScalar Jm1 = computeJM1(grad_u);
115c8565611SJeremy L Thompson 
116c8565611SJeremy L Thompson   // C : right Cauchy-Green tensor
117c8565611SJeremy L Thompson   // C = I + 2E
118c8565611SJeremy L Thompson   const CeedScalar C[3][3] = {
119c8565611SJeremy L Thompson       {1 + E2[0][0], E2[0][1],     E2[0][2]    },
120c8565611SJeremy L Thompson       {E2[0][1],     1 + E2[1][1], E2[1][2]    },
121c8565611SJeremy L Thompson       {E2[0][2],     E2[1][2],     1 + E2[2][2]}
122c8565611SJeremy L Thompson   };
123c8565611SJeremy L Thompson 
124c8565611SJeremy L Thompson   // Compute C^(-1) : C-Inverse
125c8565611SJeremy L Thompson   const CeedScalar detC = (Jm1 + 1.) * (Jm1 + 1.);
126c8565611SJeremy L Thompson   computeMatinvSym(C, detC, Cinvwork);
127c8565611SJeremy L Thompson 
128c8565611SJeremy L Thompson   const CeedScalar C_inv[3][3] = {
129c8565611SJeremy L Thompson       {Cinvwork[0], Cinvwork[5], Cinvwork[4]},
130c8565611SJeremy L Thompson       {Cinvwork[5], Cinvwork[1], Cinvwork[3]},
131c8565611SJeremy L Thompson       {Cinvwork[4], Cinvwork[3], Cinvwork[2]}
132c8565611SJeremy L Thompson   };
133c8565611SJeremy L Thompson 
134c8565611SJeremy L Thompson   // Compute the Second Piola-Kirchhoff (S)
135c8565611SJeremy L Thompson   *logJ = log1p_series_shifted(Jm1);
136c8565611SJeremy L Thompson   for (CeedInt m = 0; m < 6; m++) {
137c8565611SJeremy L Thompson     Swork[m] = (lambda * (*logJ)) * Cinvwork[m];
138c8565611SJeremy L Thompson     for (CeedInt n = 0; n < 3; n++) Swork[m] += mu * C_inv[indj[m]][n] * E2[n][indk[m]];
139c8565611SJeremy L Thompson   }
140c8565611SJeremy L Thompson 
141c8565611SJeremy L Thompson   return CEED_ERROR_SUCCESS;
142c8565611SJeremy L Thompson }
143c8565611SJeremy L Thompson 
144c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
145c8565611SJeremy L Thompson // Residual evaluation for hyperelasticity, finite strain
146c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
ElasFSResidual_NH(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)147c8565611SJeremy L Thompson CEED_QFUNCTION(ElasFSResidual_NH)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
148c8565611SJeremy L Thompson   // Inputs
149c8565611SJeremy L Thompson   const CeedScalar(*ug)[3][CEED_Q_VLA] = (const CeedScalar(*)[3][CEED_Q_VLA])in[0], (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[1];
150c8565611SJeremy L Thompson 
151c8565611SJeremy L Thompson   // Outputs
152c8565611SJeremy L Thompson   CeedScalar(*dvdX)[3][CEED_Q_VLA] = (CeedScalar(*)[3][CEED_Q_VLA])out[0];
153c8565611SJeremy L Thompson   // Store grad_u for HyperFSdF (Jacobian of HyperFSF)
154c8565611SJeremy L Thompson   CeedScalar(*grad_u)[3][CEED_Q_VLA] = (CeedScalar(*)[3][CEED_Q_VLA])out[1];
155c8565611SJeremy L Thompson 
156c8565611SJeremy L Thompson   // Context
157c8565611SJeremy L Thompson   const Physics    context = (Physics)ctx;
158c8565611SJeremy L Thompson   const CeedScalar E       = context->E;
159c8565611SJeremy L Thompson   const CeedScalar nu      = context->nu;
160c8565611SJeremy L Thompson   const CeedScalar TwoMu   = E / (1 + nu);
161c8565611SJeremy L Thompson   const CeedScalar mu      = TwoMu / 2;
162c8565611SJeremy L Thompson   const CeedScalar Kbulk   = E / (3 * (1 - 2 * nu));  // Bulk Modulus
163c8565611SJeremy L Thompson   const CeedScalar lambda  = (3 * Kbulk - TwoMu) / 3;
164c8565611SJeremy L Thompson 
165c8565611SJeremy L Thompson   // Formulation Terminology:
166c8565611SJeremy L Thompson   //  I3    : 3x3 Identity matrix
167c8565611SJeremy L Thompson   //  C     : right Cauchy-Green tensor
168c8565611SJeremy L Thompson   //  C_inv : inverse of C
169c8565611SJeremy L Thompson   //  F     : deformation gradient
170c8565611SJeremy L Thompson   //  S     : 2nd Piola-Kirchhoff (in current config)
171c8565611SJeremy L Thompson   //  P     : 1st Piola-Kirchhoff (in referential config)
172c8565611SJeremy L Thompson   // Formulation:
173c8565611SJeremy L Thompson   //  F =  I3 + grad_ue
174c8565611SJeremy L Thompson   //  J = det(F)
175c8565611SJeremy L Thompson   //  C = F(^T)*F
176c8565611SJeremy L Thompson   //  S = mu*I3 + (lambda*log(J)-mu)*C_inv;
177c8565611SJeremy L Thompson   //  P = F*S
178c8565611SJeremy L Thompson 
179c8565611SJeremy L Thompson   // Quadrature Point Loop
180c8565611SJeremy L Thompson   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
181c8565611SJeremy L Thompson     // Read spatial derivatives of u
182c8565611SJeremy L Thompson     const CeedScalar du[3][3] = {
183c8565611SJeremy L Thompson         {ug[0][0][i], ug[1][0][i], ug[2][0][i]},
184c8565611SJeremy L Thompson         {ug[0][1][i], ug[1][1][i], ug[2][1][i]},
185c8565611SJeremy L Thompson         {ug[0][2][i], ug[1][2][i], ug[2][2][i]}
186c8565611SJeremy L Thompson     };
187c8565611SJeremy L Thompson     // -- Qdata
188c8565611SJeremy L Thompson     const CeedScalar wdetJ      = q_data[0][i];
189c8565611SJeremy L Thompson     const CeedScalar dXdx[3][3] = {
190c8565611SJeremy L Thompson         {q_data[1][i], q_data[2][i], q_data[3][i]},
191c8565611SJeremy L Thompson         {q_data[4][i], q_data[5][i], q_data[6][i]},
192c8565611SJeremy L Thompson         {q_data[7][i], q_data[8][i], q_data[9][i]}
193c8565611SJeremy L Thompson     };
194c8565611SJeremy L Thompson 
195c8565611SJeremy L Thompson     // Compute grad_u
196c8565611SJeremy L Thompson     //   dXdx = (dx/dX)^(-1)
197c8565611SJeremy L Thompson     // Apply dXdx to du = grad_u
198c8565611SJeremy L Thompson     for (CeedInt j = 0; j < 3; j++) {    // Component
199c8565611SJeremy L Thompson       for (CeedInt k = 0; k < 3; k++) {  // Derivative
200c8565611SJeremy L Thompson         grad_u[j][k][i] = 0;
201c8565611SJeremy L Thompson         for (CeedInt m = 0; m < 3; m++) grad_u[j][k][i] += dXdx[m][k] * du[j][m];
202c8565611SJeremy L Thompson       }
203c8565611SJeremy L Thompson     }
204c8565611SJeremy L Thompson 
205c8565611SJeremy L Thompson     // I3 : 3x3 Identity matrix
206c8565611SJeremy L Thompson     // Compute The Deformation Gradient : F = I3 + grad_u
207c8565611SJeremy L Thompson     const CeedScalar F[3][3] = {
208c8565611SJeremy L Thompson         {grad_u[0][0][i] + 1, grad_u[0][1][i],     grad_u[0][2][i]    },
209c8565611SJeremy L Thompson         {grad_u[1][0][i],     grad_u[1][1][i] + 1, grad_u[1][2][i]    },
210c8565611SJeremy L Thompson         {grad_u[2][0][i],     grad_u[2][1][i],     grad_u[2][2][i] + 1}
211c8565611SJeremy L Thompson     };
212c8565611SJeremy L Thompson 
213c8565611SJeremy L Thompson     // Common components of finite strain calculations
214c8565611SJeremy L Thompson     CeedScalar       Swork[6], Cinvwork[6], logJ;
215c8565611SJeremy L Thompson     const CeedScalar tempgradu[3][3] = {
216c8565611SJeremy L Thompson         {grad_u[0][0][i], grad_u[0][1][i], grad_u[0][2][i]},
217c8565611SJeremy L Thompson         {grad_u[1][0][i], grad_u[1][1][i], grad_u[1][2][i]},
218c8565611SJeremy L Thompson         {grad_u[2][0][i], grad_u[2][1][i], grad_u[2][2][i]}
219c8565611SJeremy L Thompson     };
220c8565611SJeremy L Thompson     commonFS(lambda, mu, tempgradu, Swork, Cinvwork, &logJ);
221c8565611SJeremy L Thompson 
222c8565611SJeremy L Thompson     // Second Piola-Kirchhoff (S)
223c8565611SJeremy L Thompson     const CeedScalar S[3][3] = {
224c8565611SJeremy L Thompson         {Swork[0], Swork[5], Swork[4]},
225c8565611SJeremy L Thompson         {Swork[5], Swork[1], Swork[3]},
226c8565611SJeremy L Thompson         {Swork[4], Swork[3], Swork[2]}
227c8565611SJeremy L Thompson     };
228c8565611SJeremy L Thompson 
229c8565611SJeremy L Thompson     // Compute the First Piola-Kirchhoff : P = F*S
230c8565611SJeremy L Thompson     CeedScalar P[3][3];
231c8565611SJeremy L Thompson     for (CeedInt j = 0; j < 3; j++) {
232c8565611SJeremy L Thompson       for (CeedInt k = 0; k < 3; k++) {
233c8565611SJeremy L Thompson         P[j][k] = 0;
234c8565611SJeremy L Thompson         for (CeedInt m = 0; m < 3; m++) P[j][k] += F[j][m] * S[m][k];
235c8565611SJeremy L Thompson       }
236c8565611SJeremy L Thompson     }
237c8565611SJeremy L Thompson 
238c8565611SJeremy L Thompson     // Apply dXdx^T and weight to P (First Piola-Kirchhoff)
239c8565611SJeremy L Thompson     for (CeedInt j = 0; j < 3; j++) {    // Component
240c8565611SJeremy L Thompson       for (CeedInt k = 0; k < 3; k++) {  // Derivative
241c8565611SJeremy L Thompson         dvdX[k][j][i] = 0;
242c8565611SJeremy L Thompson         for (CeedInt m = 0; m < 3; m++) dvdX[k][j][i] += dXdx[k][m] * P[j][m] * wdetJ;
243c8565611SJeremy L Thompson       }
244c8565611SJeremy L Thompson     }
245c8565611SJeremy L Thompson   }  // End of Quadrature Point Loop
246c8565611SJeremy L Thompson 
247c8565611SJeremy L Thompson   return CEED_ERROR_SUCCESS;
248c8565611SJeremy L Thompson }
249c8565611SJeremy L Thompson 
250c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
251c8565611SJeremy L Thompson // Jacobian evaluation for hyperelasticity, finite strain
252c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
ElasFSJacobian_NH(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)253c8565611SJeremy L Thompson CEED_QFUNCTION(ElasFSJacobian_NH)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
254c8565611SJeremy L Thompson   // Inputs
255c8565611SJeremy L Thompson   const CeedScalar(*deltaug)[3][CEED_Q_VLA] = (const CeedScalar(*)[3][CEED_Q_VLA])in[0],
256c8565611SJeremy L Thompson         (*q_data)[CEED_Q_VLA]               = (const CeedScalar(*)[CEED_Q_VLA])in[1];
257c8565611SJeremy L Thompson   // grad_u is used for hyperelasticity (non-linear)
258c8565611SJeremy L Thompson   const CeedScalar(*grad_u)[3][CEED_Q_VLA] = (const CeedScalar(*)[3][CEED_Q_VLA])in[2];
259c8565611SJeremy L Thompson 
260c8565611SJeremy L Thompson   // Outputs
261c8565611SJeremy L Thompson   CeedScalar(*deltadvdX)[3][CEED_Q_VLA] = (CeedScalar(*)[3][CEED_Q_VLA])out[0];
262c8565611SJeremy L Thompson 
263c8565611SJeremy L Thompson   // Context
264c8565611SJeremy L Thompson   const Physics    context = (Physics)ctx;
265c8565611SJeremy L Thompson   const CeedScalar E       = context->E;
266c8565611SJeremy L Thompson   const CeedScalar nu      = context->nu;
267c8565611SJeremy L Thompson 
268c8565611SJeremy L Thompson   // Constants
269c8565611SJeremy L Thompson   const CeedScalar TwoMu  = E / (1 + nu);
270c8565611SJeremy L Thompson   const CeedScalar mu     = TwoMu / 2;
271c8565611SJeremy L Thompson   const CeedScalar Kbulk  = E / (3 * (1 - 2 * nu));  // Bulk Modulus
272c8565611SJeremy L Thompson   const CeedScalar lambda = (3 * Kbulk - TwoMu) / 3;
273c8565611SJeremy L Thompson 
274c8565611SJeremy L Thompson   // Quadrature Point Loop
275c8565611SJeremy L Thompson   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
276c8565611SJeremy L Thompson     // Read spatial derivatives of delta_u
277c8565611SJeremy L Thompson     const CeedScalar deltadu[3][3] = {
278c8565611SJeremy L Thompson         {deltaug[0][0][i], deltaug[1][0][i], deltaug[2][0][i]},
279c8565611SJeremy L Thompson         {deltaug[0][1][i], deltaug[1][1][i], deltaug[2][1][i]},
280c8565611SJeremy L Thompson         {deltaug[0][2][i], deltaug[1][2][i], deltaug[2][2][i]}
281c8565611SJeremy L Thompson     };
282c8565611SJeremy L Thompson     // -- Qdata
283c8565611SJeremy L Thompson     const CeedScalar wdetJ      = q_data[0][i];
284c8565611SJeremy L Thompson     const CeedScalar dXdx[3][3] = {
285c8565611SJeremy L Thompson         {q_data[1][i], q_data[2][i], q_data[3][i]},
286c8565611SJeremy L Thompson         {q_data[4][i], q_data[5][i], q_data[6][i]},
287c8565611SJeremy L Thompson         {q_data[7][i], q_data[8][i], q_data[9][i]}
288c8565611SJeremy L Thompson     };
289c8565611SJeremy L Thompson 
290c8565611SJeremy L Thompson     // Compute graddeltau
291c8565611SJeremy L Thompson     //   dXdx = (dx/dX)^(-1)
292c8565611SJeremy L Thompson     // Apply dXdx to deltadu = graddelta
293c8565611SJeremy L Thompson     CeedScalar graddeltau[3][3];
294c8565611SJeremy L Thompson     for (CeedInt j = 0; j < 3; j++) {    // Component
295c8565611SJeremy L Thompson       for (CeedInt k = 0; k < 3; k++) {  // Derivative
296c8565611SJeremy L Thompson         graddeltau[j][k] = 0;
297c8565611SJeremy L Thompson         for (CeedInt m = 0; m < 3; m++) graddeltau[j][k] += dXdx[m][k] * deltadu[j][m];
298c8565611SJeremy L Thompson       }
299c8565611SJeremy L Thompson     }
300c8565611SJeremy L Thompson 
301c8565611SJeremy L Thompson     // I3 : 3x3 Identity matrix
302c8565611SJeremy L Thompson     // Deformation Gradient : F = I3 + grad_u
303c8565611SJeremy L Thompson     const CeedScalar F[3][3] = {
304c8565611SJeremy L Thompson         {grad_u[0][0][i] + 1, grad_u[0][1][i],     grad_u[0][2][i]    },
305c8565611SJeremy L Thompson         {grad_u[1][0][i],     grad_u[1][1][i] + 1, grad_u[1][2][i]    },
306c8565611SJeremy L Thompson         {grad_u[2][0][i],     grad_u[2][1][i],     grad_u[2][2][i] + 1}
307c8565611SJeremy L Thompson     };
308c8565611SJeremy L Thompson 
309c8565611SJeremy L Thompson     // Common components of finite strain calculations
310c8565611SJeremy L Thompson     CeedScalar       Swork[6], Cinvwork[6], logJ;
311c8565611SJeremy L Thompson     const CeedScalar tempgradu[3][3] = {
312c8565611SJeremy L Thompson         {grad_u[0][0][i], grad_u[0][1][i], grad_u[0][2][i]},
313c8565611SJeremy L Thompson         {grad_u[1][0][i], grad_u[1][1][i], grad_u[1][2][i]},
314c8565611SJeremy L Thompson         {grad_u[2][0][i], grad_u[2][1][i], grad_u[2][2][i]}
315c8565611SJeremy L Thompson     };
316c8565611SJeremy L Thompson     commonFS(lambda, mu, tempgradu, Swork, Cinvwork, &logJ);
317c8565611SJeremy L Thompson 
318c8565611SJeremy L Thompson     // deltaE - Green-Lagrange strain tensor
319c8565611SJeremy L Thompson     const CeedInt indj[6] = {0, 1, 2, 1, 0, 0}, indk[6] = {0, 1, 2, 2, 2, 1};
320c8565611SJeremy L Thompson     CeedScalar    deltaEwork[6];
321c8565611SJeremy L Thompson     for (CeedInt m = 0; m < 6; m++) {
322c8565611SJeremy L Thompson       deltaEwork[m] = 0;
323c8565611SJeremy L Thompson       for (CeedInt n = 0; n < 3; n++) deltaEwork[m] += (graddeltau[n][indj[m]] * F[n][indk[m]] + F[n][indj[m]] * graddeltau[n][indk[m]]) / 2.;
324c8565611SJeremy L Thompson     }
325c8565611SJeremy L Thompson     CeedScalar deltaE[3][3] = {
326c8565611SJeremy L Thompson         {deltaEwork[0], deltaEwork[5], deltaEwork[4]},
327c8565611SJeremy L Thompson         {deltaEwork[5], deltaEwork[1], deltaEwork[3]},
328c8565611SJeremy L Thompson         {deltaEwork[4], deltaEwork[3], deltaEwork[2]}
329c8565611SJeremy L Thompson     };
330c8565611SJeremy L Thompson 
331c8565611SJeremy L Thompson     // C : right Cauchy-Green tensor
332c8565611SJeremy L Thompson     // C^(-1) : C-Inverse
333c8565611SJeremy L Thompson     const CeedScalar C_inv[3][3] = {
334c8565611SJeremy L Thompson         {Cinvwork[0], Cinvwork[5], Cinvwork[4]},
335c8565611SJeremy L Thompson         {Cinvwork[5], Cinvwork[1], Cinvwork[3]},
336c8565611SJeremy L Thompson         {Cinvwork[4], Cinvwork[3], Cinvwork[2]}
337c8565611SJeremy L Thompson     };
338c8565611SJeremy L Thompson 
339c8565611SJeremy L Thompson     // Second Piola-Kirchhoff (S)
340c8565611SJeremy L Thompson     const CeedScalar S[3][3] = {
341c8565611SJeremy L Thompson         {Swork[0], Swork[5], Swork[4]},
342c8565611SJeremy L Thompson         {Swork[5], Swork[1], Swork[3]},
343c8565611SJeremy L Thompson         {Swork[4], Swork[3], Swork[2]}
344c8565611SJeremy L Thompson     };
345c8565611SJeremy L Thompson 
346c8565611SJeremy L Thompson     // deltaS = dSdE:deltaE
347c8565611SJeremy L Thompson     //      = lambda(C_inv:deltaE)C_inv + 2(mu-lambda*log(J))C_inv*deltaE*C_inv
348c8565611SJeremy L Thompson     // -- C_inv:deltaE
349c8565611SJeremy L Thompson     CeedScalar Cinv_contract_E = 0;
350c8565611SJeremy L Thompson     for (CeedInt j = 0; j < 3; j++) {
351c8565611SJeremy L Thompson       for (CeedInt k = 0; k < 3; k++) Cinv_contract_E += C_inv[j][k] * deltaE[j][k];
352c8565611SJeremy L Thompson     }
353c8565611SJeremy L Thompson     // -- deltaE*C_inv
354c8565611SJeremy L Thompson     CeedScalar deltaECinv[3][3];
355c8565611SJeremy L Thompson     for (CeedInt j = 0; j < 3; j++) {
356c8565611SJeremy L Thompson       for (CeedInt k = 0; k < 3; k++) {
357c8565611SJeremy L Thompson         deltaECinv[j][k] = 0;
358c8565611SJeremy L Thompson         for (CeedInt m = 0; m < 3; m++) deltaECinv[j][k] += deltaE[j][m] * C_inv[m][k];
359c8565611SJeremy L Thompson       }
360c8565611SJeremy L Thompson     }
361c8565611SJeremy L Thompson     // -- intermediate deltaS = C_inv*deltaE*C_inv
362c8565611SJeremy L Thompson     CeedScalar deltaS[3][3];
363c8565611SJeremy L Thompson     for (CeedInt j = 0; j < 3; j++) {
364c8565611SJeremy L Thompson       for (CeedInt k = 0; k < 3; k++) {
365c8565611SJeremy L Thompson         deltaS[j][k] = 0;
366c8565611SJeremy L Thompson         for (CeedInt m = 0; m < 3; m++) deltaS[j][k] += C_inv[j][m] * deltaECinv[m][k];
367c8565611SJeremy L Thompson       }
368c8565611SJeremy L Thompson     }
369c8565611SJeremy L Thompson     // -- deltaS = lambda(C_inv:deltaE)C_inv - 2(lambda*log(J)-mu)*(intermediate)
370c8565611SJeremy L Thompson     for (CeedInt j = 0; j < 3; j++) {
371c8565611SJeremy L Thompson       for (CeedInt k = 0; k < 3; k++) deltaS[j][k] = lambda * Cinv_contract_E * C_inv[j][k] - 2. * (lambda * logJ - mu) * deltaS[j][k];
372c8565611SJeremy L Thompson     }
373c8565611SJeremy L Thompson 
374c8565611SJeremy L Thompson     // deltaP = dPdF:deltaF = deltaF*S + F*deltaS
375c8565611SJeremy L Thompson     CeedScalar deltaP[3][3];
376c8565611SJeremy L Thompson     for (CeedInt j = 0; j < 3; j++) {
377c8565611SJeremy L Thompson       for (CeedInt k = 0; k < 3; k++) {
378c8565611SJeremy L Thompson         deltaP[j][k] = 0;
379c8565611SJeremy L Thompson         for (CeedInt m = 0; m < 3; m++) deltaP[j][k] += graddeltau[j][m] * S[m][k] + F[j][m] * deltaS[m][k];
380c8565611SJeremy L Thompson       }
381c8565611SJeremy L Thompson     }
382c8565611SJeremy L Thompson 
383c8565611SJeremy L Thompson     // Apply dXdx^T and weight
384c8565611SJeremy L Thompson     for (CeedInt j = 0; j < 3; j++) {    // Component
385c8565611SJeremy L Thompson       for (CeedInt k = 0; k < 3; k++) {  // Derivative
386c8565611SJeremy L Thompson         deltadvdX[k][j][i] = 0;
387c8565611SJeremy L Thompson         for (CeedInt m = 0; m < 3; m++) deltadvdX[k][j][i] += dXdx[k][m] * deltaP[j][m] * wdetJ;
388c8565611SJeremy L Thompson       }
389c8565611SJeremy L Thompson     }
390c8565611SJeremy L Thompson   }  // End of Quadrature Point Loop
391c8565611SJeremy L Thompson 
392c8565611SJeremy L Thompson   return CEED_ERROR_SUCCESS;
393c8565611SJeremy L Thompson }
394c8565611SJeremy L Thompson 
395c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
396c8565611SJeremy L Thompson // Strain energy computation for hyperelasticity, finite strain
397c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
ElasFSEnergy_NH(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)398c8565611SJeremy L Thompson CEED_QFUNCTION(ElasFSEnergy_NH)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
399c8565611SJeremy L Thompson   // Inputs
400c8565611SJeremy L Thompson   const CeedScalar(*ug)[3][CEED_Q_VLA] = (const CeedScalar(*)[3][CEED_Q_VLA])in[0], (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[1];
401c8565611SJeremy L Thompson 
402c8565611SJeremy L Thompson   // Outputs
403c8565611SJeremy L Thompson   CeedScalar(*energy) = (CeedScalar(*))out[0];
404c8565611SJeremy L Thompson 
405c8565611SJeremy L Thompson   // Context
406c8565611SJeremy L Thompson   const Physics    context = (Physics)ctx;
407c8565611SJeremy L Thompson   const CeedScalar E       = context->E;
408c8565611SJeremy L Thompson   const CeedScalar nu      = context->nu;
409c8565611SJeremy L Thompson   const CeedScalar TwoMu   = E / (1 + nu);
410c8565611SJeremy L Thompson   const CeedScalar mu      = TwoMu / 2;
411c8565611SJeremy L Thompson   const CeedScalar Kbulk   = E / (3 * (1 - 2 * nu));  // Bulk Modulus
412c8565611SJeremy L Thompson   const CeedScalar lambda  = (3 * Kbulk - TwoMu) / 3;
413c8565611SJeremy L Thompson 
414c8565611SJeremy L Thompson   // Quadrature Point Loop
415c8565611SJeremy L Thompson   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
416c8565611SJeremy L Thompson     // Read spatial derivatives of u
417c8565611SJeremy L Thompson     const CeedScalar du[3][3] = {
418c8565611SJeremy L Thompson         {ug[0][0][i], ug[1][0][i], ug[2][0][i]},
419c8565611SJeremy L Thompson         {ug[0][1][i], ug[1][1][i], ug[2][1][i]},
420c8565611SJeremy L Thompson         {ug[0][2][i], ug[1][2][i], ug[2][2][i]}
421c8565611SJeremy L Thompson     };
422c8565611SJeremy L Thompson     // -- Qdata
423c8565611SJeremy L Thompson     const CeedScalar wdetJ      = q_data[0][i];
424c8565611SJeremy L Thompson     const CeedScalar dXdx[3][3] = {
425c8565611SJeremy L Thompson         {q_data[1][i], q_data[2][i], q_data[3][i]},
426c8565611SJeremy L Thompson         {q_data[4][i], q_data[5][i], q_data[6][i]},
427c8565611SJeremy L Thompson         {q_data[7][i], q_data[8][i], q_data[9][i]}
428c8565611SJeremy L Thompson     };
429c8565611SJeremy L Thompson 
430c8565611SJeremy L Thompson     // Compute grad_u
431c8565611SJeremy L Thompson     //   dXdx = (dx/dX)^(-1)
432c8565611SJeremy L Thompson     // Apply dXdx to du = grad_u
433c8565611SJeremy L Thompson     CeedScalar grad_u[3][3];
434c8565611SJeremy L Thompson     for (int j = 0; j < 3; j++) {    // Component
435c8565611SJeremy L Thompson       for (int k = 0; k < 3; k++) {  // Derivative
436c8565611SJeremy L Thompson         grad_u[j][k] = 0;
437c8565611SJeremy L Thompson         for (int m = 0; m < 3; m++) grad_u[j][k] += dXdx[m][k] * du[j][m];
438c8565611SJeremy L Thompson       }
439c8565611SJeremy L Thompson     }
440c8565611SJeremy L Thompson 
441c8565611SJeremy L Thompson     // E - Green-Lagrange strain tensor
442c8565611SJeremy L Thompson     //     E = 1/2 (grad_u + grad_u^T + grad_u^T*grad_u)
443c8565611SJeremy L Thompson     const CeedInt indj[6] = {0, 1, 2, 1, 0, 0}, indk[6] = {0, 1, 2, 2, 2, 1};
444c8565611SJeremy L Thompson     CeedScalar    E2work[6];
445c8565611SJeremy L Thompson     for (CeedInt m = 0; m < 6; m++) {
446c8565611SJeremy L Thompson       E2work[m] = grad_u[indj[m]][indk[m]] + grad_u[indk[m]][indj[m]];
447c8565611SJeremy L Thompson       for (CeedInt n = 0; n < 3; n++) E2work[m] += grad_u[n][indj[m]] * grad_u[n][indk[m]];
448c8565611SJeremy L Thompson     }
449c8565611SJeremy L Thompson     CeedScalar E2[3][3] = {
450c8565611SJeremy L Thompson         {E2work[0], E2work[5], E2work[4]},
451c8565611SJeremy L Thompson         {E2work[5], E2work[1], E2work[3]},
452c8565611SJeremy L Thompson         {E2work[4], E2work[3], E2work[2]}
453c8565611SJeremy L Thompson     };
454c8565611SJeremy L Thompson     const CeedScalar Jm1  = computeJM1(grad_u);
455c8565611SJeremy L Thompson     const CeedScalar logJ = log1p_series_shifted(Jm1);
456c8565611SJeremy L Thompson 
457c8565611SJeremy L Thompson     // Strain energy Phi(E) for compressible Neo-Hookean
458c8565611SJeremy L Thompson     energy[i] = (lambda * logJ * logJ / 2. - mu * logJ + mu * (E2[0][0] + E2[1][1] + E2[2][2]) / 2.) * wdetJ;
459c8565611SJeremy L Thompson 
460c8565611SJeremy L Thompson   }  // End of Quadrature Point Loop
461c8565611SJeremy L Thompson 
462c8565611SJeremy L Thompson   return CEED_ERROR_SUCCESS;
463c8565611SJeremy L Thompson }
464c8565611SJeremy L Thompson 
465c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
466c8565611SJeremy L Thompson // Nodal diagnostic quantities for hyperelasticity, finite strain
467c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
ElasFSDiagnostic_NH(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)468c8565611SJeremy L Thompson CEED_QFUNCTION(ElasFSDiagnostic_NH)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
469c8565611SJeremy L Thompson   // Inputs
470c8565611SJeremy L Thompson   const CeedScalar(*u)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0], (*ug)[3][CEED_Q_VLA] = (const CeedScalar(*)[3][CEED_Q_VLA])in[1],
471c8565611SJeremy L Thompson         (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2];
472c8565611SJeremy L Thompson 
473c8565611SJeremy L Thompson   // Outputs
474c8565611SJeremy L Thompson   CeedScalar(*diagnostic)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
475c8565611SJeremy L Thompson 
476c8565611SJeremy L Thompson   // Context
477c8565611SJeremy L Thompson   const Physics    context = (Physics)ctx;
478c8565611SJeremy L Thompson   const CeedScalar E       = context->E;
479c8565611SJeremy L Thompson   const CeedScalar nu      = context->nu;
480c8565611SJeremy L Thompson   const CeedScalar TwoMu   = E / (1 + nu);
481c8565611SJeremy L Thompson   const CeedScalar mu      = TwoMu / 2;
482c8565611SJeremy L Thompson   const CeedScalar Kbulk   = E / (3 * (1 - 2 * nu));  // Bulk Modulus
483c8565611SJeremy L Thompson   const CeedScalar lambda  = (3 * Kbulk - TwoMu) / 3;
484c8565611SJeremy L Thompson 
485c8565611SJeremy L Thompson   // Quadrature Point Loop
486c8565611SJeremy L Thompson   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
487c8565611SJeremy L Thompson     // Read spatial derivatives of u
488c8565611SJeremy L Thompson     const CeedScalar du[3][3] = {
489c8565611SJeremy L Thompson         {ug[0][0][i], ug[1][0][i], ug[2][0][i]},
490c8565611SJeremy L Thompson         {ug[0][1][i], ug[1][1][i], ug[2][1][i]},
491c8565611SJeremy L Thompson         {ug[0][2][i], ug[1][2][i], ug[2][2][i]}
492c8565611SJeremy L Thompson     };
493c8565611SJeremy L Thompson     // -- Qdata
494c8565611SJeremy L Thompson     const CeedScalar dXdx[3][3] = {
495c8565611SJeremy L Thompson         {q_data[1][i], q_data[2][i], q_data[3][i]},
496c8565611SJeremy L Thompson         {q_data[4][i], q_data[5][i], q_data[6][i]},
497c8565611SJeremy L Thompson         {q_data[7][i], q_data[8][i], q_data[9][i]}
498c8565611SJeremy L Thompson     };
499c8565611SJeremy L Thompson 
500c8565611SJeremy L Thompson     // Compute grad_u
501c8565611SJeremy L Thompson     //   dXdx = (dx/dX)^(-1)
502c8565611SJeremy L Thompson     // Apply dXdx to du = grad_u
503c8565611SJeremy L Thompson     CeedScalar grad_u[3][3];
504c8565611SJeremy L Thompson     for (int j = 0; j < 3; j++) {    // Component
505c8565611SJeremy L Thompson       for (int k = 0; k < 3; k++) {  // Derivative
506c8565611SJeremy L Thompson         grad_u[j][k] = 0;
507c8565611SJeremy L Thompson         for (int m = 0; m < 3; m++) grad_u[j][k] += dXdx[m][k] * du[j][m];
508c8565611SJeremy L Thompson       }
509c8565611SJeremy L Thompson     }
510c8565611SJeremy L Thompson 
511c8565611SJeremy L Thompson     // E - Green-Lagrange strain tensor
512c8565611SJeremy L Thompson     //     E = 1/2 (grad_u + grad_u^T + grad_u^T*grad_u)
513c8565611SJeremy L Thompson     const CeedInt indj[6] = {0, 1, 2, 1, 0, 0}, indk[6] = {0, 1, 2, 2, 2, 1};
514c8565611SJeremy L Thompson     CeedScalar    E2work[6];
515c8565611SJeremy L Thompson     for (CeedInt m = 0; m < 6; m++) {
516c8565611SJeremy L Thompson       E2work[m] = grad_u[indj[m]][indk[m]] + grad_u[indk[m]][indj[m]];
517c8565611SJeremy L Thompson       for (CeedInt n = 0; n < 3; n++) E2work[m] += grad_u[n][indj[m]] * grad_u[n][indk[m]];
518c8565611SJeremy L Thompson     }
519c8565611SJeremy L Thompson     CeedScalar E2[3][3] = {
520c8565611SJeremy L Thompson         {E2work[0], E2work[5], E2work[4]},
521c8565611SJeremy L Thompson         {E2work[5], E2work[1], E2work[3]},
522c8565611SJeremy L Thompson         {E2work[4], E2work[3], E2work[2]}
523c8565611SJeremy L Thompson     };
524c8565611SJeremy L Thompson 
525c8565611SJeremy L Thompson     // Displacement
526c8565611SJeremy L Thompson     diagnostic[0][i] = u[0][i];
527c8565611SJeremy L Thompson     diagnostic[1][i] = u[1][i];
528c8565611SJeremy L Thompson     diagnostic[2][i] = u[2][i];
529c8565611SJeremy L Thompson 
530c8565611SJeremy L Thompson     // Pressure
531c8565611SJeremy L Thompson     const CeedScalar Jm1  = computeJM1(grad_u);
532c8565611SJeremy L Thompson     const CeedScalar logJ = log1p_series_shifted(Jm1);
533c8565611SJeremy L Thompson     diagnostic[3][i]      = -lambda * logJ;
534c8565611SJeremy L Thompson 
535c8565611SJeremy L Thompson     // Stress tensor invariants
536c8565611SJeremy L Thompson     diagnostic[4][i] = (E2[0][0] + E2[1][1] + E2[2][2]) / 2.;
537c8565611SJeremy L Thompson     diagnostic[5][i] = 0.;
538c8565611SJeremy L Thompson     for (CeedInt j = 0; j < 3; j++) {
539c8565611SJeremy L Thompson       for (CeedInt m = 0; m < 3; m++) diagnostic[5][i] += E2[j][m] * E2[m][j] / 4.;
540c8565611SJeremy L Thompson     }
541c8565611SJeremy L Thompson     diagnostic[6][i] = Jm1 + 1.;
542c8565611SJeremy L Thompson 
543c8565611SJeremy L Thompson     // Strain energy
544c8565611SJeremy L Thompson     diagnostic[7][i] = (lambda * logJ * logJ / 2. - mu * logJ + mu * (E2[0][0] + E2[1][1] + E2[2][2]) / 2.);
545c8565611SJeremy L Thompson   }  // End of Quadrature Point Loop
546c8565611SJeremy L Thompson 
547c8565611SJeremy L Thompson   return CEED_ERROR_SUCCESS;
548c8565611SJeremy L Thompson }
549c8565611SJeremy L Thompson // -----------------------------------------------------------------------------
550