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