xref: /libCEED/backends/ref/ceed-ref-operator.c (revision d1bcdac99090efedac6b43fd437855ade149b9cc)
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);
30885ac19cSjeremylt 
31885ac19cSjeremylt   for (CeedInt i=0; i<impl->numqin+impl->numqout; i++) {
32885ac19cSjeremylt     ierr = CeedFree(&impl->qdata_alloc[i]); CeedChk(ierr);
33885ac19cSjeremylt   }
34885ac19cSjeremylt   ierr = CeedFree(&impl->qdata_alloc); CeedChk(ierr);
35885ac19cSjeremylt   ierr = CeedFree(&impl->qdata); CeedChk(ierr);
36885ac19cSjeremylt 
37885ac19cSjeremylt   ierr = CeedFree(&impl->indata); CeedChk(ierr);
38885ac19cSjeremylt   ierr = CeedFree(&impl->outdata); CeedChk(ierr);
39885ac19cSjeremylt 
4021617c04Sjeremylt   ierr = CeedFree(&op->data); CeedChk(ierr);
4121617c04Sjeremylt   return 0;
4221617c04Sjeremylt }
4321617c04Sjeremylt 
44885ac19cSjeremylt /*
45885ac19cSjeremylt   Setup infields or outfields
46885ac19cSjeremylt  */
47*d1bcdac9Sjeremylt static int CeedOperatorSetupFields_Ref(CeedQFunctionField qfields[16],
48*d1bcdac9Sjeremylt                                        CeedOperatorField ofields[16],
49885ac19cSjeremylt                                        CeedVector *evecs, CeedScalar **qdata,
50885ac19cSjeremylt                                        CeedScalar **qdata_alloc, CeedScalar **indata,
51135a076eSjeremylt                                        CeedInt starti, CeedInt startq,
52135a076eSjeremylt                                        CeedInt numfields, CeedInt Q) {
53135a076eSjeremylt   CeedInt dim, ierr, iq=startq, ncomp;
54*d1bcdac9Sjeremylt   CeedBasis basis;
55*d1bcdac9Sjeremylt   CeedElemRestriction Erestrict;
5621617c04Sjeremylt 
57885ac19cSjeremylt   // Loop over fields
58885ac19cSjeremylt   for (CeedInt i=0; i<numfields; i++) {
59*d1bcdac9Sjeremylt     CeedEvalMode emode;
60*d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfields[i], &emode); CeedChk(ierr);
61135a076eSjeremylt 
62135a076eSjeremylt     if (emode != CEED_EVAL_WEIGHT) {
63*d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(ofields[i], &Erestrict);
64*d1bcdac9Sjeremylt       CeedChk(ierr);
65*d1bcdac9Sjeremylt       ierr = CeedElemRestrictionCreateVector(Erestrict, NULL,
664b8bea3bSJed Brown                                              &evecs[i+starti]);
67135a076eSjeremylt       CeedChk(ierr);
68135a076eSjeremylt     }
69135a076eSjeremylt 
70885ac19cSjeremylt     switch(emode) {
71885ac19cSjeremylt     case CEED_EVAL_NONE:
72885ac19cSjeremylt       break; // No action
73885ac19cSjeremylt     case CEED_EVAL_INTERP:
74*d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qfields[i], &ncomp);
75*d1bcdac9Sjeremylt       CeedChk(ierr);
76885ac19cSjeremylt       ierr = CeedMalloc(Q*ncomp, &qdata_alloc[iq]); CeedChk(ierr);
77885ac19cSjeremylt       qdata[i + starti] = qdata_alloc[iq];
78885ac19cSjeremylt       iq++;
79885ac19cSjeremylt       break;
80885ac19cSjeremylt     case CEED_EVAL_GRAD:
81*d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetBasis(ofields[i], &basis); CeedChk(ierr);
82*d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qfields[i], &ncomp);
83*d1bcdac9Sjeremylt       ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
84885ac19cSjeremylt       ierr = CeedMalloc(Q*ncomp*dim, &qdata_alloc[iq]); CeedChk(ierr);
85885ac19cSjeremylt       qdata[i + starti] = qdata_alloc[iq];
86885ac19cSjeremylt       iq++;
87885ac19cSjeremylt       break;
88885ac19cSjeremylt     case CEED_EVAL_WEIGHT: // Only on input fields
89*d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetBasis(ofields[i], &basis); CeedChk(ierr);
90885ac19cSjeremylt       ierr = CeedMalloc(Q, &qdata_alloc[iq]); CeedChk(ierr);
91*d1bcdac9Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT,
92885ac19cSjeremylt                             NULL, qdata_alloc[iq]); CeedChk(ierr);
93885ac19cSjeremylt       qdata[i] = qdata_alloc[iq];
94885ac19cSjeremylt       indata[i] = qdata[i];
95885ac19cSjeremylt       iq++;
96885ac19cSjeremylt       break;
97885ac19cSjeremylt     case CEED_EVAL_DIV:
98885ac19cSjeremylt       break; // Not implimented
99885ac19cSjeremylt     case CEED_EVAL_CURL:
100885ac19cSjeremylt       break; // Not implimented
10121617c04Sjeremylt     }
102885ac19cSjeremylt   }
10321617c04Sjeremylt   return 0;
10421617c04Sjeremylt }
10521617c04Sjeremylt 
106885ac19cSjeremylt /*
107885ac19cSjeremylt   CeedOperator needs to connect all the named fields (be they active or passive)
108885ac19cSjeremylt   to the named inputs and outputs of its CeedQFunction.
109885ac19cSjeremylt  */
110885ac19cSjeremylt static int CeedOperatorSetup_Ref(CeedOperator op) {
11121617c04Sjeremylt   int ierr;
1124ce2993fSjeremylt   bool setupdone;
1134ce2993fSjeremylt   ierr = CeedOperatorGetSetupStatus(op, &setupdone); CeedChk(ierr);
1144ce2993fSjeremylt   if (setupdone) return 0;
1154ce2993fSjeremylt   CeedOperator_Ref *impl;
1164ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void*)&impl); CeedChk(ierr);
1174ce2993fSjeremylt   CeedQFunction qf;
1184ce2993fSjeremylt   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
1194ce2993fSjeremylt   CeedInt Q, numinputfields, numoutputfields;
1204ce2993fSjeremylt   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr);
121a8de75f0Sjeremylt   ierr = CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
122a8de75f0Sjeremylt   CeedChk(ierr);
123*d1bcdac9Sjeremylt   CeedOperatorField *opinputfields, *opoutputfields;
124*d1bcdac9Sjeremylt   ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields);
125*d1bcdac9Sjeremylt   CeedChk(ierr);
126*d1bcdac9Sjeremylt   CeedQFunctionField *qfinputfields, *qfoutputfields;
127*d1bcdac9Sjeremylt   ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields);
128*d1bcdac9Sjeremylt   CeedChk(ierr);
129*d1bcdac9Sjeremylt   CeedEvalMode emode;
1304ce2993fSjeremylt 
1314ce2993fSjeremylt   // Count infield and outfield array sizes and evectors
1321a4ead9bSjeremylt   impl->numein = numinputfields;
1331a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
134*d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
135*d1bcdac9Sjeremylt     CeedChk(ierr);
1368d94b059Sjeremylt     impl->numqin += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD) +
1378d94b059Sjeremylt                     !!(emode & CEED_EVAL_WEIGHT);
13821617c04Sjeremylt   }
1391a4ead9bSjeremylt   impl->numeout = numoutputfields;
1401a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
141*d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode);
142*d1bcdac9Sjeremylt     CeedChk(ierr);
143a2b73c81Sjeremylt     impl->numqout += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD);
144885ac19cSjeremylt   }
145885ac19cSjeremylt 
146885ac19cSjeremylt   // Allocate
147a2b73c81Sjeremylt   ierr = CeedCalloc(impl->numein + impl->numeout, &impl->evecs); CeedChk(ierr);
148a2b73c81Sjeremylt   ierr = CeedCalloc(impl->numein + impl->numeout, &impl->edata);
149885ac19cSjeremylt   CeedChk(ierr);
150885ac19cSjeremylt 
151a2b73c81Sjeremylt   ierr = CeedCalloc(impl->numqin + impl->numqout, &impl->qdata_alloc);
152885ac19cSjeremylt   CeedChk(ierr);
1531a4ead9bSjeremylt   ierr = CeedCalloc(numinputfields + numoutputfields, &impl->qdata);
154885ac19cSjeremylt   CeedChk(ierr);
155885ac19cSjeremylt 
156a2b73c81Sjeremylt   ierr = CeedCalloc(16, &impl->indata); CeedChk(ierr);
157a2b73c81Sjeremylt   ierr = CeedCalloc(16, &impl->outdata); CeedChk(ierr);
158885ac19cSjeremylt 
159885ac19cSjeremylt   // Set up infield and outfield pointer arrays
160885ac19cSjeremylt   // Infields
161*d1bcdac9Sjeremylt   ierr = CeedOperatorSetupFields_Ref(qfinputfields, opinputfields,
162a2b73c81Sjeremylt                                      impl->evecs, impl->qdata, impl->qdata_alloc,
163a2b73c81Sjeremylt                                      impl->indata, 0, 0,
1641a4ead9bSjeremylt                                      numinputfields, Q); CeedChk(ierr);
165885ac19cSjeremylt 
166885ac19cSjeremylt   // Outfields
167*d1bcdac9Sjeremylt   ierr = CeedOperatorSetupFields_Ref(qfoutputfields, opoutputfields,
168a2b73c81Sjeremylt                                      impl->evecs, impl->qdata, impl->qdata_alloc,
1691a4ead9bSjeremylt                                      impl->indata, numinputfields,
170*d1bcdac9Sjeremylt                                      impl->numqin, numoutputfields, Q);
171*d1bcdac9Sjeremylt   CeedChk(ierr);
172885ac19cSjeremylt 
1738d94b059Sjeremylt   // Input Qvecs
1741a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
175*d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
176*d1bcdac9Sjeremylt     CeedChk(ierr);
1778d94b059Sjeremylt     if ((emode != CEED_EVAL_NONE) && (emode != CEED_EVAL_WEIGHT))
1788d94b059Sjeremylt       impl->indata[i] =  impl->qdata[i];
1798d94b059Sjeremylt   }
1807ca8db16Sjeremylt   // Output Qvecs
1811a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
182*d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode);
183*d1bcdac9Sjeremylt     CeedChk(ierr);
1848d94b059Sjeremylt     if (emode != CEED_EVAL_NONE)
1851a4ead9bSjeremylt       impl->outdata[i] =  impl->qdata[i + numinputfields];
1867ca8db16Sjeremylt   }
1877ca8db16Sjeremylt 
1884ce2993fSjeremylt   ierr = CeedOperatorSetSetupDone(op); CeedChk(ierr);
189885ac19cSjeremylt 
190885ac19cSjeremylt   return 0;
191885ac19cSjeremylt }
192885ac19cSjeremylt 
193885ac19cSjeremylt static int CeedOperatorApply_Ref(CeedOperator op, CeedVector invec,
194885ac19cSjeremylt                                  CeedVector outvec, CeedRequest *request) {
195885ac19cSjeremylt   int ierr;
1964ce2993fSjeremylt   CeedOperator_Ref *impl;
1974ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void*)&impl); CeedChk(ierr);
1984ce2993fSjeremylt   CeedQFunction qf;
1994ce2993fSjeremylt   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
200*d1bcdac9Sjeremylt   CeedInt Q, numelements, elemsize, numinputfields, numoutputfields, ncomp;
2014ce2993fSjeremylt   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr);
2024ce2993fSjeremylt   ierr = CeedOperatorGetNumElements(op, &numelements); CeedChk(ierr);
2034ce2993fSjeremylt   ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
2044ce2993fSjeremylt   CeedChk(ierr);
205885ac19cSjeremylt   CeedTransposeMode lmode = CEED_NOTRANSPOSE;
206*d1bcdac9Sjeremylt   CeedOperatorField *opinputfields, *opoutputfields;
207*d1bcdac9Sjeremylt   ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields);
208*d1bcdac9Sjeremylt   CeedChk(ierr);
209*d1bcdac9Sjeremylt   CeedQFunctionField *qfinputfields, *qfoutputfields;
210*d1bcdac9Sjeremylt   ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields);
211*d1bcdac9Sjeremylt   CeedChk(ierr);
212*d1bcdac9Sjeremylt   CeedEvalMode emode;
213*d1bcdac9Sjeremylt   CeedVector vec;
214*d1bcdac9Sjeremylt   CeedBasis basis;
215*d1bcdac9Sjeremylt   CeedElemRestriction Erestrict;
216885ac19cSjeremylt 
217885ac19cSjeremylt   // Setup
218885ac19cSjeremylt   ierr = CeedOperatorSetup_Ref(op); CeedChk(ierr);
219885ac19cSjeremylt 
220885ac19cSjeremylt   // Input Evecs and Restriction
2211a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
222*d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
223*d1bcdac9Sjeremylt     CeedChk(ierr);
224135a076eSjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
225668048e2SJed Brown     } else {
226*d1bcdac9Sjeremylt       // Get input vector
227*d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetVector(opinputfields[i], &vec); CeedChk(ierr);
228*d1bcdac9Sjeremylt       if (vec == CEED_VECTOR_ACTIVE)
229*d1bcdac9Sjeremylt         vec = invec;
230668048e2SJed Brown       // Restrict
231*d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opinputfields[i], &Erestrict);
232*d1bcdac9Sjeremylt       CeedChk(ierr);
233*d1bcdac9Sjeremylt       ierr = CeedElemRestrictionApply(Erestrict, CEED_NOTRANSPOSE,
234*d1bcdac9Sjeremylt                                       lmode, vec, impl->evecs[i],
235668048e2SJed Brown                                       request); CeedChk(ierr);
236668048e2SJed Brown       // Get evec
237a2b73c81Sjeremylt       ierr = CeedVectorGetArrayRead(impl->evecs[i], CEED_MEM_HOST,
238*d1bcdac9Sjeremylt                                     (const CeedScalar **) &impl->edata[i]);
239*d1bcdac9Sjeremylt       CeedChk(ierr);
240885ac19cSjeremylt     }
241885ac19cSjeremylt   }
242885ac19cSjeremylt 
243885ac19cSjeremylt   // Output Evecs
2441a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
245a2b73c81Sjeremylt     ierr = CeedVectorGetArray(impl->evecs[i+impl->numein], CEED_MEM_HOST,
2461a4ead9bSjeremylt                               &impl->edata[i + numinputfields]); CeedChk(ierr);
247885ac19cSjeremylt   }
248885ac19cSjeremylt 
249885ac19cSjeremylt   // Loop through elements
2504ce2993fSjeremylt   for (CeedInt e=0; e<numelements; e++) {
251885ac19cSjeremylt     // Input basis apply if needed
2521a4ead9bSjeremylt     for (CeedInt i=0; i<numinputfields; i++) {
253135a076eSjeremylt       // Get elemsize, emode, ncomp
254*d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opinputfields[i], &Erestrict);
255*d1bcdac9Sjeremylt       CeedChk(ierr);
256*d1bcdac9Sjeremylt       ierr = CeedElemRestrictionGetElementSize(Erestrict, &elemsize);
257*d1bcdac9Sjeremylt       CeedChk(ierr);
258*d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
259*d1bcdac9Sjeremylt       CeedChk(ierr);
260*d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qfinputfields[i], &ncomp);
261*d1bcdac9Sjeremylt       CeedChk(ierr);
262885ac19cSjeremylt       // Basis action
263885ac19cSjeremylt       switch(emode) {
264885ac19cSjeremylt       case CEED_EVAL_NONE:
265a2b73c81Sjeremylt         impl->indata[i] = &impl->edata[i][e*Q*ncomp];
266885ac19cSjeremylt         break;
267885ac19cSjeremylt       case CEED_EVAL_INTERP:
268*d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); CeedChk(ierr);
269*d1bcdac9Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE,
270*d1bcdac9Sjeremylt                               CEED_EVAL_INTERP, &impl->edata[i][e*elemsize*ncomp],
271*d1bcdac9Sjeremylt                               impl->qdata[i]); CeedChk(ierr);
272885ac19cSjeremylt         break;
273885ac19cSjeremylt       case CEED_EVAL_GRAD:
274*d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); CeedChk(ierr);
275*d1bcdac9Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE,
276*d1bcdac9Sjeremylt                               CEED_EVAL_GRAD, &impl->edata[i][e*elemsize*ncomp],
277*d1bcdac9Sjeremylt                               impl->qdata[i]); CeedChk(ierr);
278885ac19cSjeremylt         break;
279885ac19cSjeremylt       case CEED_EVAL_WEIGHT:
280885ac19cSjeremylt         break;  // No action
281885ac19cSjeremylt       case CEED_EVAL_DIV:
282885ac19cSjeremylt         break; // Not implimented
283885ac19cSjeremylt       case CEED_EVAL_CURL:
284885ac19cSjeremylt         break; // Not implimented
285885ac19cSjeremylt       }
286885ac19cSjeremylt     }
287885ac19cSjeremylt     // Output pointers
2881a4ead9bSjeremylt     for (CeedInt i=0; i<numoutputfields; i++) {
289*d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode);
290*d1bcdac9Sjeremylt       CeedChk(ierr);
291885ac19cSjeremylt       if (emode == CEED_EVAL_NONE) {
292*d1bcdac9Sjeremylt         ierr = CeedQFunctionFieldGetNumComponents(qfoutputfields[i], &ncomp);
293*d1bcdac9Sjeremylt         CeedChk(ierr);
2941a4ead9bSjeremylt         impl->outdata[i] = &impl->edata[i + numinputfields][e*Q*ncomp];
295885ac19cSjeremylt       }
296885ac19cSjeremylt     }
297885ac19cSjeremylt     // Q function
2984ce2993fSjeremylt     ierr = CeedQFunctionApply(qf, Q, (const CeedScalar * const*) impl->indata,
299a2b73c81Sjeremylt                               impl->outdata); CeedChk(ierr);
300885ac19cSjeremylt 
301885ac19cSjeremylt     // Output basis apply if needed
3021a4ead9bSjeremylt     for (CeedInt i=0; i<numoutputfields; i++) {
303135a076eSjeremylt       // Get elemsize, emode, ncomp
304*d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opoutputfields[i], &Erestrict);
305*d1bcdac9Sjeremylt       CeedChk(ierr);
306*d1bcdac9Sjeremylt       ierr = CeedElemRestrictionGetElementSize(Erestrict, &elemsize);
307*d1bcdac9Sjeremylt       CeedChk(ierr);
308*d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode);
309*d1bcdac9Sjeremylt       CeedChk(ierr);
310*d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qfoutputfields[i], &ncomp);
311*d1bcdac9Sjeremylt       CeedChk(ierr);
312885ac19cSjeremylt       // Basis action
313885ac19cSjeremylt       switch(emode) {
314885ac19cSjeremylt       case CEED_EVAL_NONE:
315885ac19cSjeremylt         break; // No action
316885ac19cSjeremylt       case CEED_EVAL_INTERP:
317*d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opoutputfields[i], &basis);
318*d1bcdac9Sjeremylt         CeedChk(ierr);
319*d1bcdac9Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
320a2b73c81Sjeremylt                               CEED_EVAL_INTERP, impl->outdata[i],
3211a4ead9bSjeremylt                               &impl->edata[i + numinputfields][e*elemsize*ncomp]);
3228d94b059Sjeremylt         CeedChk(ierr);
323885ac19cSjeremylt         break;
324885ac19cSjeremylt       case CEED_EVAL_GRAD:
325*d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opoutputfields[i], &basis);
326*d1bcdac9Sjeremylt         CeedChk(ierr);
327*d1bcdac9Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
328*d1bcdac9Sjeremylt                               CEED_EVAL_GRAD, impl->outdata[i],
329*d1bcdac9Sjeremylt                               &impl->edata[i + numinputfields][e*elemsize*ncomp]);
330885ac19cSjeremylt         CeedChk(ierr);
331885ac19cSjeremylt         break;
3324ce2993fSjeremylt       case CEED_EVAL_WEIGHT: {
3334ce2993fSjeremylt         Ceed ceed;
3344ce2993fSjeremylt         ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
3354ce2993fSjeremylt         return CeedError(ceed, 1,
3368d94b059Sjeremylt                          "CEED_EVAL_WEIGHT cannot be an output evaluation mode");
337885ac19cSjeremylt         break; // Should not occur
3384ce2993fSjeremylt       }
339885ac19cSjeremylt       case CEED_EVAL_DIV:
340885ac19cSjeremylt         break; // Not implimented
341885ac19cSjeremylt       case CEED_EVAL_CURL:
342885ac19cSjeremylt         break; // Not implimented
343885ac19cSjeremylt       }
344885ac19cSjeremylt     }
345885ac19cSjeremylt   }
346885ac19cSjeremylt 
34742ecf959Sjeremylt   // Zero lvecs
348*d1bcdac9Sjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
349*d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); CeedChk(ierr);
350*d1bcdac9Sjeremylt     if (vec == CEED_VECTOR_ACTIVE)
351*d1bcdac9Sjeremylt       vec = outvec;
352*d1bcdac9Sjeremylt     ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
35342ecf959Sjeremylt     }
35442ecf959Sjeremylt 
355885ac19cSjeremylt   // Output restriction
3561a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
357a2b73c81Sjeremylt     // Restore evec
358a2b73c81Sjeremylt     ierr = CeedVectorRestoreArray(impl->evecs[i+impl->numein],
359*d1bcdac9Sjeremylt                                   &impl->edata[i + numinputfields]);
360*d1bcdac9Sjeremylt     CeedChk(ierr);
361*d1bcdac9Sjeremylt     // Get output vector
362*d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); CeedChk(ierr);
363668048e2SJed Brown     // Active
364*d1bcdac9Sjeremylt     if (vec == CEED_VECTOR_ACTIVE)
365*d1bcdac9Sjeremylt       vec = outvec;
3667ca8db16Sjeremylt     // Restrict
367*d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetElemRestriction(opoutputfields[i], &Erestrict);
368*d1bcdac9Sjeremylt     CeedChk(ierr);
369*d1bcdac9Sjeremylt     ierr = CeedElemRestrictionApply(Erestrict, CEED_TRANSPOSE,
370*d1bcdac9Sjeremylt                                     lmode, impl->evecs[i+impl->numein], vec,
371668048e2SJed Brown                                     request); CeedChk(ierr);
372885ac19cSjeremylt   }
373885ac19cSjeremylt 
3747ca8db16Sjeremylt   // Restore input arrays
3751a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
376*d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
377*d1bcdac9Sjeremylt     CeedChk(ierr);
378135a076eSjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
3797ca8db16Sjeremylt     } else {
380a2b73c81Sjeremylt       ierr = CeedVectorRestoreArrayRead(impl->evecs[i],
381*d1bcdac9Sjeremylt                                         (const CeedScalar **) &impl->edata[i]);
382*d1bcdac9Sjeremylt       CeedChk(ierr);
3837ca8db16Sjeremylt     }
3847ca8db16Sjeremylt   }
3857ca8db16Sjeremylt 
38621617c04Sjeremylt   return 0;
38721617c04Sjeremylt }
38821617c04Sjeremylt 
38921617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) {
39021617c04Sjeremylt   int ierr;
3914ce2993fSjeremylt   CeedOperator_Ref *impl;
39221617c04Sjeremylt 
39321617c04Sjeremylt   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
39421617c04Sjeremylt   op->data = impl;
39521617c04Sjeremylt   op->Destroy = CeedOperatorDestroy_Ref;
39621617c04Sjeremylt   op->Apply = CeedOperatorApply_Ref;
39721617c04Sjeremylt   return 0;
39821617c04Sjeremylt }
399