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