1 // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3 // 4 // SPDX-License-Identifier: BSD-2-Clause 5 // 6 // This file is part of CEED: http://github.com/ceed 7 8 #ifndef ex2_surface_h 9 #define ex2_surface_h 10 11 #include <ceed.h> 12 13 /// A structure used to pass additional data to f_build_diff 14 struct BuildContext { 15 CeedInt dim, space_dim; 16 }; 17 18 /// libCEED Q-function for building quadrature data for a diffusion operator 19 CEED_QFUNCTION(f_build_diff)(void *ctx, const CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 20 struct BuildContext *bc = (struct BuildContext *)ctx; 21 // in[0] is Jacobians with shape [dim, nc=dim, Q] 22 // in[1] is quadrature weights, size (Q) 23 // 24 // At every quadrature point, compute w/det(J).adj(J).adj(J)^T and store 25 // the symmetric part of the result. 26 const CeedScalar *J = in[0], *w = in[1]; 27 CeedScalar *q_data = out[0]; 28 29 switch (bc->dim + 10 * bc->space_dim) { 30 case 11: 31 CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { q_data[i] = w[i] / J[i]; } // End of Quadrature Point Loop 32 break; 33 case 22: 34 CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 35 // J: 0 2 q_data: 0 2 adj(J): J22 -J12 36 // 1 3 2 1 -J21 J11 37 const CeedScalar J11 = J[i + Q * 0]; 38 const CeedScalar J21 = J[i + Q * 1]; 39 const CeedScalar J12 = J[i + Q * 2]; 40 const CeedScalar J22 = J[i + Q * 3]; 41 const CeedScalar qw = w[i] / (J11 * J22 - J21 * J12); 42 q_data[i + Q * 0] = qw * (J12 * J12 + J22 * J22); 43 q_data[i + Q * 1] = qw * (J11 * J11 + J21 * J21); 44 q_data[i + Q * 2] = -qw * (J11 * J12 + J21 * J22); 45 } // End of Quadrature Point Loop 46 break; 47 case 33: 48 CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 49 // Compute the adjoint 50 CeedScalar A[3][3]; 51 for (CeedInt j = 0; j < 3; j++) 52 for (CeedInt k = 0; k < 3; k++) 53 // Equivalent code with J as a VLA and no mod operations: 54 // A[k][j] = J[j+1][k+1]*J[j+2][k+2] - J[j+1][k+2]*J[j+2][k+1] 55 A[k][j] = J[i + Q * ((j + 1) % 3 + 3 * ((k + 1) % 3))] * J[i + Q * ((j + 2) % 3 + 3 * ((k + 2) % 3))] - 56 J[i + Q * ((j + 1) % 3 + 3 * ((k + 2) % 3))] * J[i + Q * ((j + 2) % 3 + 3 * ((k + 1) % 3))]; 57 58 // Compute quadrature weight / det(J) 59 const CeedScalar qw = w[i] / (J[i + Q * 0] * A[0][0] + J[i + Q * 1] * A[0][1] + J[i + Q * 2] * A[0][2]); 60 61 // Compute geometric factors 62 // Stored in Voigt convention 63 // 0 5 4 64 // 5 1 3 65 // 4 3 2 66 q_data[i + Q * 0] = qw * (A[0][0] * A[0][0] + A[0][1] * A[0][1] + A[0][2] * A[0][2]); 67 q_data[i + Q * 1] = qw * (A[1][0] * A[1][0] + A[1][1] * A[1][1] + A[1][2] * A[1][2]); 68 q_data[i + Q * 2] = qw * (A[2][0] * A[2][0] + A[2][1] * A[2][1] + A[2][2] * A[2][2]); 69 q_data[i + Q * 3] = qw * (A[1][0] * A[2][0] + A[1][1] * A[2][1] + A[1][2] * A[2][2]); 70 q_data[i + Q * 4] = qw * (A[0][0] * A[2][0] + A[0][1] * A[2][1] + A[0][2] * A[2][2]); 71 q_data[i + Q * 5] = qw * (A[0][0] * A[1][0] + A[0][1] * A[1][1] + A[0][2] * A[1][2]); 72 } // End of Quadrature Point Loop 73 break; 74 } 75 return 0; 76 } 77 78 /// libCEED Q-function for applying a diff operator 79 CEED_QFUNCTION(f_apply_diff)(void *ctx, const CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 80 struct BuildContext *bc = (struct BuildContext *)ctx; 81 // in[0], out[0] have shape [dim, nc=1, Q] 82 const CeedScalar *ug = in[0], *q_data = in[1]; 83 CeedScalar *vg = out[0]; 84 85 switch (bc->dim) { 86 case 1: 87 CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { vg[i] = ug[i] * q_data[i]; } // End of Quadrature Point Loop 88 break; 89 case 2: 90 CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 91 // Read spatial derivatives of u 92 const CeedScalar du[2] = {ug[i + Q * 0], ug[i + Q * 1]}; 93 94 // Read q_data (dXdxdXdx_T symmetric matrix) 95 // Stored in Voigt convention 96 // 0 2 97 // 2 1 98 const CeedScalar dXdxdXdx_T[2][2] = { 99 {q_data[i + 0 * Q], q_data[i + 2 * Q]}, 100 {q_data[i + 2 * Q], q_data[i + 1 * Q]} 101 }; 102 // j = direction of vg 103 for (int j = 0; j < 2; j++) vg[i + j * Q] = (du[0] * dXdxdXdx_T[0][j] + du[1] * dXdxdXdx_T[1][j]); 104 } // End of Quadrature Point Loop 105 break; 106 case 3: 107 CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 108 // Read spatial derivatives of u 109 const CeedScalar du[3] = {ug[i + Q * 0], ug[i + Q * 1], ug[i + Q * 2]}; 110 111 // Read q_data (dXdxdXdx_T symmetric matrix) 112 // Stored in Voigt convention 113 // 0 5 4 114 // 5 1 3 115 // 4 3 2 116 const CeedScalar dXdxdXdx_T[3][3] = { 117 {q_data[i + 0 * Q], q_data[i + 5 * Q], q_data[i + 4 * Q]}, 118 {q_data[i + 5 * Q], q_data[i + 1 * Q], q_data[i + 3 * Q]}, 119 {q_data[i + 4 * Q], q_data[i + 3 * Q], q_data[i + 2 * Q]} 120 }; 121 // j = direction of vg 122 for (int j = 0; j < 3; j++) vg[i + j * Q] = (du[0] * dXdxdXdx_T[0][j] + du[1] * dXdxdXdx_T[1][j] + du[2] * dXdxdXdx_T[2][j]); 123 } // End of Quadrature Point Loop 124 break; 125 } 126 return 0; 127 } 128 129 #endif // ex2_surface_h 130