xref: /libCEED/tests/t562-operator.c (revision e2f04181a00c6a5b9d49ef9d074211a68e322886)
1*e2f04181SAndrew T. Barker /// @file
2*e2f04181SAndrew T. Barker /// Test full assembly of mass and Poisson operator (see t535)
3*e2f04181SAndrew T. Barker /// \test Test full assembly of mass and Poisson operator
4*e2f04181SAndrew T. Barker #include <ceed.h>
5*e2f04181SAndrew T. Barker #include <stdlib.h>
6*e2f04181SAndrew T. Barker #include <math.h>
7*e2f04181SAndrew T. Barker #include "t535-operator.h"
8*e2f04181SAndrew T. Barker 
9*e2f04181SAndrew T. Barker int main(int argc, char **argv) {
10*e2f04181SAndrew T. Barker   Ceed ceed;
11*e2f04181SAndrew T. Barker   CeedElemRestriction Erestrictx, Erestrictu,
12*e2f04181SAndrew T. Barker                       Erestrictui, Erestrictqi;
13*e2f04181SAndrew T. Barker   CeedBasis bx, bu;
14*e2f04181SAndrew T. Barker   CeedQFunction qf_setup_mass, qf_setup_diff, qf_apply;
15*e2f04181SAndrew T. Barker   CeedOperator op_setup_mass, op_setup_diff, op_apply;
16*e2f04181SAndrew T. Barker   CeedVector qdata_mass, qdata_diff, X, U, V;
17*e2f04181SAndrew T. Barker   CeedInt P = 3, Q = 4, dim = 2;
18*e2f04181SAndrew T. Barker   CeedInt nx = 3, ny = 2;
19*e2f04181SAndrew T. Barker   CeedInt nelem = nx * ny;
20*e2f04181SAndrew T. Barker   CeedInt ndofs = (nx*2+1)*(ny*2+1), nqpts = nelem*Q*Q;
21*e2f04181SAndrew T. Barker   CeedInt indx[nelem*P*P];
22*e2f04181SAndrew T. Barker   CeedScalar assembled[ndofs*ndofs];
23*e2f04181SAndrew T. Barker   CeedScalar x[dim*ndofs], assembledTrue[ndofs*ndofs];
24*e2f04181SAndrew T. Barker   CeedScalar *u;
25*e2f04181SAndrew T. Barker   const CeedScalar *v;
26*e2f04181SAndrew T. Barker 
27*e2f04181SAndrew T. Barker   CeedInit(argv[1], &ceed);
28*e2f04181SAndrew T. Barker 
29*e2f04181SAndrew T. Barker   // DoF Coordinates
30*e2f04181SAndrew T. Barker   for (CeedInt i=0; i<nx*2+1; i++)
31*e2f04181SAndrew T. Barker     for (CeedInt j=0; j<ny*2+1; j++) {
32*e2f04181SAndrew T. Barker       x[i+j*(nx*2+1)+0*ndofs] = (CeedScalar) i / (2*nx);
33*e2f04181SAndrew T. Barker       x[i+j*(nx*2+1)+1*ndofs] = (CeedScalar) j / (2*ny);
34*e2f04181SAndrew T. Barker     }
35*e2f04181SAndrew T. Barker   CeedVectorCreate(ceed, dim*ndofs, &X);
36*e2f04181SAndrew T. Barker   CeedVectorSetArray(X, CEED_MEM_HOST, CEED_USE_POINTER, x);
37*e2f04181SAndrew T. Barker 
38*e2f04181SAndrew T. Barker   // Qdata Vectors
39*e2f04181SAndrew T. Barker   CeedVectorCreate(ceed, nqpts, &qdata_mass);
40*e2f04181SAndrew T. Barker   CeedVectorCreate(ceed, nqpts*dim*(dim+1)/2, &qdata_diff);
41*e2f04181SAndrew T. Barker 
42*e2f04181SAndrew T. Barker   // Element Setup
43*e2f04181SAndrew T. Barker   for (CeedInt i=0; i<nelem; i++) {
44*e2f04181SAndrew T. Barker     CeedInt col, row, offset;
45*e2f04181SAndrew T. Barker     col = i % nx;
46*e2f04181SAndrew T. Barker     row = i / nx;
47*e2f04181SAndrew T. Barker     offset = col*(P-1) + row*(nx*2+1)*(P-1);
48*e2f04181SAndrew T. Barker     for (CeedInt j=0; j<P; j++)
49*e2f04181SAndrew T. Barker       for (CeedInt k=0; k<P; k++)
50*e2f04181SAndrew T. Barker         indx[P*(P*i+k)+j] = offset + k*(nx*2+1) + j;
51*e2f04181SAndrew T. Barker   }
52*e2f04181SAndrew T. Barker 
53*e2f04181SAndrew T. Barker   // Restrictions
54*e2f04181SAndrew T. Barker   CeedElemRestrictionCreate(ceed, nelem, P*P, dim, ndofs, dim*ndofs,
55*e2f04181SAndrew T. Barker                             CEED_MEM_HOST, CEED_USE_POINTER, indx, &Erestrictx);
56*e2f04181SAndrew T. Barker 
57*e2f04181SAndrew T. Barker   CeedElemRestrictionCreate(ceed, nelem, P*P, 1, 1, ndofs, CEED_MEM_HOST,
58*e2f04181SAndrew T. Barker                             CEED_USE_POINTER, indx, &Erestrictu);
59*e2f04181SAndrew T. Barker   CeedInt stridesu[3] = {1, Q*Q, Q*Q};
60*e2f04181SAndrew T. Barker   CeedElemRestrictionCreateStrided(ceed, nelem, Q*Q, 1, nqpts, stridesu,
61*e2f04181SAndrew T. Barker                                    &Erestrictui);
62*e2f04181SAndrew T. Barker 
63*e2f04181SAndrew T. Barker   CeedInt stridesqd[3] = {1, Q*Q, Q *Q *dim *(dim+1)/2};
64*e2f04181SAndrew T. Barker   CeedElemRestrictionCreateStrided(ceed, nelem, Q*Q, dim*(dim+1)/2,
65*e2f04181SAndrew T. Barker                                    dim*(dim+1)/2*nqpts,
66*e2f04181SAndrew T. Barker                                    stridesqd, &Erestrictqi);
67*e2f04181SAndrew T. Barker 
68*e2f04181SAndrew T. Barker   // Bases
69*e2f04181SAndrew T. Barker   CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, P, Q, CEED_GAUSS, &bx);
70*e2f04181SAndrew T. Barker   CeedBasisCreateTensorH1Lagrange(ceed, dim, 1, P, Q, CEED_GAUSS, &bu);
71*e2f04181SAndrew T. Barker 
72*e2f04181SAndrew T. Barker   // QFunction - setup mass
73*e2f04181SAndrew T. Barker   CeedQFunctionCreateInterior(ceed, 1, setup_mass, setup_mass_loc,
74*e2f04181SAndrew T. Barker                               &qf_setup_mass);
75*e2f04181SAndrew T. Barker   CeedQFunctionAddInput(qf_setup_mass, "dx", dim*dim, CEED_EVAL_GRAD);
76*e2f04181SAndrew T. Barker   CeedQFunctionAddInput(qf_setup_mass, "_weight", 1, CEED_EVAL_WEIGHT);
77*e2f04181SAndrew T. Barker   CeedQFunctionAddOutput(qf_setup_mass, "qdata", 1, CEED_EVAL_NONE);
78*e2f04181SAndrew T. Barker 
79*e2f04181SAndrew T. Barker   // Operator - setup mass
80*e2f04181SAndrew T. Barker   CeedOperatorCreate(ceed, qf_setup_mass, CEED_QFUNCTION_NONE,
81*e2f04181SAndrew T. Barker                      CEED_QFUNCTION_NONE, &op_setup_mass);
82*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_setup_mass, "dx", Erestrictx, bx, CEED_VECTOR_ACTIVE);
83*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_setup_mass, "_weight", CEED_ELEMRESTRICTION_NONE, bx,
84*e2f04181SAndrew T. Barker                        CEED_VECTOR_NONE);
85*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_setup_mass, "qdata", Erestrictui,
86*e2f04181SAndrew T. Barker                        CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
87*e2f04181SAndrew T. Barker 
88*e2f04181SAndrew T. Barker   // QFunction - setup diff
89*e2f04181SAndrew T. Barker   CeedQFunctionCreateInterior(ceed, 1, setup_diff, setup_diff_loc,
90*e2f04181SAndrew T. Barker                               &qf_setup_diff);
91*e2f04181SAndrew T. Barker   CeedQFunctionAddInput(qf_setup_diff, "dx", dim*dim, CEED_EVAL_GRAD);
92*e2f04181SAndrew T. Barker   CeedQFunctionAddInput(qf_setup_diff, "_weight", 1, CEED_EVAL_WEIGHT);
93*e2f04181SAndrew T. Barker   CeedQFunctionAddOutput(qf_setup_diff, "qdata", dim*(dim+1)/2, CEED_EVAL_NONE);
94*e2f04181SAndrew T. Barker 
95*e2f04181SAndrew T. Barker   // Operator - setup diff
96*e2f04181SAndrew T. Barker   CeedOperatorCreate(ceed, qf_setup_diff, CEED_QFUNCTION_NONE,
97*e2f04181SAndrew T. Barker                      CEED_QFUNCTION_NONE, &op_setup_diff);
98*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_setup_diff, "dx", Erestrictx, bx, CEED_VECTOR_ACTIVE);
99*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_setup_diff, "_weight", CEED_ELEMRESTRICTION_NONE, bx,
100*e2f04181SAndrew T. Barker                        CEED_VECTOR_NONE);
101*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_setup_diff, "qdata", Erestrictqi,
102*e2f04181SAndrew T. Barker                        CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
103*e2f04181SAndrew T. Barker 
104*e2f04181SAndrew T. Barker   // Apply Setup Operators
105*e2f04181SAndrew T. Barker   CeedOperatorApply(op_setup_mass, X, qdata_mass, CEED_REQUEST_IMMEDIATE);
106*e2f04181SAndrew T. Barker   CeedOperatorApply(op_setup_diff, X, qdata_diff, CEED_REQUEST_IMMEDIATE);
107*e2f04181SAndrew T. Barker 
108*e2f04181SAndrew T. Barker   // QFunction - apply
109*e2f04181SAndrew T. Barker   CeedQFunctionCreateInterior(ceed, 1, apply, apply_loc, &qf_apply);
110*e2f04181SAndrew T. Barker   CeedQFunctionAddInput(qf_apply, "du", dim, CEED_EVAL_GRAD);
111*e2f04181SAndrew T. Barker   CeedQFunctionAddInput(qf_apply, "qdata_mass", 1, CEED_EVAL_NONE);
112*e2f04181SAndrew T. Barker   CeedQFunctionAddInput(qf_apply, "qdata_diff", dim*(dim+1)/2, CEED_EVAL_NONE);
113*e2f04181SAndrew T. Barker   CeedQFunctionAddInput(qf_apply, "u", 1, CEED_EVAL_INTERP);
114*e2f04181SAndrew T. Barker   CeedQFunctionAddOutput(qf_apply, "v", 1, CEED_EVAL_INTERP);
115*e2f04181SAndrew T. Barker   CeedQFunctionAddOutput(qf_apply, "dv", dim, CEED_EVAL_GRAD);
116*e2f04181SAndrew T. Barker 
117*e2f04181SAndrew T. Barker   // Operator - apply
118*e2f04181SAndrew T. Barker   CeedOperatorCreate(ceed, qf_apply, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE,
119*e2f04181SAndrew T. Barker                      &op_apply);
120*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_apply, "du", Erestrictu, bu, CEED_VECTOR_ACTIVE);
121*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_apply, "qdata_mass", Erestrictui,
122*e2f04181SAndrew T. Barker                        CEED_BASIS_COLLOCATED, qdata_mass);
123*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_apply, "qdata_diff", Erestrictqi,
124*e2f04181SAndrew T. Barker                        CEED_BASIS_COLLOCATED, qdata_diff);
125*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_apply, "u", Erestrictu, bu, CEED_VECTOR_ACTIVE);
126*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_apply, "v", Erestrictu, bu, CEED_VECTOR_ACTIVE);
127*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_apply, "dv", Erestrictu, bu, CEED_VECTOR_ACTIVE);
128*e2f04181SAndrew T. Barker 
129*e2f04181SAndrew T. Barker   // Fully assemble operator
130*e2f04181SAndrew T. Barker   for (int k=0; k<ndofs*ndofs; ++k) {
131*e2f04181SAndrew T. Barker     assembled[k] = 0.0;
132*e2f04181SAndrew T. Barker     assembledTrue[k] = 0.0;
133*e2f04181SAndrew T. Barker   }
134*e2f04181SAndrew T. Barker   CeedInt nentries;
135*e2f04181SAndrew T. Barker   CeedInt *rows;
136*e2f04181SAndrew T. Barker   CeedInt *cols;
137*e2f04181SAndrew T. Barker   CeedVector values;
138*e2f04181SAndrew T. Barker   CeedOperatorLinearAssembleSymbolic(op_apply, &nentries, &rows, &cols);
139*e2f04181SAndrew T. Barker   CeedVectorCreate(ceed, nentries, &values);
140*e2f04181SAndrew T. Barker   CeedOperatorLinearAssemble(op_apply, values);
141*e2f04181SAndrew T. Barker   const CeedScalar *vals;
142*e2f04181SAndrew T. Barker   CeedVectorGetArrayRead(values, CEED_MEM_HOST, &vals);
143*e2f04181SAndrew T. Barker   for (int k=0; k<nentries; ++k) {
144*e2f04181SAndrew T. Barker     assembled[rows[k]*ndofs + cols[k]] += vals[k];
145*e2f04181SAndrew T. Barker   }
146*e2f04181SAndrew T. Barker   CeedVectorRestoreArrayRead(values, &vals);
147*e2f04181SAndrew T. Barker 
148*e2f04181SAndrew T. Barker   // Manually assemble operator
149*e2f04181SAndrew T. Barker   CeedVectorCreate(ceed, ndofs, &U);
150*e2f04181SAndrew T. Barker   CeedVectorSetValue(U, 0.0);
151*e2f04181SAndrew T. Barker   CeedVectorCreate(ceed, ndofs, &V);
152*e2f04181SAndrew T. Barker   for (int i=0; i<ndofs; i++) {
153*e2f04181SAndrew T. Barker     // Set input
154*e2f04181SAndrew T. Barker     CeedVectorGetArray(U, CEED_MEM_HOST, &u);
155*e2f04181SAndrew T. Barker     u[i] = 1.0;
156*e2f04181SAndrew T. Barker     if (i)
157*e2f04181SAndrew T. Barker       u[i-1] = 0.0;
158*e2f04181SAndrew T. Barker     CeedVectorRestoreArray(U, &u);
159*e2f04181SAndrew T. Barker 
160*e2f04181SAndrew T. Barker     // Compute entries for column i
161*e2f04181SAndrew T. Barker     CeedOperatorApply(op_apply, U, V, CEED_REQUEST_IMMEDIATE);
162*e2f04181SAndrew T. Barker 
163*e2f04181SAndrew T. Barker     CeedVectorGetArrayRead(V, CEED_MEM_HOST, &v);
164*e2f04181SAndrew T. Barker     for (int k=0; k<ndofs; k++) {
165*e2f04181SAndrew T. Barker       assembledTrue[i*ndofs + k] = v[k];
166*e2f04181SAndrew T. Barker     }
167*e2f04181SAndrew T. Barker     CeedVectorRestoreArrayRead(V, &v);
168*e2f04181SAndrew T. Barker   }
169*e2f04181SAndrew T. Barker 
170*e2f04181SAndrew T. Barker   // Check output
171*e2f04181SAndrew T. Barker   for (int i=0; i<ndofs; i++)
172*e2f04181SAndrew T. Barker     for (int j=0; j<ndofs; j++)
173*e2f04181SAndrew T. Barker       if (fabs(assembled[j*ndofs+i] - assembledTrue[j*ndofs+i]) > 1e-14)
174*e2f04181SAndrew T. Barker         // LCOV_EXCL_START
175*e2f04181SAndrew T. Barker         printf("[%d,%d] Error in assembly: %f != %f\n", i, j,
176*e2f04181SAndrew T. Barker                assembled[j*ndofs+i], assembledTrue[j*ndofs+i]);
177*e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
178*e2f04181SAndrew T. Barker 
179*e2f04181SAndrew T. Barker   // Cleanup
180*e2f04181SAndrew T. Barker   free(rows);
181*e2f04181SAndrew T. Barker   free(cols);
182*e2f04181SAndrew T. Barker   CeedVectorDestroy(&values);
183*e2f04181SAndrew T. Barker   CeedQFunctionDestroy(&qf_setup_mass);
184*e2f04181SAndrew T. Barker   CeedQFunctionDestroy(&qf_setup_diff);
185*e2f04181SAndrew T. Barker   CeedQFunctionDestroy(&qf_apply);
186*e2f04181SAndrew T. Barker   CeedOperatorDestroy(&op_setup_mass);
187*e2f04181SAndrew T. Barker   CeedOperatorDestroy(&op_setup_diff);
188*e2f04181SAndrew T. Barker   CeedOperatorDestroy(&op_apply);
189*e2f04181SAndrew T. Barker   CeedElemRestrictionDestroy(&Erestrictu);
190*e2f04181SAndrew T. Barker   CeedElemRestrictionDestroy(&Erestrictx);
191*e2f04181SAndrew T. Barker   CeedElemRestrictionDestroy(&Erestrictui);
192*e2f04181SAndrew T. Barker   CeedElemRestrictionDestroy(&Erestrictqi);
193*e2f04181SAndrew T. Barker   CeedBasisDestroy(&bu);
194*e2f04181SAndrew T. Barker   CeedBasisDestroy(&bx);
195*e2f04181SAndrew T. Barker   CeedVectorDestroy(&X);
196*e2f04181SAndrew T. Barker   CeedVectorDestroy(&qdata_mass);
197*e2f04181SAndrew T. Barker   CeedVectorDestroy(&qdata_diff);
198*e2f04181SAndrew T. Barker   CeedVectorDestroy(&U);
199*e2f04181SAndrew T. Barker   CeedVectorDestroy(&V);
200*e2f04181SAndrew T. Barker   CeedDestroy(&ceed);
201*e2f04181SAndrew T. Barker   return 0;
202*e2f04181SAndrew T. Barker }
203