1c8565611SJeremy L Thompson // Copyright (c) 2017-2024, 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 11*c0b5abf0SJeremy L Thompson #include <ceed/types.h> 12*c0b5abf0SJeremy L Thompson #ifndef CEED_RUNNING_JIT_PASS 13c8565611SJeremy L Thompson #include <math.h> 14*c0b5abf0SJeremy 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 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 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 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 // ----------------------------------------------------------------------------- 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 // ----------------------------------------------------------------------------- 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 // ----------------------------------------------------------------------------- 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 // ----------------------------------------------------------------------------- 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 // ----------------------------------------------------------------------------- 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