xref: /libCEED/rust/libceed-sys/c-src/backends/ref/ceed-ref-operator.c (revision 8d713cf6e78a6ffd2518ae96db9cfdbd22a60f79)
121617c04Sjeremylt // Copyright (c) 2017-2018, Lawrence Livermore National Security, LLC.
221617c04Sjeremylt // Produced at the Lawrence Livermore National Laboratory. LLNL-CODE-734707.
321617c04Sjeremylt // All Rights reserved. See files LICENSE and NOTICE for details.
421617c04Sjeremylt //
521617c04Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
621617c04Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
721617c04Sjeremylt // element discretizations for exascale applications. For more information and
821617c04Sjeremylt // source code availability see http://github.com/ceed.
921617c04Sjeremylt //
1021617c04Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
1121617c04Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
1221617c04Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
1321617c04Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
1421617c04Sjeremylt // software, applications, hardware, advanced system engineering and early
1521617c04Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
1621617c04Sjeremylt 
1721617c04Sjeremylt #include <string.h>
1821617c04Sjeremylt #include "ceed-ref.h"
1921617c04Sjeremylt 
2021617c04Sjeremylt static int CeedOperatorDestroy_Ref(CeedOperator op) {
2121617c04Sjeremylt   int ierr;
224ce2993fSjeremylt   CeedOperator_Ref *impl;
234ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void*)&impl); CeedChk(ierr);
2421617c04Sjeremylt 
25885ac19cSjeremylt   for (CeedInt i=0; i<impl->numein+impl->numeout; i++) {
26885ac19cSjeremylt     ierr = CeedVectorDestroy(&impl->evecs[i]); CeedChk(ierr);
27885ac19cSjeremylt   }
28885ac19cSjeremylt   ierr = CeedFree(&impl->evecs); CeedChk(ierr);
29885ac19cSjeremylt   ierr = CeedFree(&impl->edata); CeedChk(ierr);
30*8d713cf6Sjeremylt   ierr = CeedFree(&impl->inputstate); CeedChk(ierr);
31885ac19cSjeremylt 
32aedaa0e5Sjeremylt   for (CeedInt i=0; i<impl->numein; i++) {
3391703d3fSjeremylt     ierr = CeedVectorDestroy(&impl->evecsin[i]); CeedChk(ierr);
34aedaa0e5Sjeremylt     ierr = CeedVectorDestroy(&impl->qvecsin[i]); CeedChk(ierr);
35885ac19cSjeremylt   }
3691703d3fSjeremylt   ierr = CeedFree(&impl->evecsin); CeedChk(ierr);
37aedaa0e5Sjeremylt   ierr = CeedFree(&impl->qvecsin); CeedChk(ierr);
38885ac19cSjeremylt 
39aedaa0e5Sjeremylt   for (CeedInt i=0; i<impl->numeout; i++) {
4091703d3fSjeremylt     ierr = CeedVectorDestroy(&impl->evecsout[i]); CeedChk(ierr);
41aedaa0e5Sjeremylt     ierr = CeedVectorDestroy(&impl->qvecsout[i]); CeedChk(ierr);
42aedaa0e5Sjeremylt   }
4391703d3fSjeremylt   ierr = CeedFree(&impl->evecsout); CeedChk(ierr);
44aedaa0e5Sjeremylt   ierr = CeedFree(&impl->qvecsout); CeedChk(ierr);
45885ac19cSjeremylt 
46fe2413ffSjeremylt   ierr = CeedFree(&impl); CeedChk(ierr);
4721617c04Sjeremylt   return 0;
4821617c04Sjeremylt }
4921617c04Sjeremylt 
50885ac19cSjeremylt /*
51885ac19cSjeremylt   Setup infields or outfields
52885ac19cSjeremylt  */
53fe2413ffSjeremylt static int CeedOperatorSetupFields_Ref(CeedQFunction qf, CeedOperator op,
5491703d3fSjeremylt                                        bool inOrOut,
5591703d3fSjeremylt                                        CeedVector *fullevecs, CeedVector *evecs,
56aedaa0e5Sjeremylt                                        CeedVector *qvecs, CeedInt starte,
57135a076eSjeremylt                                        CeedInt numfields, CeedInt Q) {
58aedaa0e5Sjeremylt   CeedInt dim, ierr, ncomp;
59aedaa0e5Sjeremylt   Ceed ceed;
60aedaa0e5Sjeremylt   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
61d1bcdac9Sjeremylt   CeedBasis basis;
62d1bcdac9Sjeremylt   CeedElemRestriction Erestrict;
63aedaa0e5Sjeremylt   CeedOperatorField *opfields;
64aedaa0e5Sjeremylt   CeedQFunctionField *qffields;
65fe2413ffSjeremylt   if (inOrOut) {
66aedaa0e5Sjeremylt     ierr = CeedOperatorGetFields(op, NULL, &opfields);
67fe2413ffSjeremylt     CeedChk(ierr);
68aedaa0e5Sjeremylt     ierr = CeedQFunctionGetFields(qf, NULL, &qffields);
69fe2413ffSjeremylt     CeedChk(ierr);
70fe2413ffSjeremylt   } else {
71aedaa0e5Sjeremylt     ierr = CeedOperatorGetFields(op, &opfields, NULL);
72fe2413ffSjeremylt     CeedChk(ierr);
73aedaa0e5Sjeremylt     ierr = CeedQFunctionGetFields(qf, &qffields, NULL);
74fe2413ffSjeremylt     CeedChk(ierr);
75fe2413ffSjeremylt   }
7621617c04Sjeremylt 
77885ac19cSjeremylt   // Loop over fields
78885ac19cSjeremylt   for (CeedInt i=0; i<numfields; i++) {
79d1bcdac9Sjeremylt     CeedEvalMode emode;
80aedaa0e5Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode); CeedChk(ierr);
81135a076eSjeremylt 
82135a076eSjeremylt     if (emode != CEED_EVAL_WEIGHT) {
83aedaa0e5Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opfields[i], &Erestrict);
84d1bcdac9Sjeremylt       CeedChk(ierr);
85d1bcdac9Sjeremylt       ierr = CeedElemRestrictionCreateVector(Erestrict, NULL,
8691703d3fSjeremylt                                              &fullevecs[i+starte]);
87135a076eSjeremylt       CeedChk(ierr);
88135a076eSjeremylt     }
89135a076eSjeremylt 
90885ac19cSjeremylt     switch(emode) {
91885ac19cSjeremylt     case CEED_EVAL_NONE:
92aedaa0e5Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qffields[i], &ncomp);
93d1bcdac9Sjeremylt       CeedChk(ierr);
94aedaa0e5Sjeremylt       ierr = CeedVectorCreate(ceed, Q*ncomp, &qvecs[i]); CeedChk(ierr);
95aedaa0e5Sjeremylt       break;
96aedaa0e5Sjeremylt     case CEED_EVAL_INTERP:
97aedaa0e5Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qffields[i], &ncomp);
98aedaa0e5Sjeremylt       CeedChk(ierr);
9991703d3fSjeremylt       ierr = CeedVectorCreate(ceed, Q*ncomp, &evecs[i]); CeedChk(ierr);
100aedaa0e5Sjeremylt       ierr = CeedVectorCreate(ceed, Q*ncomp, &qvecs[i]); CeedChk(ierr);
101885ac19cSjeremylt       break;
102885ac19cSjeremylt     case CEED_EVAL_GRAD:
103aedaa0e5Sjeremylt       ierr = CeedOperatorFieldGetBasis(opfields[i], &basis); CeedChk(ierr);
104aedaa0e5Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qffields[i], &ncomp);
105d1bcdac9Sjeremylt       ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
10691703d3fSjeremylt       ierr = CeedVectorCreate(ceed, Q*ncomp, &evecs[i]); CeedChk(ierr);
107aedaa0e5Sjeremylt       ierr = CeedVectorCreate(ceed, Q*ncomp*dim, &qvecs[i]); CeedChk(ierr);
108885ac19cSjeremylt       break;
109885ac19cSjeremylt     case CEED_EVAL_WEIGHT: // Only on input fields
110aedaa0e5Sjeremylt       ierr = CeedOperatorFieldGetBasis(opfields[i], &basis); CeedChk(ierr);
111aedaa0e5Sjeremylt       ierr = CeedVectorCreate(ceed, Q, &qvecs[i]); CeedChk(ierr);
112d1bcdac9Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT,
113aedaa0e5Sjeremylt                             NULL, qvecs[i]); CeedChk(ierr);
114885ac19cSjeremylt       break;
115885ac19cSjeremylt     case CEED_EVAL_DIV:
116885ac19cSjeremylt       break; // Not implimented
117885ac19cSjeremylt     case CEED_EVAL_CURL:
118885ac19cSjeremylt       break; // Not implimented
11921617c04Sjeremylt     }
120885ac19cSjeremylt   }
12121617c04Sjeremylt   return 0;
12221617c04Sjeremylt }
12321617c04Sjeremylt 
124885ac19cSjeremylt /*
125885ac19cSjeremylt   CeedOperator needs to connect all the named fields (be they active or passive)
126885ac19cSjeremylt   to the named inputs and outputs of its CeedQFunction.
127885ac19cSjeremylt  */
128885ac19cSjeremylt static int CeedOperatorSetup_Ref(CeedOperator op) {
12921617c04Sjeremylt   int ierr;
1304ce2993fSjeremylt   bool setupdone;
1314ce2993fSjeremylt   ierr = CeedOperatorGetSetupStatus(op, &setupdone); CeedChk(ierr);
1324ce2993fSjeremylt   if (setupdone) return 0;
133aedaa0e5Sjeremylt   Ceed ceed;
134aedaa0e5Sjeremylt   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
1354ce2993fSjeremylt   CeedOperator_Ref *impl;
1364ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void*)&impl); CeedChk(ierr);
1374ce2993fSjeremylt   CeedQFunction qf;
1384ce2993fSjeremylt   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
1394ce2993fSjeremylt   CeedInt Q, numinputfields, numoutputfields;
1404ce2993fSjeremylt   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr);
141a8de75f0Sjeremylt   ierr = CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
142a8de75f0Sjeremylt   CeedChk(ierr);
143d1bcdac9Sjeremylt   CeedOperatorField *opinputfields, *opoutputfields;
144d1bcdac9Sjeremylt   ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields);
145d1bcdac9Sjeremylt   CeedChk(ierr);
146d1bcdac9Sjeremylt   CeedQFunctionField *qfinputfields, *qfoutputfields;
147d1bcdac9Sjeremylt   ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields);
148d1bcdac9Sjeremylt   CeedChk(ierr);
149885ac19cSjeremylt 
150885ac19cSjeremylt   // Allocate
151aedaa0e5Sjeremylt   ierr = CeedCalloc(numinputfields + numoutputfields, &impl->evecs);
152aedaa0e5Sjeremylt   CeedChk(ierr);
153aedaa0e5Sjeremylt   ierr = CeedCalloc(numinputfields + numoutputfields, &impl->edata);
154885ac19cSjeremylt   CeedChk(ierr);
155885ac19cSjeremylt 
156*8d713cf6Sjeremylt   ierr = CeedCalloc(16, &impl->inputstate); CeedChk(ierr);
15791703d3fSjeremylt   ierr = CeedCalloc(16, &impl->evecsin); CeedChk(ierr);
15891703d3fSjeremylt   ierr = CeedCalloc(16, &impl->evecsout); CeedChk(ierr);
159aedaa0e5Sjeremylt   ierr = CeedCalloc(16, &impl->qvecsin); CeedChk(ierr);
160aedaa0e5Sjeremylt   ierr = CeedCalloc(16, &impl->qvecsout); CeedChk(ierr);
161885ac19cSjeremylt 
162aedaa0e5Sjeremylt   impl->numein = numinputfields; impl->numeout = numoutputfields;
163885ac19cSjeremylt 
164aedaa0e5Sjeremylt   // Set up infield and outfield evecs and qvecs
165885ac19cSjeremylt   // Infields
16691703d3fSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf, op, 0, impl->evecs,
16791703d3fSjeremylt                                      impl->evecsin, impl->qvecsin, 0,
168aedaa0e5Sjeremylt                                      numinputfields, Q);
169aedaa0e5Sjeremylt   CeedChk(ierr);
170885ac19cSjeremylt 
171885ac19cSjeremylt   // Outfields
17291703d3fSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf, op, 1, impl->evecs,
17391703d3fSjeremylt                                      impl->evecsout, impl->qvecsout,
174aedaa0e5Sjeremylt                                      numinputfields, numoutputfields, Q);
175d1bcdac9Sjeremylt   CeedChk(ierr);
176885ac19cSjeremylt 
1774ce2993fSjeremylt   ierr = CeedOperatorSetSetupDone(op); CeedChk(ierr);
178885ac19cSjeremylt 
179885ac19cSjeremylt   return 0;
180885ac19cSjeremylt }
181885ac19cSjeremylt 
182885ac19cSjeremylt static int CeedOperatorApply_Ref(CeedOperator op, CeedVector invec,
183885ac19cSjeremylt                                  CeedVector outvec, CeedRequest *request) {
184885ac19cSjeremylt   int ierr;
1854ce2993fSjeremylt   CeedOperator_Ref *impl;
1864ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void*)&impl); CeedChk(ierr);
1874ce2993fSjeremylt   CeedQFunction qf;
1884ce2993fSjeremylt   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
189d1bcdac9Sjeremylt   CeedInt Q, numelements, elemsize, numinputfields, numoutputfields, ncomp;
1904ce2993fSjeremylt   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr);
1914ce2993fSjeremylt   ierr = CeedOperatorGetNumElements(op, &numelements); CeedChk(ierr);
1924ce2993fSjeremylt   ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
1934ce2993fSjeremylt   CeedChk(ierr);
1944dccadb6Sjeremylt   CeedTransposeMode lmode;
195d1bcdac9Sjeremylt   CeedOperatorField *opinputfields, *opoutputfields;
196d1bcdac9Sjeremylt   ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields);
197d1bcdac9Sjeremylt   CeedChk(ierr);
198d1bcdac9Sjeremylt   CeedQFunctionField *qfinputfields, *qfoutputfields;
199d1bcdac9Sjeremylt   ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields);
200d1bcdac9Sjeremylt   CeedChk(ierr);
201d1bcdac9Sjeremylt   CeedEvalMode emode;
202d1bcdac9Sjeremylt   CeedVector vec;
203d1bcdac9Sjeremylt   CeedBasis basis;
204d1bcdac9Sjeremylt   CeedElemRestriction Erestrict;
205*8d713cf6Sjeremylt   uint64_t state;
206885ac19cSjeremylt 
207885ac19cSjeremylt   // Setup
208885ac19cSjeremylt   ierr = CeedOperatorSetup_Ref(op); CeedChk(ierr);
209885ac19cSjeremylt 
210885ac19cSjeremylt   // Input Evecs and Restriction
2111a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
212d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
213d1bcdac9Sjeremylt     CeedChk(ierr);
214135a076eSjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
215668048e2SJed Brown     } else {
216d1bcdac9Sjeremylt       // Get input vector
217d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetVector(opinputfields[i], &vec); CeedChk(ierr);
218d1bcdac9Sjeremylt       if (vec == CEED_VECTOR_ACTIVE)
219d1bcdac9Sjeremylt         vec = invec;
220668048e2SJed Brown       // Restrict
221*8d713cf6Sjeremylt       ierr = CeedVectorGetState(vec, &state); CeedChk(ierr);
222*8d713cf6Sjeremylt       // Skip restriction if input is unchanged
223*8d713cf6Sjeremylt       if (state != impl->inputstate[i] || vec == invec) {
224d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetElemRestriction(opinputfields[i], &Erestrict);
225d1bcdac9Sjeremylt         CeedChk(ierr);
2264dccadb6Sjeremylt         ierr = CeedOperatorFieldGetLMode(opinputfields[i], &lmode); CeedChk(ierr);
227d1bcdac9Sjeremylt         ierr = CeedElemRestrictionApply(Erestrict, CEED_NOTRANSPOSE,
228d1bcdac9Sjeremylt                                         lmode, vec, impl->evecs[i],
229668048e2SJed Brown                                         request); CeedChk(ierr);
230*8d713cf6Sjeremylt         impl->inputstate[i] = state;
231*8d713cf6Sjeremylt       }
232668048e2SJed Brown       // Get evec
233a2b73c81Sjeremylt       ierr = CeedVectorGetArrayRead(impl->evecs[i], CEED_MEM_HOST,
234d1bcdac9Sjeremylt                                     (const CeedScalar **) &impl->edata[i]);
235d1bcdac9Sjeremylt       CeedChk(ierr);
236885ac19cSjeremylt     }
237885ac19cSjeremylt   }
238885ac19cSjeremylt 
239885ac19cSjeremylt   // Output Evecs
2401a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
241a2b73c81Sjeremylt     ierr = CeedVectorGetArray(impl->evecs[i+impl->numein], CEED_MEM_HOST,
2421a4ead9bSjeremylt                               &impl->edata[i + numinputfields]); CeedChk(ierr);
243885ac19cSjeremylt   }
244885ac19cSjeremylt 
245885ac19cSjeremylt   // Loop through elements
2464ce2993fSjeremylt   for (CeedInt e=0; e<numelements; e++) {
247885ac19cSjeremylt     // Input basis apply if needed
2481a4ead9bSjeremylt     for (CeedInt i=0; i<numinputfields; i++) {
249135a076eSjeremylt       // Get elemsize, emode, ncomp
250d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opinputfields[i], &Erestrict);
251d1bcdac9Sjeremylt       CeedChk(ierr);
252d1bcdac9Sjeremylt       ierr = CeedElemRestrictionGetElementSize(Erestrict, &elemsize);
253d1bcdac9Sjeremylt       CeedChk(ierr);
254d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
255d1bcdac9Sjeremylt       CeedChk(ierr);
256d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qfinputfields[i], &ncomp);
257d1bcdac9Sjeremylt       CeedChk(ierr);
258885ac19cSjeremylt       // Basis action
259885ac19cSjeremylt       switch(emode) {
260885ac19cSjeremylt       case CEED_EVAL_NONE:
261aedaa0e5Sjeremylt         ierr = CeedVectorSetArray(impl->qvecsin[i], CEED_MEM_HOST,
262aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
263aedaa0e5Sjeremylt                                   &impl->edata[i][e*Q*ncomp]); CeedChk(ierr);
264885ac19cSjeremylt         break;
265885ac19cSjeremylt       case CEED_EVAL_INTERP:
266d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); CeedChk(ierr);
26791703d3fSjeremylt         ierr = CeedVectorSetArray(impl->evecsin[i], CEED_MEM_HOST,
268aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
269aedaa0e5Sjeremylt                                   &impl->edata[i][e*elemsize*ncomp]);
270aedaa0e5Sjeremylt         CeedChk(ierr);
271d1bcdac9Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE,
27291703d3fSjeremylt                               CEED_EVAL_INTERP, impl->evecsin[i],
273aedaa0e5Sjeremylt                               impl->qvecsin[i]); CeedChk(ierr);
274885ac19cSjeremylt         break;
275885ac19cSjeremylt       case CEED_EVAL_GRAD:
276d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); CeedChk(ierr);
27791703d3fSjeremylt         ierr = CeedVectorSetArray(impl->evecsin[i], CEED_MEM_HOST,
278aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
279aedaa0e5Sjeremylt                                   &impl->edata[i][e*elemsize*ncomp]);
280aedaa0e5Sjeremylt         CeedChk(ierr);
281d1bcdac9Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE,
28291703d3fSjeremylt                               CEED_EVAL_GRAD, impl->evecsin[i],
283aedaa0e5Sjeremylt                               impl->qvecsin[i]); CeedChk(ierr);
284885ac19cSjeremylt         break;
285885ac19cSjeremylt       case CEED_EVAL_WEIGHT:
286885ac19cSjeremylt         break;  // No action
287885ac19cSjeremylt       case CEED_EVAL_DIV:
288885ac19cSjeremylt         break; // Not implimented
289885ac19cSjeremylt       case CEED_EVAL_CURL:
290885ac19cSjeremylt         break; // Not implimented
291885ac19cSjeremylt       }
292885ac19cSjeremylt     }
293885ac19cSjeremylt     // Output pointers
2941a4ead9bSjeremylt     for (CeedInt i=0; i<numoutputfields; i++) {
295d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode);
296d1bcdac9Sjeremylt       CeedChk(ierr);
297885ac19cSjeremylt       if (emode == CEED_EVAL_NONE) {
298d1bcdac9Sjeremylt         ierr = CeedQFunctionFieldGetNumComponents(qfoutputfields[i], &ncomp);
299d1bcdac9Sjeremylt         CeedChk(ierr);
300aedaa0e5Sjeremylt         ierr = CeedVectorSetArray(impl->qvecsout[i], CEED_MEM_HOST,
301aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
302aedaa0e5Sjeremylt                                   &impl->edata[i + numinputfields][e*Q*ncomp]);
303aedaa0e5Sjeremylt         CeedChk(ierr);
304885ac19cSjeremylt       }
305885ac19cSjeremylt     }
306885ac19cSjeremylt     // Q function
307aedaa0e5Sjeremylt     ierr = CeedQFunctionApply(qf, Q, impl->qvecsin, impl->qvecsout); CeedChk(ierr);
308885ac19cSjeremylt 
309885ac19cSjeremylt     // Output basis apply if needed
3101a4ead9bSjeremylt     for (CeedInt i=0; i<numoutputfields; i++) {
311135a076eSjeremylt       // Get elemsize, emode, ncomp
312d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opoutputfields[i], &Erestrict);
313d1bcdac9Sjeremylt       CeedChk(ierr);
314d1bcdac9Sjeremylt       ierr = CeedElemRestrictionGetElementSize(Erestrict, &elemsize);
315d1bcdac9Sjeremylt       CeedChk(ierr);
316d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode);
317d1bcdac9Sjeremylt       CeedChk(ierr);
318d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qfoutputfields[i], &ncomp);
319d1bcdac9Sjeremylt       CeedChk(ierr);
320885ac19cSjeremylt       // Basis action
321885ac19cSjeremylt       switch(emode) {
322885ac19cSjeremylt       case CEED_EVAL_NONE:
323885ac19cSjeremylt         break; // No action
324885ac19cSjeremylt       case CEED_EVAL_INTERP:
325d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opoutputfields[i], &basis);
326d1bcdac9Sjeremylt         CeedChk(ierr);
32791703d3fSjeremylt         ierr = CeedVectorSetArray(impl->evecsout[i], CEED_MEM_HOST,
328aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
3291a4ead9bSjeremylt                                   &impl->edata[i + numinputfields][e*elemsize*ncomp]);
330aedaa0e5Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
331aedaa0e5Sjeremylt                               CEED_EVAL_INTERP, impl->qvecsout[i],
33291703d3fSjeremylt                               impl->evecsout[i]); CeedChk(ierr);
333885ac19cSjeremylt         break;
334885ac19cSjeremylt       case CEED_EVAL_GRAD:
335d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opoutputfields[i], &basis);
336d1bcdac9Sjeremylt         CeedChk(ierr);
33791703d3fSjeremylt         ierr = CeedVectorSetArray(impl->evecsout[i], CEED_MEM_HOST,
338aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
339d1bcdac9Sjeremylt                                   &impl->edata[i + numinputfields][e*elemsize*ncomp]);
340aedaa0e5Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
341aedaa0e5Sjeremylt                               CEED_EVAL_GRAD, impl->qvecsout[i],
34291703d3fSjeremylt                               impl->evecsout[i]); CeedChk(ierr);
343885ac19cSjeremylt         break;
3444ce2993fSjeremylt       case CEED_EVAL_WEIGHT: {
3454ce2993fSjeremylt         Ceed ceed;
3464ce2993fSjeremylt         ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
3474ce2993fSjeremylt         return CeedError(ceed, 1,
3488d94b059Sjeremylt                          "CEED_EVAL_WEIGHT cannot be an output evaluation mode");
349885ac19cSjeremylt         break; // Should not occur
3504ce2993fSjeremylt       }
351885ac19cSjeremylt       case CEED_EVAL_DIV:
352885ac19cSjeremylt         break; // Not implimented
353885ac19cSjeremylt       case CEED_EVAL_CURL:
354885ac19cSjeremylt         break; // Not implimented
355885ac19cSjeremylt       }
356885ac19cSjeremylt     }
357885ac19cSjeremylt   }
358885ac19cSjeremylt 
35942ecf959Sjeremylt   // Zero lvecs
360d1bcdac9Sjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
361d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); CeedChk(ierr);
362d1bcdac9Sjeremylt     if (vec == CEED_VECTOR_ACTIVE)
363d1bcdac9Sjeremylt       vec = outvec;
364d1bcdac9Sjeremylt     ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
36542ecf959Sjeremylt   }
36642ecf959Sjeremylt 
367885ac19cSjeremylt   // Output restriction
3681a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
369a2b73c81Sjeremylt     // Restore evec
370a2b73c81Sjeremylt     ierr = CeedVectorRestoreArray(impl->evecs[i+impl->numein],
371d1bcdac9Sjeremylt                                   &impl->edata[i + numinputfields]);
372d1bcdac9Sjeremylt     CeedChk(ierr);
373d1bcdac9Sjeremylt     // Get output vector
374d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); CeedChk(ierr);
375668048e2SJed Brown     // Active
376d1bcdac9Sjeremylt     if (vec == CEED_VECTOR_ACTIVE)
377d1bcdac9Sjeremylt       vec = outvec;
3787ca8db16Sjeremylt     // Restrict
379d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetElemRestriction(opoutputfields[i], &Erestrict);
380d1bcdac9Sjeremylt     CeedChk(ierr);
3814dccadb6Sjeremylt     ierr = CeedOperatorFieldGetLMode(opoutputfields[i], &lmode); CeedChk(ierr);
382d1bcdac9Sjeremylt     ierr = CeedElemRestrictionApply(Erestrict, CEED_TRANSPOSE,
383d1bcdac9Sjeremylt                                     lmode, impl->evecs[i+impl->numein], vec,
384668048e2SJed Brown                                     request); CeedChk(ierr);
385885ac19cSjeremylt   }
386885ac19cSjeremylt 
3877ca8db16Sjeremylt   // Restore input arrays
3881a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
389d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
390d1bcdac9Sjeremylt     CeedChk(ierr);
391135a076eSjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
3927ca8db16Sjeremylt     } else {
393a2b73c81Sjeremylt       ierr = CeedVectorRestoreArrayRead(impl->evecs[i],
394d1bcdac9Sjeremylt                                         (const CeedScalar **) &impl->edata[i]);
395d1bcdac9Sjeremylt       CeedChk(ierr);
3967ca8db16Sjeremylt     }
3977ca8db16Sjeremylt   }
3987ca8db16Sjeremylt 
39921617c04Sjeremylt   return 0;
40021617c04Sjeremylt }
40121617c04Sjeremylt 
40221617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) {
40321617c04Sjeremylt   int ierr;
404fe2413ffSjeremylt   Ceed ceed;
405fe2413ffSjeremylt   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
4064ce2993fSjeremylt   CeedOperator_Ref *impl;
40721617c04Sjeremylt 
40821617c04Sjeremylt   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
409fe2413ffSjeremylt   ierr = CeedOperatorSetData(op, (void*)&impl);
410fe2413ffSjeremylt 
411fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Apply",
412fe2413ffSjeremylt                                 CeedOperatorApply_Ref); CeedChk(ierr);
413fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Destroy",
414fe2413ffSjeremylt                                 CeedOperatorDestroy_Ref); CeedChk(ierr);
41521617c04Sjeremylt   return 0;
41621617c04Sjeremylt }
417