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