1*506b1a0cSSebastian Grimberg /// @file
2*506b1a0cSSebastian Grimberg /// Test full assembly of a non-square mass matrix operator (see t553)
3*506b1a0cSSebastian Grimberg /// \test Test full assembly of a non-square mass matrix operator
4*506b1a0cSSebastian Grimberg #include <ceed.h>
5*506b1a0cSSebastian Grimberg #include <math.h>
6*506b1a0cSSebastian Grimberg #include <stdio.h>
7*506b1a0cSSebastian Grimberg #include <stdlib.h>
8*506b1a0cSSebastian Grimberg
main(int argc,char ** argv)9*506b1a0cSSebastian Grimberg int main(int argc, char **argv) {
10*506b1a0cSSebastian Grimberg Ceed ceed;
11*506b1a0cSSebastian Grimberg CeedElemRestriction elem_restriction_x, elem_restriction_q_data, elem_restriction_u_coarse, elem_restriction_u_fine;
12*506b1a0cSSebastian Grimberg CeedBasis basis_x, basis_u_coarse, basis_u_fine;
13*506b1a0cSSebastian Grimberg CeedQFunction qf_setup, qf_mass;
14*506b1a0cSSebastian Grimberg CeedOperator op_setup, op_mass;
15*506b1a0cSSebastian Grimberg CeedVector q_data, x, u, v;
16*506b1a0cSSebastian Grimberg CeedInt num_elem = 15, p_coarse = 3, p_fine = 5, q = 8;
17*506b1a0cSSebastian Grimberg CeedInt num_dofs_x = num_elem + 1, num_dofs_u_coarse = num_elem * (p_coarse - 1) + 1, num_dofs_u_fine = num_elem * (p_fine - 1) + 1;
18*506b1a0cSSebastian Grimberg CeedInt ind_u_coarse[num_elem * p_coarse], ind_u_fine[num_elem * p_fine], ind_x[num_elem * 2];
19*506b1a0cSSebastian Grimberg CeedScalar assembled_values[num_dofs_u_coarse * num_dofs_u_fine];
20*506b1a0cSSebastian Grimberg CeedScalar assembled_true[num_dofs_u_coarse * num_dofs_u_fine];
21*506b1a0cSSebastian Grimberg
22*506b1a0cSSebastian Grimberg CeedInit(argv[1], &ceed);
23*506b1a0cSSebastian Grimberg
24*506b1a0cSSebastian Grimberg CeedVectorCreate(ceed, num_dofs_x, &x);
25*506b1a0cSSebastian Grimberg {
26*506b1a0cSSebastian Grimberg CeedScalar x_array[num_dofs_x];
27*506b1a0cSSebastian Grimberg
28*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < num_dofs_x; i++) x_array[i] = (CeedScalar)i / (num_dofs_x - 1);
29*506b1a0cSSebastian Grimberg CeedVectorSetArray(x, CEED_MEM_HOST, CEED_COPY_VALUES, x_array);
30*506b1a0cSSebastian Grimberg }
31*506b1a0cSSebastian Grimberg CeedVectorCreate(ceed, num_dofs_u_coarse, &u);
32*506b1a0cSSebastian Grimberg CeedVectorCreate(ceed, num_dofs_u_fine, &v);
33*506b1a0cSSebastian Grimberg CeedVectorCreate(ceed, num_elem * q, &q_data);
34*506b1a0cSSebastian Grimberg
35*506b1a0cSSebastian Grimberg // Restrictions
36*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < num_elem; i++) {
37*506b1a0cSSebastian Grimberg ind_x[2 * i + 0] = i;
38*506b1a0cSSebastian Grimberg ind_x[2 * i + 1] = i + 1;
39*506b1a0cSSebastian Grimberg }
40*506b1a0cSSebastian Grimberg CeedElemRestrictionCreate(ceed, num_elem, 2, 1, 1, num_dofs_x, CEED_MEM_HOST, CEED_USE_POINTER, ind_x, &elem_restriction_x);
41*506b1a0cSSebastian Grimberg
42*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < num_elem; i++) {
43*506b1a0cSSebastian Grimberg for (CeedInt j = 0; j < p_coarse; j++) {
44*506b1a0cSSebastian Grimberg ind_u_coarse[p_coarse * i + j] = i * (p_coarse - 1) + j;
45*506b1a0cSSebastian Grimberg }
46*506b1a0cSSebastian Grimberg }
47*506b1a0cSSebastian Grimberg CeedElemRestrictionCreate(ceed, num_elem, p_coarse, 1, 1, num_dofs_u_coarse, CEED_MEM_HOST, CEED_USE_POINTER, ind_u_coarse,
48*506b1a0cSSebastian Grimberg &elem_restriction_u_coarse);
49*506b1a0cSSebastian Grimberg
50*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < num_elem; i++) {
51*506b1a0cSSebastian Grimberg for (CeedInt j = 0; j < p_fine; j++) {
52*506b1a0cSSebastian Grimberg ind_u_fine[p_fine * i + j] = i * (p_fine - 1) + j;
53*506b1a0cSSebastian Grimberg }
54*506b1a0cSSebastian Grimberg }
55*506b1a0cSSebastian Grimberg CeedElemRestrictionCreate(ceed, num_elem, p_fine, 1, 1, num_dofs_u_fine, CEED_MEM_HOST, CEED_USE_POINTER, ind_u_fine, &elem_restriction_u_fine);
56*506b1a0cSSebastian Grimberg
57*506b1a0cSSebastian Grimberg CeedInt strides_q_data[3] = {1, q, q};
58*506b1a0cSSebastian Grimberg CeedElemRestrictionCreateStrided(ceed, num_elem, q, 1, q * num_elem, strides_q_data, &elem_restriction_q_data);
59*506b1a0cSSebastian Grimberg
60*506b1a0cSSebastian Grimberg // Bases
61*506b1a0cSSebastian Grimberg CeedBasisCreateTensorH1Lagrange(ceed, 1, 1, 2, q, CEED_GAUSS, &basis_x);
62*506b1a0cSSebastian Grimberg CeedBasisCreateTensorH1Lagrange(ceed, 1, 1, p_coarse, q, CEED_GAUSS, &basis_u_coarse);
63*506b1a0cSSebastian Grimberg CeedBasisCreateTensorH1Lagrange(ceed, 1, 1, p_fine, q, CEED_GAUSS, &basis_u_fine);
64*506b1a0cSSebastian Grimberg
65*506b1a0cSSebastian Grimberg // QFunctions
66*506b1a0cSSebastian Grimberg CeedQFunctionCreateInteriorByName(ceed, "Mass1DBuild", &qf_setup);
67*506b1a0cSSebastian Grimberg CeedQFunctionCreateInteriorByName(ceed, "MassApply", &qf_mass);
68*506b1a0cSSebastian Grimberg
69*506b1a0cSSebastian Grimberg // Operators
70*506b1a0cSSebastian Grimberg CeedOperatorCreate(ceed, qf_setup, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, &op_setup);
71*506b1a0cSSebastian Grimberg
72*506b1a0cSSebastian Grimberg CeedOperatorSetField(op_setup, "weights", CEED_ELEMRESTRICTION_NONE, basis_x, CEED_VECTOR_NONE);
73*506b1a0cSSebastian Grimberg CeedOperatorSetField(op_setup, "dx", elem_restriction_x, basis_x, CEED_VECTOR_ACTIVE);
74*506b1a0cSSebastian Grimberg CeedOperatorSetField(op_setup, "qdata", elem_restriction_q_data, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE);
75*506b1a0cSSebastian Grimberg
76*506b1a0cSSebastian Grimberg CeedOperatorCreate(ceed, qf_mass, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, &op_mass);
77*506b1a0cSSebastian Grimberg CeedOperatorSetField(op_mass, "qdata", elem_restriction_q_data, CEED_BASIS_NONE, q_data);
78*506b1a0cSSebastian Grimberg CeedOperatorSetField(op_mass, "u", elem_restriction_u_coarse, basis_u_coarse, CEED_VECTOR_ACTIVE);
79*506b1a0cSSebastian Grimberg CeedOperatorSetField(op_mass, "v", elem_restriction_u_fine, basis_u_fine, CEED_VECTOR_ACTIVE);
80*506b1a0cSSebastian Grimberg
81*506b1a0cSSebastian Grimberg CeedOperatorApply(op_setup, x, q_data, CEED_REQUEST_IMMEDIATE);
82*506b1a0cSSebastian Grimberg
83*506b1a0cSSebastian Grimberg // Fully assemble operator
84*506b1a0cSSebastian Grimberg CeedSize num_entries;
85*506b1a0cSSebastian Grimberg CeedInt *rows;
86*506b1a0cSSebastian Grimberg CeedInt *cols;
87*506b1a0cSSebastian Grimberg CeedVector assembled;
88*506b1a0cSSebastian Grimberg
89*506b1a0cSSebastian Grimberg for (CeedInt k = 0; k < num_dofs_u_coarse * num_dofs_u_fine; ++k) {
90*506b1a0cSSebastian Grimberg assembled_values[k] = 0.0;
91*506b1a0cSSebastian Grimberg assembled_true[k] = 0.0;
92*506b1a0cSSebastian Grimberg }
93*506b1a0cSSebastian Grimberg CeedOperatorLinearAssembleSymbolic(op_mass, &num_entries, &rows, &cols);
94*506b1a0cSSebastian Grimberg CeedVectorCreate(ceed, num_entries, &assembled);
95*506b1a0cSSebastian Grimberg CeedOperatorLinearAssemble(op_mass, assembled);
96*506b1a0cSSebastian Grimberg {
97*506b1a0cSSebastian Grimberg const CeedScalar *assembled_array;
98*506b1a0cSSebastian Grimberg
99*506b1a0cSSebastian Grimberg CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembled_array);
100*506b1a0cSSebastian Grimberg for (CeedInt k = 0; k < num_entries; ++k) {
101*506b1a0cSSebastian Grimberg assembled_values[rows[k] * num_dofs_u_coarse + cols[k]] += assembled_array[k];
102*506b1a0cSSebastian Grimberg }
103*506b1a0cSSebastian Grimberg CeedVectorRestoreArrayRead(assembled, &assembled_array);
104*506b1a0cSSebastian Grimberg }
105*506b1a0cSSebastian Grimberg
106*506b1a0cSSebastian Grimberg // Manually assemble operator
107*506b1a0cSSebastian Grimberg CeedVectorSetValue(u, 0.0);
108*506b1a0cSSebastian Grimberg for (CeedInt j = 0; j < num_dofs_u_coarse; j++) {
109*506b1a0cSSebastian Grimberg CeedScalar *u_array;
110*506b1a0cSSebastian Grimberg const CeedScalar *v_array;
111*506b1a0cSSebastian Grimberg
112*506b1a0cSSebastian Grimberg // Set input
113*506b1a0cSSebastian Grimberg CeedVectorGetArray(u, CEED_MEM_HOST, &u_array);
114*506b1a0cSSebastian Grimberg u_array[j] = 1.0;
115*506b1a0cSSebastian Grimberg if (j) u_array[j - 1] = 0.0;
116*506b1a0cSSebastian Grimberg CeedVectorRestoreArray(u, &u_array);
117*506b1a0cSSebastian Grimberg
118*506b1a0cSSebastian Grimberg // Compute entries for column j
119*506b1a0cSSebastian Grimberg CeedOperatorApply(op_mass, u, v, CEED_REQUEST_IMMEDIATE);
120*506b1a0cSSebastian Grimberg
121*506b1a0cSSebastian Grimberg CeedVectorGetArrayRead(v, CEED_MEM_HOST, &v_array);
122*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < num_dofs_u_fine; i++) assembled_true[i * num_dofs_u_coarse + j] = v_array[i];
123*506b1a0cSSebastian Grimberg CeedVectorRestoreArrayRead(v, &v_array);
124*506b1a0cSSebastian Grimberg }
125*506b1a0cSSebastian Grimberg
126*506b1a0cSSebastian Grimberg // Check output
127*506b1a0cSSebastian Grimberg for (CeedInt i = 0; i < num_dofs_u_fine; i++) {
128*506b1a0cSSebastian Grimberg for (CeedInt j = 0; j < num_dofs_u_coarse; j++) {
129*506b1a0cSSebastian Grimberg if (fabs(assembled_values[i * num_dofs_u_coarse + j] - assembled_true[i * num_dofs_u_coarse + j]) > 100. * CEED_EPSILON) {
130*506b1a0cSSebastian Grimberg // LCOV_EXCL_START
131*506b1a0cSSebastian Grimberg printf("[%" CeedInt_FMT ", %" CeedInt_FMT "] Error in assembly: %f != %f\n", i, j, assembled_values[i * num_dofs_u_coarse + j],
132*506b1a0cSSebastian Grimberg assembled_true[i * num_dofs_u_coarse + j]);
133*506b1a0cSSebastian Grimberg // LCOV_EXCL_STOP
134*506b1a0cSSebastian Grimberg }
135*506b1a0cSSebastian Grimberg }
136*506b1a0cSSebastian Grimberg }
137*506b1a0cSSebastian Grimberg
138*506b1a0cSSebastian Grimberg // Cleanup
139*506b1a0cSSebastian Grimberg free(rows);
140*506b1a0cSSebastian Grimberg free(cols);
141*506b1a0cSSebastian Grimberg CeedVectorDestroy(&x);
142*506b1a0cSSebastian Grimberg CeedVectorDestroy(&q_data);
143*506b1a0cSSebastian Grimberg CeedVectorDestroy(&u);
144*506b1a0cSSebastian Grimberg CeedVectorDestroy(&v);
145*506b1a0cSSebastian Grimberg CeedVectorDestroy(&assembled);
146*506b1a0cSSebastian Grimberg CeedElemRestrictionDestroy(&elem_restriction_u_coarse);
147*506b1a0cSSebastian Grimberg CeedElemRestrictionDestroy(&elem_restriction_u_fine);
148*506b1a0cSSebastian Grimberg CeedElemRestrictionDestroy(&elem_restriction_x);
149*506b1a0cSSebastian Grimberg CeedElemRestrictionDestroy(&elem_restriction_q_data);
150*506b1a0cSSebastian Grimberg CeedBasisDestroy(&basis_u_coarse);
151*506b1a0cSSebastian Grimberg CeedBasisDestroy(&basis_u_fine);
152*506b1a0cSSebastian Grimberg CeedBasisDestroy(&basis_x);
153*506b1a0cSSebastian Grimberg CeedQFunctionDestroy(&qf_setup);
154*506b1a0cSSebastian Grimberg CeedQFunctionDestroy(&qf_mass);
155*506b1a0cSSebastian Grimberg CeedOperatorDestroy(&op_setup);
156*506b1a0cSSebastian Grimberg CeedOperatorDestroy(&op_mass);
157*506b1a0cSSebastian Grimberg CeedDestroy(&ceed);
158*506b1a0cSSebastian Grimberg return 0;
159*506b1a0cSSebastian Grimberg }
160