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