xref: /libCEED/tests/t565-operator.c (revision e2f04181a00c6a5b9d49ef9d074211a68e322886)
1*e2f04181SAndrew T. Barker /// @file
2*e2f04181SAndrew T. Barker /// Test full assembly of composite operator (see t538)
3*e2f04181SAndrew T. Barker /// \test Test full assembly of composite 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 
8*e2f04181SAndrew T. Barker int main(int argc, char **argv) {
9*e2f04181SAndrew T. Barker   Ceed ceed;
10*e2f04181SAndrew T. Barker   CeedElemRestriction Erestrictx, Erestrictu,
11*e2f04181SAndrew T. Barker                       Erestrictui, ErestrictqiMass, ErestrictqiDiff;
12*e2f04181SAndrew T. Barker   CeedBasis bx, bu;
13*e2f04181SAndrew T. Barker   CeedQFunction qf_setupMass, qf_mass, qf_setupDiff, qf_diff;
14*e2f04181SAndrew T. Barker   CeedOperator op_setupMass, op_mass, op_setupDiff, op_diff, op_apply;
15*e2f04181SAndrew T. Barker   CeedVector qdataMass, qdataDiff, X, U, V;
16*e2f04181SAndrew T. Barker   CeedInt P = 3, Q = 4, dim = 2;
17*e2f04181SAndrew T. Barker   CeedInt nx = 3, ny = 2;
18*e2f04181SAndrew T. Barker   CeedInt nelem = nx * ny;
19*e2f04181SAndrew T. Barker   CeedInt ndofs = (nx*2+1)*(ny*2+1), nqpts = nelem*Q*Q;
20*e2f04181SAndrew T. Barker   CeedInt indx[nelem*P*P];
21*e2f04181SAndrew T. Barker   CeedScalar assembled[ndofs*ndofs];
22*e2f04181SAndrew T. Barker   CeedScalar x[dim*ndofs], assembledTrue[ndofs*ndofs];
23*e2f04181SAndrew T. Barker   CeedScalar *u;
24*e2f04181SAndrew T. Barker   const CeedScalar *v;
25*e2f04181SAndrew T. Barker 
26*e2f04181SAndrew T. Barker   CeedInit(argv[1], &ceed);
27*e2f04181SAndrew T. Barker 
28*e2f04181SAndrew T. Barker   // DoF Coordinates
29*e2f04181SAndrew T. Barker   for (CeedInt i=0; i<nx*2+1; i++)
30*e2f04181SAndrew T. Barker     for (CeedInt j=0; j<ny*2+1; j++) {
31*e2f04181SAndrew T. Barker       x[i+j*(nx*2+1)+0*ndofs] = (CeedScalar) i / (2*nx);
32*e2f04181SAndrew T. Barker       x[i+j*(nx*2+1)+1*ndofs] = (CeedScalar) j / (2*ny);
33*e2f04181SAndrew T. Barker     }
34*e2f04181SAndrew T. Barker   CeedVectorCreate(ceed, dim*ndofs, &X);
35*e2f04181SAndrew T. Barker   CeedVectorSetArray(X, CEED_MEM_HOST, CEED_USE_POINTER, x);
36*e2f04181SAndrew T. Barker 
37*e2f04181SAndrew T. Barker   // Qdata Vectors
38*e2f04181SAndrew T. Barker   CeedVectorCreate(ceed, nqpts, &qdataMass);
39*e2f04181SAndrew T. Barker   CeedVectorCreate(ceed, nqpts*dim*(dim+1)/2, &qdataDiff);
40*e2f04181SAndrew T. Barker 
41*e2f04181SAndrew T. Barker   // Element Setup
42*e2f04181SAndrew T. Barker   for (CeedInt i=0; i<nelem; i++) {
43*e2f04181SAndrew T. Barker     CeedInt col, row, offset;
44*e2f04181SAndrew T. Barker     col = i % nx;
45*e2f04181SAndrew T. Barker     row = i / nx;
46*e2f04181SAndrew T. Barker     offset = col*(P-1) + row*(nx*2+1)*(P-1);
47*e2f04181SAndrew T. Barker     for (CeedInt j=0; j<P; j++)
48*e2f04181SAndrew T. Barker       for (CeedInt k=0; k<P; k++)
49*e2f04181SAndrew T. Barker         indx[P*(P*i+k)+j] = offset + k*(nx*2+1) + j;
50*e2f04181SAndrew T. Barker   }
51*e2f04181SAndrew T. Barker 
52*e2f04181SAndrew T. Barker   // Restrictions
53*e2f04181SAndrew T. Barker   CeedElemRestrictionCreate(ceed, nelem, P*P, dim, ndofs, dim*ndofs,
54*e2f04181SAndrew T. Barker                             CEED_MEM_HOST, CEED_USE_POINTER, indx, &Erestrictx);
55*e2f04181SAndrew T. Barker 
56*e2f04181SAndrew T. Barker   CeedElemRestrictionCreate(ceed, nelem, P*P, 1, 1, ndofs, CEED_MEM_HOST,
57*e2f04181SAndrew T. Barker                             CEED_USE_POINTER, indx, &Erestrictu);
58*e2f04181SAndrew T. Barker   CeedInt stridesu[3] = {1, Q*Q, Q*Q};
59*e2f04181SAndrew T. Barker   CeedElemRestrictionCreateStrided(ceed, nelem, Q*Q, 1, nqpts, stridesu,
60*e2f04181SAndrew T. Barker                                    &Erestrictui);
61*e2f04181SAndrew T. Barker 
62*e2f04181SAndrew T. Barker   CeedInt stridesqdMass[3] = {1, Q*Q, Q*Q};
63*e2f04181SAndrew T. Barker   CeedElemRestrictionCreateStrided(ceed, nelem, Q*Q, 1, nqpts,
64*e2f04181SAndrew T. Barker                                    stridesqdMass, &ErestrictqiMass);
65*e2f04181SAndrew T. Barker   CeedInt stridesqdDiff[3] = {1, Q*Q, Q*Q*dim*(dim+1)/2}; /* *NOPAD* */
66*e2f04181SAndrew T. Barker   CeedElemRestrictionCreateStrided(ceed, nelem, Q*Q, dim*(dim+1)/2,
67*e2f04181SAndrew T. Barker                                    dim*(dim+1)/2*nqpts,
68*e2f04181SAndrew T. Barker                                    stridesqdDiff, &ErestrictqiDiff);
69*e2f04181SAndrew T. Barker 
70*e2f04181SAndrew T. Barker   // Bases
71*e2f04181SAndrew T. Barker   CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, P, Q, CEED_GAUSS, &bx);
72*e2f04181SAndrew T. Barker   CeedBasisCreateTensorH1Lagrange(ceed, dim, 1, P, Q, CEED_GAUSS, &bu);
73*e2f04181SAndrew T. Barker 
74*e2f04181SAndrew T. Barker   // QFunction - setup mass
75*e2f04181SAndrew T. Barker   CeedQFunctionCreateInteriorByName(ceed, "Mass2DBuild", &qf_setupMass);
76*e2f04181SAndrew T. Barker 
77*e2f04181SAndrew T. Barker   // Operator - setup mass
78*e2f04181SAndrew T. Barker   CeedOperatorCreate(ceed, qf_setupMass, CEED_QFUNCTION_NONE,
79*e2f04181SAndrew T. Barker                      CEED_QFUNCTION_NONE, &op_setupMass);
80*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_setupMass, "dx", Erestrictx, bx, CEED_VECTOR_ACTIVE);
81*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_setupMass, "weights", CEED_ELEMRESTRICTION_NONE, bx,
82*e2f04181SAndrew T. Barker                        CEED_VECTOR_NONE);
83*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_setupMass, "qdata", ErestrictqiMass,
84*e2f04181SAndrew T. Barker                        CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
85*e2f04181SAndrew T. Barker 
86*e2f04181SAndrew T. Barker   // QFunction - setup diffusion
87*e2f04181SAndrew T. Barker   CeedQFunctionCreateInteriorByName(ceed, "Poisson2DBuild", &qf_setupDiff);
88*e2f04181SAndrew T. Barker 
89*e2f04181SAndrew T. Barker   // Operator - setup diffusion
90*e2f04181SAndrew T. Barker   CeedOperatorCreate(ceed, qf_setupDiff, CEED_QFUNCTION_NONE,
91*e2f04181SAndrew T. Barker                      CEED_QFUNCTION_NONE, &op_setupDiff);
92*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_setupDiff, "dx", Erestrictx, bx, CEED_VECTOR_ACTIVE);
93*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_setupDiff, "weights", CEED_ELEMRESTRICTION_NONE, bx,
94*e2f04181SAndrew T. Barker                        CEED_VECTOR_NONE);
95*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_setupDiff, "qdata", ErestrictqiDiff,
96*e2f04181SAndrew T. Barker                        CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
97*e2f04181SAndrew T. Barker 
98*e2f04181SAndrew T. Barker   // Apply Setup Operators
99*e2f04181SAndrew T. Barker   CeedOperatorApply(op_setupMass, X, qdataMass, CEED_REQUEST_IMMEDIATE);
100*e2f04181SAndrew T. Barker   CeedOperatorApply(op_setupDiff, X, qdataDiff, CEED_REQUEST_IMMEDIATE);
101*e2f04181SAndrew T. Barker 
102*e2f04181SAndrew T. Barker   // QFunction - apply mass
103*e2f04181SAndrew T. Barker   CeedQFunctionCreateInteriorByName(ceed, "MassApply", &qf_mass);
104*e2f04181SAndrew T. Barker 
105*e2f04181SAndrew T. Barker   // Operator - apply mass
106*e2f04181SAndrew T. Barker   CeedOperatorCreate(ceed, qf_mass, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE,
107*e2f04181SAndrew T. Barker                      &op_mass);
108*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_mass, "u", Erestrictu, bu, CEED_VECTOR_ACTIVE);
109*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_mass, "qdata", ErestrictqiMass, CEED_BASIS_COLLOCATED,
110*e2f04181SAndrew T. Barker                        qdataMass);
111*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_mass, "v", Erestrictu, bu, CEED_VECTOR_ACTIVE);
112*e2f04181SAndrew T. Barker 
113*e2f04181SAndrew T. Barker   // QFunction - apply diff
114*e2f04181SAndrew T. Barker   CeedQFunctionCreateInteriorByName(ceed, "Poisson2DApply", &qf_diff);
115*e2f04181SAndrew T. Barker 
116*e2f04181SAndrew T. Barker   // Operator - apply
117*e2f04181SAndrew T. Barker   CeedOperatorCreate(ceed, qf_diff, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE,
118*e2f04181SAndrew T. Barker                      &op_diff);
119*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_diff, "du", Erestrictu, bu, CEED_VECTOR_ACTIVE);
120*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_diff, "qdata", ErestrictqiDiff, CEED_BASIS_COLLOCATED,
121*e2f04181SAndrew T. Barker                        qdataDiff);
122*e2f04181SAndrew T. Barker   CeedOperatorSetField(op_diff, "dv", Erestrictu, bu, CEED_VECTOR_ACTIVE);
123*e2f04181SAndrew T. Barker 
124*e2f04181SAndrew T. Barker   // Composite operator
125*e2f04181SAndrew T. Barker   CeedCompositeOperatorCreate(ceed, &op_apply);
126*e2f04181SAndrew T. Barker   CeedCompositeOperatorAddSub(op_apply, op_mass);
127*e2f04181SAndrew T. Barker   CeedCompositeOperatorAddSub(op_apply, op_diff);
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 diagonal
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_setupMass);
184*e2f04181SAndrew T. Barker   CeedQFunctionDestroy(&qf_setupDiff);
185*e2f04181SAndrew T. Barker   CeedQFunctionDestroy(&qf_diff);
186*e2f04181SAndrew T. Barker   CeedQFunctionDestroy(&qf_mass);
187*e2f04181SAndrew T. Barker   CeedOperatorDestroy(&op_setupMass);
188*e2f04181SAndrew T. Barker   CeedOperatorDestroy(&op_setupDiff);
189*e2f04181SAndrew T. Barker   CeedOperatorDestroy(&op_mass);
190*e2f04181SAndrew T. Barker   CeedOperatorDestroy(&op_diff);
191*e2f04181SAndrew T. Barker   CeedOperatorDestroy(&op_apply);
192*e2f04181SAndrew T. Barker   CeedElemRestrictionDestroy(&Erestrictu);
193*e2f04181SAndrew T. Barker   CeedElemRestrictionDestroy(&Erestrictx);
194*e2f04181SAndrew T. Barker   CeedElemRestrictionDestroy(&Erestrictui);
195*e2f04181SAndrew T. Barker   CeedElemRestrictionDestroy(&ErestrictqiMass);
196*e2f04181SAndrew T. Barker   CeedElemRestrictionDestroy(&ErestrictqiDiff);
197*e2f04181SAndrew T. Barker   CeedBasisDestroy(&bu);
198*e2f04181SAndrew T. Barker   CeedBasisDestroy(&bx);
199*e2f04181SAndrew T. Barker   CeedVectorDestroy(&X);
200*e2f04181SAndrew T. Barker   CeedVectorDestroy(&qdataMass);
201*e2f04181SAndrew T. Barker   CeedVectorDestroy(&qdataDiff);
202*e2f04181SAndrew T. Barker   CeedVectorDestroy(&U);
203*e2f04181SAndrew T. Barker   CeedVectorDestroy(&V);
204*e2f04181SAndrew T. Barker   CeedDestroy(&ceed);
205*e2f04181SAndrew T. Barker   return 0;
206*e2f04181SAndrew T. Barker }
207