xref: /libCEED/tests/t570-operator.c (revision 7e2def383022a8dc258779d80e0e212f0ebe40f9)
1*7e2def38SSebastian Grimberg /// @file
2*7e2def38SSebastian Grimberg /// Test assembly of H(div) mass matrix operator diagonal
3*7e2def38SSebastian Grimberg /// \test Test assembly of H(div) mass matrix operator diagonal
4*7e2def38SSebastian Grimberg #include <ceed.h>
5*7e2def38SSebastian Grimberg #include <math.h>
6*7e2def38SSebastian Grimberg #include <stdio.h>
7*7e2def38SSebastian Grimberg #include <stdlib.h>
8*7e2def38SSebastian Grimberg 
9*7e2def38SSebastian Grimberg #include "t330-basis.h"
10*7e2def38SSebastian Grimberg #include "t570-operator.h"
11*7e2def38SSebastian Grimberg 
12*7e2def38SSebastian Grimberg int main(int argc, char **argv) {
13*7e2def38SSebastian Grimberg   Ceed                ceed;
14*7e2def38SSebastian Grimberg   CeedElemRestriction elem_restriction_x, elem_restriction_u;
15*7e2def38SSebastian Grimberg   CeedBasis           basis_x, basis_u;
16*7e2def38SSebastian Grimberg   CeedQFunction       qf_mass;
17*7e2def38SSebastian Grimberg   CeedOperator        op_mass;
18*7e2def38SSebastian Grimberg   CeedVector          x, assembled, u, v;
19*7e2def38SSebastian Grimberg   CeedInt             dim = 2, p = 8, q = 3, px = 2;
20*7e2def38SSebastian Grimberg   CeedInt             n_x = 1, n_y = 1;  // Currently only implemented for single element
21*7e2def38SSebastian Grimberg   CeedInt             row, column, offset;
22*7e2def38SSebastian Grimberg   CeedInt             num_elem = n_x * n_y, num_faces = (n_x + 1) * n_y + (n_y + 1) * n_x;
23*7e2def38SSebastian Grimberg   CeedInt             num_dofs_x = (n_x + 1) * (n_y + 1), num_dofs_u = num_faces * 2, num_qpts = q * q;
24*7e2def38SSebastian Grimberg   CeedInt             ind_x[num_elem * px * px], ind_u[num_elem * p];
25*7e2def38SSebastian Grimberg   bool                orient_u[num_elem * p];
26*7e2def38SSebastian Grimberg   CeedScalar          assembled_true[num_dofs_u];
27*7e2def38SSebastian Grimberg   CeedScalar          q_ref[dim * num_qpts], q_weight[num_qpts];
28*7e2def38SSebastian Grimberg   CeedScalar          interp[dim * p * num_qpts], div[p * num_qpts];
29*7e2def38SSebastian Grimberg 
30*7e2def38SSebastian Grimberg   CeedInit(argv[1], &ceed);
31*7e2def38SSebastian Grimberg 
32*7e2def38SSebastian Grimberg   // Vectors
33*7e2def38SSebastian Grimberg   CeedVectorCreate(ceed, dim * num_dofs_x, &x);
34*7e2def38SSebastian Grimberg   {
35*7e2def38SSebastian Grimberg     CeedScalar x_array[dim * num_dofs_x];
36*7e2def38SSebastian Grimberg 
37*7e2def38SSebastian Grimberg     for (CeedInt i = 0; i < n_x + 1; i++) {
38*7e2def38SSebastian Grimberg       for (CeedInt j = 0; j < n_y + 1; j++) {
39*7e2def38SSebastian Grimberg         x_array[i + j * (n_x + 1) + 0 * num_dofs_x] = i / (CeedScalar)n_x;
40*7e2def38SSebastian Grimberg         x_array[i + j * (n_x + 1) + 1 * num_dofs_x] = j / (CeedScalar)n_y;
41*7e2def38SSebastian Grimberg       }
42*7e2def38SSebastian Grimberg     }
43*7e2def38SSebastian Grimberg     CeedVectorSetArray(x, CEED_MEM_HOST, CEED_COPY_VALUES, x_array);
44*7e2def38SSebastian Grimberg   }
45*7e2def38SSebastian Grimberg   CeedVectorCreate(ceed, num_dofs_u, &u);
46*7e2def38SSebastian Grimberg   CeedVectorCreate(ceed, num_dofs_u, &v);
47*7e2def38SSebastian Grimberg 
48*7e2def38SSebastian Grimberg   // Restrictions
49*7e2def38SSebastian Grimberg   for (CeedInt i = 0; i < num_elem; i++) {
50*7e2def38SSebastian Grimberg     column = i % n_x;
51*7e2def38SSebastian Grimberg     row    = i / n_x;
52*7e2def38SSebastian Grimberg     offset = column * (px - 1) + row * (n_x + 1) * (px - 1);
53*7e2def38SSebastian Grimberg 
54*7e2def38SSebastian Grimberg     for (CeedInt j = 0; j < px; j++) {
55*7e2def38SSebastian Grimberg       for (CeedInt k = 0; k < px; k++) {
56*7e2def38SSebastian Grimberg         ind_x[px * (px * i + k) + j] = offset + k * (n_x + 1) + j;
57*7e2def38SSebastian Grimberg       }
58*7e2def38SSebastian Grimberg     }
59*7e2def38SSebastian Grimberg   }
60*7e2def38SSebastian Grimberg   bool    orient_u_local[8] = {false, false, false, false, true, true, true, true};
61*7e2def38SSebastian Grimberg   CeedInt ind_u_local[8]    = {0, 1, 6, 7, 2, 3, 4, 5};
62*7e2def38SSebastian Grimberg   for (CeedInt j = 0; j < n_y; j++) {
63*7e2def38SSebastian Grimberg     for (CeedInt i = 0; i < n_x; i++) {
64*7e2def38SSebastian Grimberg       for (CeedInt k = 0; k < p; k++) {
65*7e2def38SSebastian Grimberg         ind_u[k]    = ind_u_local[k];
66*7e2def38SSebastian Grimberg         orient_u[k] = orient_u_local[k];
67*7e2def38SSebastian Grimberg       }
68*7e2def38SSebastian Grimberg     }
69*7e2def38SSebastian Grimberg   }
70*7e2def38SSebastian Grimberg   CeedElemRestrictionCreate(ceed, num_elem, px * px, dim, num_dofs_x, dim * num_dofs_x, CEED_MEM_HOST, CEED_USE_POINTER, ind_x, &elem_restriction_x);
71*7e2def38SSebastian Grimberg   CeedElemRestrictionCreateOriented(ceed, num_elem, p, 1, 1, num_dofs_u, CEED_MEM_HOST, CEED_COPY_VALUES, ind_u, orient_u, &elem_restriction_u);
72*7e2def38SSebastian Grimberg 
73*7e2def38SSebastian Grimberg   // Bases
74*7e2def38SSebastian Grimberg   CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, px, q, CEED_GAUSS, &basis_x);
75*7e2def38SSebastian Grimberg 
76*7e2def38SSebastian Grimberg   BuildHdivQuadrilateral(q, q_ref, q_weight, interp, div, CEED_GAUSS);
77*7e2def38SSebastian Grimberg   CeedBasisCreateHdiv(ceed, CEED_TOPOLOGY_QUAD, 1, p, num_qpts, interp, div, q_ref, q_weight, &basis_u);
78*7e2def38SSebastian Grimberg 
79*7e2def38SSebastian Grimberg   // QFunctions
80*7e2def38SSebastian Grimberg   CeedQFunctionCreateInterior(ceed, 1, mass, mass_loc, &qf_mass);
81*7e2def38SSebastian Grimberg   CeedQFunctionAddInput(qf_mass, "weight", 1, CEED_EVAL_WEIGHT);
82*7e2def38SSebastian Grimberg   CeedQFunctionAddInput(qf_mass, "dx", dim * dim, CEED_EVAL_GRAD);
83*7e2def38SSebastian Grimberg   CeedQFunctionAddInput(qf_mass, "u", dim, CEED_EVAL_INTERP);
84*7e2def38SSebastian Grimberg   CeedQFunctionAddOutput(qf_mass, "v", dim, CEED_EVAL_INTERP);
85*7e2def38SSebastian Grimberg 
86*7e2def38SSebastian Grimberg   // Operators
87*7e2def38SSebastian Grimberg   CeedOperatorCreate(ceed, qf_mass, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, &op_mass);
88*7e2def38SSebastian Grimberg   CeedOperatorSetField(op_mass, "weight", CEED_ELEMRESTRICTION_NONE, basis_x, CEED_VECTOR_NONE);
89*7e2def38SSebastian Grimberg   CeedOperatorSetField(op_mass, "dx", elem_restriction_x, basis_x, x);
90*7e2def38SSebastian Grimberg   CeedOperatorSetField(op_mass, "u", elem_restriction_u, basis_u, CEED_VECTOR_ACTIVE);
91*7e2def38SSebastian Grimberg   CeedOperatorSetField(op_mass, "v", elem_restriction_u, basis_u, CEED_VECTOR_ACTIVE);
92*7e2def38SSebastian Grimberg 
93*7e2def38SSebastian Grimberg   // Assemble diagonal
94*7e2def38SSebastian Grimberg   CeedVectorCreate(ceed, num_dofs_u, &assembled);
95*7e2def38SSebastian Grimberg   CeedOperatorLinearAssembleDiagonal(op_mass, assembled, CEED_REQUEST_IMMEDIATE);
96*7e2def38SSebastian Grimberg 
97*7e2def38SSebastian Grimberg   // Manually assemble diagonal
98*7e2def38SSebastian Grimberg   CeedVectorSetValue(u, 0.0);
99*7e2def38SSebastian Grimberg   for (int i = 0; i < num_dofs_u; i++) {
100*7e2def38SSebastian Grimberg     CeedScalar       *u_array;
101*7e2def38SSebastian Grimberg     const CeedScalar *v_array;
102*7e2def38SSebastian Grimberg 
103*7e2def38SSebastian Grimberg     // Set input
104*7e2def38SSebastian Grimberg     CeedVectorGetArray(u, CEED_MEM_HOST, &u_array);
105*7e2def38SSebastian Grimberg     u_array[i] = 1.0;
106*7e2def38SSebastian Grimberg     if (i) u_array[i - 1] = 0.0;
107*7e2def38SSebastian Grimberg     CeedVectorRestoreArray(u, &u_array);
108*7e2def38SSebastian Grimberg 
109*7e2def38SSebastian Grimberg     // Compute diag entry for DoF i
110*7e2def38SSebastian Grimberg     CeedOperatorApply(op_mass, u, v, CEED_REQUEST_IMMEDIATE);
111*7e2def38SSebastian Grimberg 
112*7e2def38SSebastian Grimberg     // Retrieve entry
113*7e2def38SSebastian Grimberg     CeedVectorGetArrayRead(v, CEED_MEM_HOST, &v_array);
114*7e2def38SSebastian Grimberg     assembled_true[i] = v_array[i];
115*7e2def38SSebastian Grimberg     CeedVectorRestoreArrayRead(v, &v_array);
116*7e2def38SSebastian Grimberg   }
117*7e2def38SSebastian Grimberg 
118*7e2def38SSebastian Grimberg   // Check output
119*7e2def38SSebastian Grimberg   {
120*7e2def38SSebastian Grimberg     const CeedScalar *assembled_array;
121*7e2def38SSebastian Grimberg 
122*7e2def38SSebastian Grimberg     CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembled_array);
123*7e2def38SSebastian Grimberg     for (int i = 0; i < num_dofs_u; i++) {
124*7e2def38SSebastian Grimberg       if (fabs(assembled_array[i] - assembled_true[i]) > 100. * CEED_EPSILON) {
125*7e2def38SSebastian Grimberg         // LCOV_EXCL_START
126*7e2def38SSebastian Grimberg         printf("[%" CeedInt_FMT "] Error in assembly: %f != %f\n", i, assembled_array[i], assembled_true[i]);
127*7e2def38SSebastian Grimberg         // LCOV_EXCL_STOP
128*7e2def38SSebastian Grimberg       }
129*7e2def38SSebastian Grimberg     }
130*7e2def38SSebastian Grimberg     CeedVectorRestoreArrayRead(assembled, &assembled_array);
131*7e2def38SSebastian Grimberg   }
132*7e2def38SSebastian Grimberg 
133*7e2def38SSebastian Grimberg   // Cleanup
134*7e2def38SSebastian Grimberg   CeedVectorDestroy(&x);
135*7e2def38SSebastian Grimberg   CeedVectorDestroy(&assembled);
136*7e2def38SSebastian Grimberg   CeedVectorDestroy(&u);
137*7e2def38SSebastian Grimberg   CeedVectorDestroy(&v);
138*7e2def38SSebastian Grimberg   CeedElemRestrictionDestroy(&elem_restriction_u);
139*7e2def38SSebastian Grimberg   CeedElemRestrictionDestroy(&elem_restriction_x);
140*7e2def38SSebastian Grimberg   CeedBasisDestroy(&basis_u);
141*7e2def38SSebastian Grimberg   CeedBasisDestroy(&basis_x);
142*7e2def38SSebastian Grimberg   CeedQFunctionDestroy(&qf_mass);
143*7e2def38SSebastian Grimberg   CeedOperatorDestroy(&op_mass);
144*7e2def38SSebastian Grimberg   CeedDestroy(&ceed);
145*7e2def38SSebastian Grimberg   return 0;
146*7e2def38SSebastian Grimberg }
147