xref: /libCEED/backends/ref/ceed-ref-operator.c (revision fe2413ff2a5f6e0d0808f191532abb277c4b8bc7)
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 
40*fe2413ffSjeremylt   ierr = CeedFree(&impl); CeedChk(ierr);
4121617c04Sjeremylt   return 0;
4221617c04Sjeremylt }
4321617c04Sjeremylt 
44885ac19cSjeremylt /*
45885ac19cSjeremylt   Setup infields or outfields
46885ac19cSjeremylt  */
47*fe2413ffSjeremylt static int CeedOperatorSetupFields_Ref(CeedQFunction qf, CeedOperator op,
48*fe2413ffSjeremylt                                        bool inOrOut,
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;
54d1bcdac9Sjeremylt   CeedBasis basis;
55d1bcdac9Sjeremylt   CeedElemRestriction Erestrict;
56*fe2413ffSjeremylt   CeedOperatorField *ofields;
57*fe2413ffSjeremylt   CeedQFunctionField *qfields;
58*fe2413ffSjeremylt   if (inOrOut) {
59*fe2413ffSjeremylt     ierr = CeedOperatorGetFields(op, NULL, &ofields);
60*fe2413ffSjeremylt     CeedChk(ierr);
61*fe2413ffSjeremylt     ierr = CeedQFunctionGetFields(qf, NULL, &qfields);
62*fe2413ffSjeremylt     CeedChk(ierr);
63*fe2413ffSjeremylt   } else {
64*fe2413ffSjeremylt     ierr = CeedOperatorGetFields(op, &ofields, NULL);
65*fe2413ffSjeremylt     CeedChk(ierr);
66*fe2413ffSjeremylt     ierr = CeedQFunctionGetFields(qf, &qfields, NULL);
67*fe2413ffSjeremylt     CeedChk(ierr);
68*fe2413ffSjeremylt   }
6921617c04Sjeremylt 
70885ac19cSjeremylt   // Loop over fields
71885ac19cSjeremylt   for (CeedInt i=0; i<numfields; i++) {
72d1bcdac9Sjeremylt     CeedEvalMode emode;
73d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfields[i], &emode); CeedChk(ierr);
74135a076eSjeremylt 
75135a076eSjeremylt     if (emode != CEED_EVAL_WEIGHT) {
76d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(ofields[i], &Erestrict);
77d1bcdac9Sjeremylt       CeedChk(ierr);
78d1bcdac9Sjeremylt       ierr = CeedElemRestrictionCreateVector(Erestrict, NULL,
794b8bea3bSJed Brown                                              &evecs[i+starti]);
80135a076eSjeremylt       CeedChk(ierr);
81135a076eSjeremylt     }
82135a076eSjeremylt 
83885ac19cSjeremylt     switch(emode) {
84885ac19cSjeremylt     case CEED_EVAL_NONE:
85885ac19cSjeremylt       break; // No action
86885ac19cSjeremylt     case CEED_EVAL_INTERP:
87d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qfields[i], &ncomp);
88d1bcdac9Sjeremylt       CeedChk(ierr);
89885ac19cSjeremylt       ierr = CeedMalloc(Q*ncomp, &qdata_alloc[iq]); CeedChk(ierr);
90885ac19cSjeremylt       qdata[i + starti] = qdata_alloc[iq];
91885ac19cSjeremylt       iq++;
92885ac19cSjeremylt       break;
93885ac19cSjeremylt     case CEED_EVAL_GRAD:
94d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetBasis(ofields[i], &basis); CeedChk(ierr);
95d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qfields[i], &ncomp);
96d1bcdac9Sjeremylt       ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
97885ac19cSjeremylt       ierr = CeedMalloc(Q*ncomp*dim, &qdata_alloc[iq]); CeedChk(ierr);
98885ac19cSjeremylt       qdata[i + starti] = qdata_alloc[iq];
99885ac19cSjeremylt       iq++;
100885ac19cSjeremylt       break;
101885ac19cSjeremylt     case CEED_EVAL_WEIGHT: // Only on input fields
102d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetBasis(ofields[i], &basis); CeedChk(ierr);
103885ac19cSjeremylt       ierr = CeedMalloc(Q, &qdata_alloc[iq]); CeedChk(ierr);
104d1bcdac9Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT,
105885ac19cSjeremylt                             NULL, qdata_alloc[iq]); CeedChk(ierr);
106885ac19cSjeremylt       qdata[i] = qdata_alloc[iq];
107885ac19cSjeremylt       indata[i] = qdata[i];
108885ac19cSjeremylt       iq++;
109885ac19cSjeremylt       break;
110885ac19cSjeremylt     case CEED_EVAL_DIV:
111885ac19cSjeremylt       break; // Not implimented
112885ac19cSjeremylt     case CEED_EVAL_CURL:
113885ac19cSjeremylt       break; // Not implimented
11421617c04Sjeremylt     }
115885ac19cSjeremylt   }
11621617c04Sjeremylt   return 0;
11721617c04Sjeremylt }
11821617c04Sjeremylt 
119885ac19cSjeremylt /*
120885ac19cSjeremylt   CeedOperator needs to connect all the named fields (be they active or passive)
121885ac19cSjeremylt   to the named inputs and outputs of its CeedQFunction.
122885ac19cSjeremylt  */
123885ac19cSjeremylt static int CeedOperatorSetup_Ref(CeedOperator op) {
12421617c04Sjeremylt   int ierr;
1254ce2993fSjeremylt   bool setupdone;
1264ce2993fSjeremylt   ierr = CeedOperatorGetSetupStatus(op, &setupdone); CeedChk(ierr);
1274ce2993fSjeremylt   if (setupdone) return 0;
1284ce2993fSjeremylt   CeedOperator_Ref *impl;
1294ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void*)&impl); CeedChk(ierr);
1304ce2993fSjeremylt   CeedQFunction qf;
1314ce2993fSjeremylt   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
1324ce2993fSjeremylt   CeedInt Q, numinputfields, numoutputfields;
1334ce2993fSjeremylt   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr);
134a8de75f0Sjeremylt   ierr = CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
135a8de75f0Sjeremylt   CeedChk(ierr);
136d1bcdac9Sjeremylt   CeedOperatorField *opinputfields, *opoutputfields;
137d1bcdac9Sjeremylt   ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields);
138d1bcdac9Sjeremylt   CeedChk(ierr);
139d1bcdac9Sjeremylt   CeedQFunctionField *qfinputfields, *qfoutputfields;
140d1bcdac9Sjeremylt   ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields);
141d1bcdac9Sjeremylt   CeedChk(ierr);
142d1bcdac9Sjeremylt   CeedEvalMode emode;
1434ce2993fSjeremylt 
1444ce2993fSjeremylt   // Count infield and outfield array sizes and evectors
1451a4ead9bSjeremylt   impl->numein = numinputfields;
1461a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
147d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
148d1bcdac9Sjeremylt     CeedChk(ierr);
1498d94b059Sjeremylt     impl->numqin += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD) +
1508d94b059Sjeremylt                     !!(emode & CEED_EVAL_WEIGHT);
15121617c04Sjeremylt   }
1521a4ead9bSjeremylt   impl->numeout = numoutputfields;
1531a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
154d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode);
155d1bcdac9Sjeremylt     CeedChk(ierr);
156a2b73c81Sjeremylt     impl->numqout += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD);
157885ac19cSjeremylt   }
158885ac19cSjeremylt 
159885ac19cSjeremylt   // Allocate
160a2b73c81Sjeremylt   ierr = CeedCalloc(impl->numein + impl->numeout, &impl->evecs); CeedChk(ierr);
161a2b73c81Sjeremylt   ierr = CeedCalloc(impl->numein + impl->numeout, &impl->edata);
162885ac19cSjeremylt   CeedChk(ierr);
163885ac19cSjeremylt 
164a2b73c81Sjeremylt   ierr = CeedCalloc(impl->numqin + impl->numqout, &impl->qdata_alloc);
165885ac19cSjeremylt   CeedChk(ierr);
1661a4ead9bSjeremylt   ierr = CeedCalloc(numinputfields + numoutputfields, &impl->qdata);
167885ac19cSjeremylt   CeedChk(ierr);
168885ac19cSjeremylt 
169a2b73c81Sjeremylt   ierr = CeedCalloc(16, &impl->indata); CeedChk(ierr);
170a2b73c81Sjeremylt   ierr = CeedCalloc(16, &impl->outdata); CeedChk(ierr);
171885ac19cSjeremylt 
172885ac19cSjeremylt   // Set up infield and outfield pointer arrays
173885ac19cSjeremylt   // Infields
174*fe2413ffSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf, op, 0,
175a2b73c81Sjeremylt                                      impl->evecs, impl->qdata, impl->qdata_alloc,
176a2b73c81Sjeremylt                                      impl->indata, 0, 0,
1771a4ead9bSjeremylt                                      numinputfields, Q); CeedChk(ierr);
178885ac19cSjeremylt 
179885ac19cSjeremylt   // Outfields
180*fe2413ffSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf, op, 1,
181a2b73c81Sjeremylt                                      impl->evecs, impl->qdata, impl->qdata_alloc,
1821a4ead9bSjeremylt                                      impl->indata, numinputfields,
183d1bcdac9Sjeremylt                                      impl->numqin, numoutputfields, Q);
184d1bcdac9Sjeremylt   CeedChk(ierr);
185885ac19cSjeremylt 
1868d94b059Sjeremylt   // Input Qvecs
1871a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
188d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
189d1bcdac9Sjeremylt     CeedChk(ierr);
1908d94b059Sjeremylt     if ((emode != CEED_EVAL_NONE) && (emode != CEED_EVAL_WEIGHT))
1918d94b059Sjeremylt       impl->indata[i] =  impl->qdata[i];
1928d94b059Sjeremylt   }
1937ca8db16Sjeremylt   // Output Qvecs
1941a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
195d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode);
196d1bcdac9Sjeremylt     CeedChk(ierr);
1978d94b059Sjeremylt     if (emode != CEED_EVAL_NONE)
1981a4ead9bSjeremylt       impl->outdata[i] =  impl->qdata[i + numinputfields];
1997ca8db16Sjeremylt   }
2007ca8db16Sjeremylt 
2014ce2993fSjeremylt   ierr = CeedOperatorSetSetupDone(op); CeedChk(ierr);
202885ac19cSjeremylt 
203885ac19cSjeremylt   return 0;
204885ac19cSjeremylt }
205885ac19cSjeremylt 
206885ac19cSjeremylt static int CeedOperatorApply_Ref(CeedOperator op, CeedVector invec,
207885ac19cSjeremylt                                  CeedVector outvec, CeedRequest *request) {
208885ac19cSjeremylt   int ierr;
2094ce2993fSjeremylt   CeedOperator_Ref *impl;
2104ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void*)&impl); CeedChk(ierr);
2114ce2993fSjeremylt   CeedQFunction qf;
2124ce2993fSjeremylt   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
213d1bcdac9Sjeremylt   CeedInt Q, numelements, elemsize, numinputfields, numoutputfields, ncomp;
2144ce2993fSjeremylt   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr);
2154ce2993fSjeremylt   ierr = CeedOperatorGetNumElements(op, &numelements); CeedChk(ierr);
2164ce2993fSjeremylt   ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
2174ce2993fSjeremylt   CeedChk(ierr);
2184dccadb6Sjeremylt   CeedTransposeMode lmode;
219d1bcdac9Sjeremylt   CeedOperatorField *opinputfields, *opoutputfields;
220d1bcdac9Sjeremylt   ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields);
221d1bcdac9Sjeremylt   CeedChk(ierr);
222d1bcdac9Sjeremylt   CeedQFunctionField *qfinputfields, *qfoutputfields;
223d1bcdac9Sjeremylt   ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields);
224d1bcdac9Sjeremylt   CeedChk(ierr);
225d1bcdac9Sjeremylt   CeedEvalMode emode;
226d1bcdac9Sjeremylt   CeedVector vec;
227d1bcdac9Sjeremylt   CeedBasis basis;
228d1bcdac9Sjeremylt   CeedElemRestriction Erestrict;
229885ac19cSjeremylt 
230885ac19cSjeremylt   // Setup
231885ac19cSjeremylt   ierr = CeedOperatorSetup_Ref(op); CeedChk(ierr);
232885ac19cSjeremylt 
233885ac19cSjeremylt   // Input Evecs and Restriction
2341a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
235d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
236d1bcdac9Sjeremylt     CeedChk(ierr);
237135a076eSjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
238668048e2SJed Brown     } else {
239d1bcdac9Sjeremylt       // Get input vector
240d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetVector(opinputfields[i], &vec); CeedChk(ierr);
241d1bcdac9Sjeremylt       if (vec == CEED_VECTOR_ACTIVE)
242d1bcdac9Sjeremylt         vec = invec;
243668048e2SJed Brown       // Restrict
244d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opinputfields[i], &Erestrict);
245d1bcdac9Sjeremylt       CeedChk(ierr);
2464dccadb6Sjeremylt       ierr = CeedOperatorFieldGetLMode(opinputfields[i], &lmode); CeedChk(ierr);
247d1bcdac9Sjeremylt       ierr = CeedElemRestrictionApply(Erestrict, CEED_NOTRANSPOSE,
248d1bcdac9Sjeremylt                                       lmode, vec, impl->evecs[i],
249668048e2SJed Brown                                       request); CeedChk(ierr);
250668048e2SJed Brown       // Get evec
251a2b73c81Sjeremylt       ierr = CeedVectorGetArrayRead(impl->evecs[i], CEED_MEM_HOST,
252d1bcdac9Sjeremylt                                     (const CeedScalar **) &impl->edata[i]);
253d1bcdac9Sjeremylt       CeedChk(ierr);
254885ac19cSjeremylt     }
255885ac19cSjeremylt   }
256885ac19cSjeremylt 
257885ac19cSjeremylt   // Output Evecs
2581a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
259a2b73c81Sjeremylt     ierr = CeedVectorGetArray(impl->evecs[i+impl->numein], CEED_MEM_HOST,
2601a4ead9bSjeremylt                               &impl->edata[i + numinputfields]); CeedChk(ierr);
261885ac19cSjeremylt   }
262885ac19cSjeremylt 
263885ac19cSjeremylt   // Loop through elements
2644ce2993fSjeremylt   for (CeedInt e=0; e<numelements; e++) {
265885ac19cSjeremylt     // Input basis apply if needed
2661a4ead9bSjeremylt     for (CeedInt i=0; i<numinputfields; i++) {
267135a076eSjeremylt       // Get elemsize, emode, ncomp
268d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opinputfields[i], &Erestrict);
269d1bcdac9Sjeremylt       CeedChk(ierr);
270d1bcdac9Sjeremylt       ierr = CeedElemRestrictionGetElementSize(Erestrict, &elemsize);
271d1bcdac9Sjeremylt       CeedChk(ierr);
272d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
273d1bcdac9Sjeremylt       CeedChk(ierr);
274d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qfinputfields[i], &ncomp);
275d1bcdac9Sjeremylt       CeedChk(ierr);
276885ac19cSjeremylt       // Basis action
277885ac19cSjeremylt       switch(emode) {
278885ac19cSjeremylt       case CEED_EVAL_NONE:
279a2b73c81Sjeremylt         impl->indata[i] = &impl->edata[i][e*Q*ncomp];
280885ac19cSjeremylt         break;
281885ac19cSjeremylt       case CEED_EVAL_INTERP:
282d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); CeedChk(ierr);
283d1bcdac9Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE,
284d1bcdac9Sjeremylt                               CEED_EVAL_INTERP, &impl->edata[i][e*elemsize*ncomp],
285d1bcdac9Sjeremylt                               impl->qdata[i]); CeedChk(ierr);
286885ac19cSjeremylt         break;
287885ac19cSjeremylt       case CEED_EVAL_GRAD:
288d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); CeedChk(ierr);
289d1bcdac9Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE,
290d1bcdac9Sjeremylt                               CEED_EVAL_GRAD, &impl->edata[i][e*elemsize*ncomp],
291d1bcdac9Sjeremylt                               impl->qdata[i]); CeedChk(ierr);
292885ac19cSjeremylt         break;
293885ac19cSjeremylt       case CEED_EVAL_WEIGHT:
294885ac19cSjeremylt         break;  // No action
295885ac19cSjeremylt       case CEED_EVAL_DIV:
296885ac19cSjeremylt         break; // Not implimented
297885ac19cSjeremylt       case CEED_EVAL_CURL:
298885ac19cSjeremylt         break; // Not implimented
299885ac19cSjeremylt       }
300885ac19cSjeremylt     }
301885ac19cSjeremylt     // Output pointers
3021a4ead9bSjeremylt     for (CeedInt i=0; i<numoutputfields; i++) {
303d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode);
304d1bcdac9Sjeremylt       CeedChk(ierr);
305885ac19cSjeremylt       if (emode == CEED_EVAL_NONE) {
306d1bcdac9Sjeremylt         ierr = CeedQFunctionFieldGetNumComponents(qfoutputfields[i], &ncomp);
307d1bcdac9Sjeremylt         CeedChk(ierr);
3081a4ead9bSjeremylt         impl->outdata[i] = &impl->edata[i + numinputfields][e*Q*ncomp];
309885ac19cSjeremylt       }
310885ac19cSjeremylt     }
311885ac19cSjeremylt     // Q function
3124ce2993fSjeremylt     ierr = CeedQFunctionApply(qf, Q, (const CeedScalar * const*) impl->indata,
313a2b73c81Sjeremylt                               impl->outdata); CeedChk(ierr);
314885ac19cSjeremylt 
315885ac19cSjeremylt     // Output basis apply if needed
3161a4ead9bSjeremylt     for (CeedInt i=0; i<numoutputfields; i++) {
317135a076eSjeremylt       // Get elemsize, emode, ncomp
318d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opoutputfields[i], &Erestrict);
319d1bcdac9Sjeremylt       CeedChk(ierr);
320d1bcdac9Sjeremylt       ierr = CeedElemRestrictionGetElementSize(Erestrict, &elemsize);
321d1bcdac9Sjeremylt       CeedChk(ierr);
322d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode);
323d1bcdac9Sjeremylt       CeedChk(ierr);
324d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qfoutputfields[i], &ncomp);
325d1bcdac9Sjeremylt       CeedChk(ierr);
326885ac19cSjeremylt       // Basis action
327885ac19cSjeremylt       switch(emode) {
328885ac19cSjeremylt       case CEED_EVAL_NONE:
329885ac19cSjeremylt         break; // No action
330885ac19cSjeremylt       case CEED_EVAL_INTERP:
331d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opoutputfields[i], &basis);
332d1bcdac9Sjeremylt         CeedChk(ierr);
333d1bcdac9Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
334a2b73c81Sjeremylt                               CEED_EVAL_INTERP, impl->outdata[i],
3351a4ead9bSjeremylt                               &impl->edata[i + numinputfields][e*elemsize*ncomp]);
3368d94b059Sjeremylt         CeedChk(ierr);
337885ac19cSjeremylt         break;
338885ac19cSjeremylt       case CEED_EVAL_GRAD:
339d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opoutputfields[i], &basis);
340d1bcdac9Sjeremylt         CeedChk(ierr);
341d1bcdac9Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
342d1bcdac9Sjeremylt                               CEED_EVAL_GRAD, impl->outdata[i],
343d1bcdac9Sjeremylt                               &impl->edata[i + numinputfields][e*elemsize*ncomp]);
344885ac19cSjeremylt         CeedChk(ierr);
345885ac19cSjeremylt         break;
3464ce2993fSjeremylt       case CEED_EVAL_WEIGHT: {
3474ce2993fSjeremylt         Ceed ceed;
3484ce2993fSjeremylt         ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
3494ce2993fSjeremylt         return CeedError(ceed, 1,
3508d94b059Sjeremylt                          "CEED_EVAL_WEIGHT cannot be an output evaluation mode");
351885ac19cSjeremylt         break; // Should not occur
3524ce2993fSjeremylt       }
353885ac19cSjeremylt       case CEED_EVAL_DIV:
354885ac19cSjeremylt         break; // Not implimented
355885ac19cSjeremylt       case CEED_EVAL_CURL:
356885ac19cSjeremylt         break; // Not implimented
357885ac19cSjeremylt       }
358885ac19cSjeremylt     }
359885ac19cSjeremylt   }
360885ac19cSjeremylt 
36142ecf959Sjeremylt   // Zero lvecs
362d1bcdac9Sjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
363d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); CeedChk(ierr);
364d1bcdac9Sjeremylt     if (vec == CEED_VECTOR_ACTIVE)
365d1bcdac9Sjeremylt       vec = outvec;
366d1bcdac9Sjeremylt     ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
36742ecf959Sjeremylt     }
36842ecf959Sjeremylt 
369885ac19cSjeremylt   // Output restriction
3701a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
371a2b73c81Sjeremylt     // Restore evec
372a2b73c81Sjeremylt     ierr = CeedVectorRestoreArray(impl->evecs[i+impl->numein],
373d1bcdac9Sjeremylt                                   &impl->edata[i + numinputfields]);
374d1bcdac9Sjeremylt     CeedChk(ierr);
375d1bcdac9Sjeremylt     // Get output vector
376d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); CeedChk(ierr);
377668048e2SJed Brown     // Active
378d1bcdac9Sjeremylt     if (vec == CEED_VECTOR_ACTIVE)
379d1bcdac9Sjeremylt       vec = outvec;
3807ca8db16Sjeremylt     // Restrict
381d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetElemRestriction(opoutputfields[i], &Erestrict);
382d1bcdac9Sjeremylt     CeedChk(ierr);
3834dccadb6Sjeremylt     ierr = CeedOperatorFieldGetLMode(opoutputfields[i], &lmode); CeedChk(ierr);
384d1bcdac9Sjeremylt     ierr = CeedElemRestrictionApply(Erestrict, CEED_TRANSPOSE,
385d1bcdac9Sjeremylt                                     lmode, impl->evecs[i+impl->numein], vec,
386668048e2SJed Brown                                     request); CeedChk(ierr);
387885ac19cSjeremylt   }
388885ac19cSjeremylt 
3897ca8db16Sjeremylt   // Restore input arrays
3901a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
391d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
392d1bcdac9Sjeremylt     CeedChk(ierr);
393135a076eSjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
3947ca8db16Sjeremylt     } else {
395a2b73c81Sjeremylt       ierr = CeedVectorRestoreArrayRead(impl->evecs[i],
396d1bcdac9Sjeremylt                                         (const CeedScalar **) &impl->edata[i]);
397d1bcdac9Sjeremylt       CeedChk(ierr);
3987ca8db16Sjeremylt     }
3997ca8db16Sjeremylt   }
4007ca8db16Sjeremylt 
40121617c04Sjeremylt   return 0;
40221617c04Sjeremylt }
40321617c04Sjeremylt 
40421617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) {
40521617c04Sjeremylt   int ierr;
406*fe2413ffSjeremylt   Ceed ceed;
407*fe2413ffSjeremylt   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
4084ce2993fSjeremylt   CeedOperator_Ref *impl;
40921617c04Sjeremylt 
41021617c04Sjeremylt   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
411*fe2413ffSjeremylt   ierr = CeedOperatorSetData(op, (void*)&impl);
412*fe2413ffSjeremylt 
413*fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Apply",
414*fe2413ffSjeremylt                                 CeedOperatorApply_Ref); CeedChk(ierr);
415*fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Destroy",
416*fe2413ffSjeremylt                                 CeedOperatorDestroy_Ref); CeedChk(ierr);
41721617c04Sjeremylt   return 0;
41821617c04Sjeremylt }
419