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