xref: /libCEED/backends/ref/ceed-ref-operator.c (revision 583b1d4c382ee3afcd0623eaf06c15e7df28a1d2)
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 <ceed-impl.h>
1821617c04Sjeremylt #include <string.h>
1921617c04Sjeremylt #include "ceed-ref.h"
2021617c04Sjeremylt 
21885ac19cSjeremylt CeedElemRestriction CEED_RESTRICTION_IDENTITY = NULL;
22885ac19cSjeremylt CeedBasis CEED_BASIS_COLOCATED = NULL;
23*583b1d4cSjeremylt CeedVector CEED_VECTOR_ACTIVE = NULL;
24*583b1d4cSjeremylt CeedVector CEED_VECTOR_NONE = NULL;
25885ac19cSjeremylt 
2621617c04Sjeremylt static int CeedOperatorDestroy_Ref(CeedOperator op) {
2721617c04Sjeremylt   CeedOperator_Ref *impl = op->data;
2821617c04Sjeremylt   int ierr;
2921617c04Sjeremylt 
30885ac19cSjeremylt   for (CeedInt i=0; i<impl->numein+impl->numeout; i++) {
31885ac19cSjeremylt     ierr = CeedVectorDestroy(&impl->evecs[i]); CeedChk(ierr);
32885ac19cSjeremylt   }
33885ac19cSjeremylt   ierr = CeedFree(&impl->evecs); CeedChk(ierr);
34885ac19cSjeremylt   ierr = CeedFree(&impl->edata); CeedChk(ierr);
35885ac19cSjeremylt 
36885ac19cSjeremylt   for (CeedInt i=0; i<impl->numqin+impl->numqout; i++) {
37885ac19cSjeremylt     ierr = CeedFree(&impl->qdata_alloc[i]); CeedChk(ierr);
38885ac19cSjeremylt   }
39885ac19cSjeremylt   ierr = CeedFree(&impl->qdata_alloc); CeedChk(ierr);
40885ac19cSjeremylt   ierr = CeedFree(&impl->qdata); CeedChk(ierr);
41885ac19cSjeremylt 
42885ac19cSjeremylt   ierr = CeedFree(&impl->indata); CeedChk(ierr);
43885ac19cSjeremylt   ierr = CeedFree(&impl->outdata); CeedChk(ierr);
44885ac19cSjeremylt 
4521617c04Sjeremylt   ierr = CeedFree(&op->data); CeedChk(ierr);
4621617c04Sjeremylt   return 0;
4721617c04Sjeremylt }
4821617c04Sjeremylt 
49885ac19cSjeremylt /*
50885ac19cSjeremylt   Setup infields or outfields
51885ac19cSjeremylt  */
52885ac19cSjeremylt static int CeedOperatorSetupFields_Ref(struct CeedQFunctionField qfields[16],
53885ac19cSjeremylt                                        struct CeedOperatorField ofields[16],
54885ac19cSjeremylt                                        CeedVector *evecs, CeedScalar **qdata,
55885ac19cSjeremylt                                        CeedScalar **qdata_alloc, CeedScalar **indata,
56885ac19cSjeremylt                                        CeedInt starti, CeedInt starte,
57885ac19cSjeremylt                                        CeedInt startq, CeedInt numfields, CeedInt Q) {
58885ac19cSjeremylt   CeedInt dim, ierr, ie=starte, iq=startq, ncomp;
5921617c04Sjeremylt 
60885ac19cSjeremylt   // Loop over fields
61885ac19cSjeremylt   for (CeedInt i=0; i<numfields; i++) {
62885ac19cSjeremylt     if (ofields[i].Erestrict) {
63885ac19cSjeremylt       ierr = CeedElemRestrictionCreateVector(ofields[i].Erestrict, NULL, &evecs[ie]);
6421617c04Sjeremylt       CeedChk(ierr);
65885ac19cSjeremylt       ie++;
6621617c04Sjeremylt     }
67885ac19cSjeremylt     CeedEvalMode emode = qfields[i].emode;
68885ac19cSjeremylt     switch(emode) {
69885ac19cSjeremylt     case CEED_EVAL_NONE:
70885ac19cSjeremylt       break; // No action
71885ac19cSjeremylt     case CEED_EVAL_INTERP:
72885ac19cSjeremylt       ncomp = qfields[i].ncomp;
73885ac19cSjeremylt       ierr = CeedMalloc(Q*ncomp, &qdata_alloc[iq]); CeedChk(ierr);
74885ac19cSjeremylt       qdata[i + starti] = qdata_alloc[iq];
75885ac19cSjeremylt       iq++;
76885ac19cSjeremylt       break;
77885ac19cSjeremylt     case CEED_EVAL_GRAD:
78885ac19cSjeremylt       ncomp = qfields[i].ncomp;
79885ac19cSjeremylt       dim = ofields[i].basis->dim;
80885ac19cSjeremylt       ierr = CeedMalloc(Q*ncomp*dim, &qdata_alloc[iq]); CeedChk(ierr);
81885ac19cSjeremylt       qdata[i + starti] = qdata_alloc[iq];
82885ac19cSjeremylt       iq++;
83885ac19cSjeremylt       break;
84885ac19cSjeremylt     case CEED_EVAL_WEIGHT: // Only on input fields
85885ac19cSjeremylt       ierr = CeedMalloc(Q, &qdata_alloc[iq]); CeedChk(ierr);
86885ac19cSjeremylt       ierr = CeedBasisApply(ofields[iq].basis, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT,
87885ac19cSjeremylt                             NULL, qdata_alloc[iq]); CeedChk(ierr);
88885ac19cSjeremylt       qdata[i] = qdata_alloc[iq];
89885ac19cSjeremylt       indata[i] = qdata[i];
90885ac19cSjeremylt       iq++;
91885ac19cSjeremylt       break;
92885ac19cSjeremylt     case CEED_EVAL_DIV:
93885ac19cSjeremylt       break; // Not implimented
94885ac19cSjeremylt     case CEED_EVAL_CURL:
95885ac19cSjeremylt       break; // Not implimented
9621617c04Sjeremylt     }
97885ac19cSjeremylt   }
9821617c04Sjeremylt   return 0;
9921617c04Sjeremylt }
10021617c04Sjeremylt 
101885ac19cSjeremylt /*
102885ac19cSjeremylt   CeedOperator needs to connect all the named fields (be they active or passive)
103885ac19cSjeremylt   to the named inputs and outputs of its CeedQFunction.
104885ac19cSjeremylt  */
105885ac19cSjeremylt static int CeedOperatorSetup_Ref(CeedOperator op) {
106885ac19cSjeremylt   if (op->setupdone) return 0;
107885ac19cSjeremylt   CeedOperator_Ref *opref = op->data;
108885ac19cSjeremylt   CeedQFunction qf = op->qf;
109885ac19cSjeremylt   CeedInt Q = op->numqpoints;
11021617c04Sjeremylt   int ierr;
11121617c04Sjeremylt 
112885ac19cSjeremylt   // Count infield and outfield array sizes and evectors
113885ac19cSjeremylt   for (CeedInt i=0; i<qf->numinputfields; i++) {
114885ac19cSjeremylt     CeedEvalMode emode = qf->inputfields[i].emode;
115885ac19cSjeremylt     opref->numqin += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD) + !!
116885ac19cSjeremylt                      (emode & CEED_EVAL_WEIGHT);
117885ac19cSjeremylt     opref->numein +=
118885ac19cSjeremylt       !!op->inputfields[i].Erestrict; // Need E-vector when restriction exists
11921617c04Sjeremylt   }
120885ac19cSjeremylt   for (CeedInt i=0; i<qf->numoutputfields; i++) {
121885ac19cSjeremylt     CeedEvalMode emode = qf->outputfields[i].emode;
122885ac19cSjeremylt     opref->numqout += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD);
123885ac19cSjeremylt     opref->numeout += !!op->outputfields[i].Erestrict;
124885ac19cSjeremylt   }
125885ac19cSjeremylt 
126885ac19cSjeremylt   // Allocate
127885ac19cSjeremylt   ierr = CeedCalloc(opref->numein + opref->numeout, &opref->evecs); CeedChk(ierr);
128885ac19cSjeremylt   ierr = CeedCalloc(qf->numinputfields + qf->numoutputfields, &opref->edata);
129885ac19cSjeremylt   CeedChk(ierr);
130885ac19cSjeremylt 
131885ac19cSjeremylt   ierr = CeedCalloc(opref->numqin + opref->numqout, &opref->qdata_alloc);
132885ac19cSjeremylt   CeedChk(ierr);
133885ac19cSjeremylt   ierr = CeedCalloc(qf->numinputfields + qf->numoutputfields, &opref->qdata);
134885ac19cSjeremylt   CeedChk(ierr);
135885ac19cSjeremylt 
136885ac19cSjeremylt   ierr = CeedCalloc(16, &opref->indata); CeedChk(ierr);
137885ac19cSjeremylt   ierr = CeedCalloc(16, &opref->outdata); CeedChk(ierr);
138885ac19cSjeremylt 
139885ac19cSjeremylt   // Set up infield and outfield pointer arrays
140885ac19cSjeremylt   // Infields
141885ac19cSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf->inputfields, op->inputfields,
142885ac19cSjeremylt                                      opref->evecs, opref->qdata, opref->qdata_alloc,
143885ac19cSjeremylt                                      opref->indata, 0, 0, 0,
144885ac19cSjeremylt                                      qf->numinputfields, Q); CeedChk(ierr);
145885ac19cSjeremylt 
146885ac19cSjeremylt   // Outfields
147885ac19cSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf->outputfields, op->outputfields,
148885ac19cSjeremylt                                      opref->evecs, opref->qdata, opref->qdata_alloc,
149885ac19cSjeremylt                                      opref->indata, qf->numinputfields, opref->numein,
150885ac19cSjeremylt                                      opref->numqin, qf->numoutputfields, Q); CeedChk(ierr);
151885ac19cSjeremylt 
152885ac19cSjeremylt   op->setupdone = 1;
153885ac19cSjeremylt 
154885ac19cSjeremylt   return 0;
155885ac19cSjeremylt }
156885ac19cSjeremylt 
157885ac19cSjeremylt static int CeedOperatorApply_Ref(CeedOperator op, CeedVector invec,
158885ac19cSjeremylt                                  CeedVector outvec, CeedRequest *request) {
159885ac19cSjeremylt   CeedOperator_Ref *opref = op->data;
160885ac19cSjeremylt   CeedInt Q = op->numqpoints, elemsize;
161885ac19cSjeremylt   int ierr;
162885ac19cSjeremylt   CeedQFunction qf = op->qf;
163885ac19cSjeremylt   CeedTransposeMode lmode = CEED_NOTRANSPOSE;
164885ac19cSjeremylt 
165885ac19cSjeremylt   // Setup
166885ac19cSjeremylt   ierr = CeedOperatorSetup_Ref(op); CeedChk(ierr);
167885ac19cSjeremylt 
168885ac19cSjeremylt   // Input Evecs and Restriction
169885ac19cSjeremylt   for (CeedInt i=0,iein=0; i<qf->numinputfields; i++) {
170885ac19cSjeremylt     // Restriction
171885ac19cSjeremylt     if (op->inputfields[i].Erestrict) {
172885ac19cSjeremylt       // Passive
173885ac19cSjeremylt       if (op->inputfields[i].vec) {
174885ac19cSjeremylt         ierr = CeedElemRestrictionApply(op->inputfields[i].Erestrict, CEED_NOTRANSPOSE,
175885ac19cSjeremylt                                         lmode, op->inputfields[i].vec, opref->evecs[iein],
176885ac19cSjeremylt                                         request); CeedChk(ierr);
177885ac19cSjeremylt         ierr = CeedVectorGetArrayRead(opref->evecs[iein], CEED_MEM_HOST,
178885ac19cSjeremylt                                       (const CeedScalar **) &opref->edata[i]); CeedChk(ierr);
179885ac19cSjeremylt         iein++;
180885ac19cSjeremylt       } else {
181885ac19cSjeremylt         // Active
182885ac19cSjeremylt         ierr = CeedElemRestrictionApply(op->inputfields[i].Erestrict, CEED_NOTRANSPOSE,
183885ac19cSjeremylt                                         lmode, invec, opref->evecs[iein], request); CeedChk(ierr);
184885ac19cSjeremylt         ierr = CeedVectorGetArrayRead(opref->evecs[iein], CEED_MEM_HOST,
185885ac19cSjeremylt                                       (const CeedScalar **) &opref->edata[i]); CeedChk(ierr);
186885ac19cSjeremylt         iein++;
187885ac19cSjeremylt       }
188885ac19cSjeremylt     } else {
189885ac19cSjeremylt       // No restriction
190885ac19cSjeremylt       CeedEvalMode emode = qf->inputfields[i].emode;
191885ac19cSjeremylt       if (emode & CEED_EVAL_WEIGHT) {
192885ac19cSjeremylt       } else {
193885ac19cSjeremylt         ierr = CeedVectorGetArrayRead(op->inputfields[i].vec, CEED_MEM_HOST,
194885ac19cSjeremylt                                       (const CeedScalar **) &opref->edata[i]); CeedChk(ierr);
195885ac19cSjeremylt       }
196885ac19cSjeremylt     }
197885ac19cSjeremylt   }
198885ac19cSjeremylt 
199885ac19cSjeremylt   // Output Evecs
200885ac19cSjeremylt   for (CeedInt i=0,ieout=opref->numein; i<qf->numoutputfields; i++) {
201885ac19cSjeremylt     // Restriction
202885ac19cSjeremylt     if (op->outputfields[i].Erestrict) {
203885ac19cSjeremylt       ierr = CeedVectorGetArray(opref->evecs[ieout], CEED_MEM_HOST,
204885ac19cSjeremylt                                 &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
205885ac19cSjeremylt       ieout++;
206885ac19cSjeremylt     } else {
207885ac19cSjeremylt       // No restriction
208885ac19cSjeremylt       // Passive
209885ac19cSjeremylt       if (op->inputfields[i].vec) {
210885ac19cSjeremylt         ierr = CeedVectorGetArray(op->inputfields[i].vec, CEED_MEM_HOST,
211885ac19cSjeremylt                                   &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
212885ac19cSjeremylt       } else {
213885ac19cSjeremylt         // Active
214885ac19cSjeremylt         ierr = CeedVectorGetArray(outvec, CEED_MEM_HOST,
215885ac19cSjeremylt                                   &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
216885ac19cSjeremylt       }
217885ac19cSjeremylt     }
218885ac19cSjeremylt   }
219885ac19cSjeremylt 
220885ac19cSjeremylt   // Output Qvecs
221885ac19cSjeremylt   for (CeedInt i=0; i<qf->numoutputfields; i++) {
222885ac19cSjeremylt     CeedEvalMode emode = qf->outputfields[i].emode;
223885ac19cSjeremylt     if (emode != CEED_EVAL_NONE) {
224885ac19cSjeremylt       opref->outdata[i] =  opref->qdata[i + qf->numinputfields];
225885ac19cSjeremylt     }
226885ac19cSjeremylt   }
227885ac19cSjeremylt 
228885ac19cSjeremylt   // Loop through elements
229885ac19cSjeremylt   for (CeedInt e=0; e<op->numelements; e++) {
230885ac19cSjeremylt     // Input basis apply if needed
231885ac19cSjeremylt     for (CeedInt i=0; i<qf->numinputfields; i++) {
232885ac19cSjeremylt       // Get elemsize
233885ac19cSjeremylt       if (op->inputfields[i].Erestrict) {
234885ac19cSjeremylt         elemsize = op->inputfields[i].Erestrict->elemsize;
235885ac19cSjeremylt       } else {
236885ac19cSjeremylt         elemsize = Q;
237885ac19cSjeremylt       }
238885ac19cSjeremylt       // Get emode, ncomp
239885ac19cSjeremylt       CeedEvalMode emode = qf->inputfields[i].emode;
240885ac19cSjeremylt       CeedInt ncomp = qf->inputfields[i].ncomp;
241885ac19cSjeremylt       // Basis action
242885ac19cSjeremylt       switch(emode) {
243885ac19cSjeremylt       case CEED_EVAL_NONE:
244885ac19cSjeremylt         opref->indata[i] = &opref->edata[i][e*Q*ncomp];
245885ac19cSjeremylt         break;
246885ac19cSjeremylt       case CEED_EVAL_INTERP:
247885ac19cSjeremylt         ierr = CeedBasisApply(op->inputfields[i].basis, CEED_NOTRANSPOSE,
248885ac19cSjeremylt                               CEED_EVAL_INTERP, &opref->edata[i][e*elemsize*ncomp], opref->qdata[i]);
249885ac19cSjeremylt         CeedChk(ierr);
250885ac19cSjeremylt         opref->indata[i] = opref->qdata[i];
251885ac19cSjeremylt         break;
252885ac19cSjeremylt       case CEED_EVAL_GRAD:
253885ac19cSjeremylt         ierr = CeedBasisApply(op->inputfields[i].basis, CEED_NOTRANSPOSE,
254885ac19cSjeremylt                               CEED_EVAL_GRAD, &opref->edata[i][e*elemsize*ncomp], opref->qdata[i]);
255885ac19cSjeremylt         CeedChk(ierr);
256885ac19cSjeremylt         opref->indata[i] = opref->qdata[i];
257885ac19cSjeremylt         break;
258885ac19cSjeremylt       case CEED_EVAL_WEIGHT:
259885ac19cSjeremylt         break;  // No action
260885ac19cSjeremylt       case CEED_EVAL_DIV:
261885ac19cSjeremylt         break; // Not implimented
262885ac19cSjeremylt       case CEED_EVAL_CURL:
263885ac19cSjeremylt         break; // Not implimented
264885ac19cSjeremylt       }
265885ac19cSjeremylt     }
266885ac19cSjeremylt     // Output pointers
267885ac19cSjeremylt     for (CeedInt i=0; i<qf->numoutputfields; i++) {
268885ac19cSjeremylt       CeedEvalMode emode = qf->outputfields[i].emode;
269885ac19cSjeremylt       if (emode == CEED_EVAL_NONE) {
270885ac19cSjeremylt         CeedInt ncomp = qf->outputfields[i].ncomp;
271885ac19cSjeremylt         opref->outdata[i] = &opref->edata[i + qf->numinputfields][e*Q*ncomp];
272885ac19cSjeremylt       }
273885ac19cSjeremylt     }
274885ac19cSjeremylt     // Q function
275885ac19cSjeremylt     ierr = CeedQFunctionApply(op->qf, Q, (const CeedScalar * const*) opref->indata,
276885ac19cSjeremylt                               opref->outdata); CeedChk(ierr);
277885ac19cSjeremylt 
278885ac19cSjeremylt     // Output basis apply if needed
279885ac19cSjeremylt     for (CeedInt i=0; i<qf->numoutputfields; i++) {
280885ac19cSjeremylt       // Get elemsize
281885ac19cSjeremylt       if (op->outputfields[i].Erestrict) {
282885ac19cSjeremylt         elemsize = op->outputfields[i].Erestrict->elemsize;
283885ac19cSjeremylt       } else {
284885ac19cSjeremylt         elemsize = Q;
285885ac19cSjeremylt       }
286885ac19cSjeremylt       // Get emode, ncomp
287885ac19cSjeremylt       CeedInt ncomp = qf->outputfields[i].ncomp;
288885ac19cSjeremylt       CeedEvalMode emode = qf->outputfields[i].emode;
289885ac19cSjeremylt       // Basis action
290885ac19cSjeremylt       switch(emode) {
291885ac19cSjeremylt       case CEED_EVAL_NONE:
292885ac19cSjeremylt         break; // No action
293885ac19cSjeremylt       case CEED_EVAL_INTERP:
294885ac19cSjeremylt         ierr = CeedBasisApply(op->outputfields[i].basis, CEED_TRANSPOSE,
295885ac19cSjeremylt                               CEED_EVAL_INTERP, opref->outdata[i],
296885ac19cSjeremylt                               &opref->edata[i + qf->numinputfields][e*elemsize*ncomp]); CeedChk(ierr);
297885ac19cSjeremylt         break;
298885ac19cSjeremylt       case CEED_EVAL_GRAD:
299885ac19cSjeremylt         ierr = CeedBasisApply(op->outputfields[i].basis, CEED_TRANSPOSE, CEED_EVAL_GRAD,
300885ac19cSjeremylt                               opref->outdata[i], &opref->edata[i + qf->numinputfields][e*elemsize*ncomp]);
301885ac19cSjeremylt         CeedChk(ierr);
302885ac19cSjeremylt         break;
303885ac19cSjeremylt       case CEED_EVAL_WEIGHT:
304885ac19cSjeremylt         break; // Should not occur
305885ac19cSjeremylt       case CEED_EVAL_DIV:
306885ac19cSjeremylt         break; // Not implimented
307885ac19cSjeremylt       case CEED_EVAL_CURL:
308885ac19cSjeremylt         break; // Not implimented
309885ac19cSjeremylt       }
310885ac19cSjeremylt     }
311885ac19cSjeremylt   }
312885ac19cSjeremylt 
313885ac19cSjeremylt   // Output restriction
314885ac19cSjeremylt   for (CeedInt i=0,ieout=opref->numein; i<qf->numoutputfields; i++) {
315885ac19cSjeremylt     // Restriction
316885ac19cSjeremylt     if (op->outputfields[i].Erestrict) {
317885ac19cSjeremylt       // Passive
318885ac19cSjeremylt       if (op->outputfields[i].vec) {
319885ac19cSjeremylt         ierr = CeedVectorRestoreArray(opref->evecs[ieout],
320885ac19cSjeremylt                                       &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
321885ac19cSjeremylt         ierr = CeedElemRestrictionApply(op->outputfields[i].Erestrict, CEED_TRANSPOSE,
322885ac19cSjeremylt                                         lmode, opref->evecs[ieout], op->outputfields[i].vec, request); CeedChk(ierr);
323885ac19cSjeremylt         ieout++;
324885ac19cSjeremylt       } else {
325885ac19cSjeremylt         // Active
326885ac19cSjeremylt         ierr = CeedVectorRestoreArray(opref->evecs[ieout],
327885ac19cSjeremylt                                       &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
328885ac19cSjeremylt         ierr = CeedElemRestrictionApply(op->outputfields[i].Erestrict, CEED_TRANSPOSE,
329885ac19cSjeremylt                                         lmode, opref->evecs[ieout], outvec, request); CeedChk(ierr);
330885ac19cSjeremylt         ieout++;
331885ac19cSjeremylt       }
332885ac19cSjeremylt     } else {
333885ac19cSjeremylt       // No Restriction
334885ac19cSjeremylt       // Passive
335885ac19cSjeremylt       if (op->outputfields[i].vec) {
336885ac19cSjeremylt         ierr = CeedVectorRestoreArray(op->outputfields[i].vec,
337885ac19cSjeremylt                                       &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
338885ac19cSjeremylt       } else {
339885ac19cSjeremylt         // Active
340885ac19cSjeremylt         ierr = CeedVectorRestoreArray(outvec, &opref->edata[i + qf->numinputfields]);
341885ac19cSjeremylt         CeedChk(ierr);
342885ac19cSjeremylt       }
343885ac19cSjeremylt     }
344885ac19cSjeremylt   }
345885ac19cSjeremylt 
34621617c04Sjeremylt   return 0;
34721617c04Sjeremylt }
34821617c04Sjeremylt 
34921617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) {
35021617c04Sjeremylt   CeedOperator_Ref *impl;
35121617c04Sjeremylt   int ierr;
35221617c04Sjeremylt 
35321617c04Sjeremylt   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
35421617c04Sjeremylt   op->data = impl;
35521617c04Sjeremylt   op->Destroy = CeedOperatorDestroy_Ref;
35621617c04Sjeremylt   op->Apply = CeedOperatorApply_Ref;
35721617c04Sjeremylt   return 0;
35821617c04Sjeremylt }
359