xref: /libCEED/backends/ref/ceed-ref-operator.c (revision 885ac19c71404eabce0bdaffc144734a44d512ec)
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 
21*885ac19cSjeremylt CeedElemRestriction CEED_RESTRICTION_IDENTITY = NULL;
22*885ac19cSjeremylt CeedBasis CEED_BASIS_COLOCATED = NULL;
23*885ac19cSjeremylt CeedVector CEED_QDATA_NONE = NULL;
24*885ac19cSjeremylt 
2521617c04Sjeremylt static int CeedOperatorDestroy_Ref(CeedOperator op) {
2621617c04Sjeremylt   CeedOperator_Ref *impl = op->data;
2721617c04Sjeremylt   int ierr;
2821617c04Sjeremylt 
29*885ac19cSjeremylt   for (CeedInt i=0; i<impl->numein+impl->numeout; i++) {
30*885ac19cSjeremylt     ierr = CeedVectorDestroy(&impl->evecs[i]); CeedChk(ierr);
31*885ac19cSjeremylt   }
32*885ac19cSjeremylt   ierr = CeedFree(&impl->evecs); CeedChk(ierr);
33*885ac19cSjeremylt   ierr = CeedFree(&impl->edata); CeedChk(ierr);
34*885ac19cSjeremylt 
35*885ac19cSjeremylt   for (CeedInt i=0; i<impl->numqin+impl->numqout; i++) {
36*885ac19cSjeremylt     ierr = CeedFree(&impl->qdata_alloc[i]); CeedChk(ierr);
37*885ac19cSjeremylt   }
38*885ac19cSjeremylt   ierr = CeedFree(&impl->qdata_alloc); CeedChk(ierr);
39*885ac19cSjeremylt   ierr = CeedFree(&impl->qdata); CeedChk(ierr);
40*885ac19cSjeremylt 
41*885ac19cSjeremylt   ierr = CeedFree(&impl->indata); CeedChk(ierr);
42*885ac19cSjeremylt   ierr = CeedFree(&impl->outdata); CeedChk(ierr);
43*885ac19cSjeremylt 
4421617c04Sjeremylt   ierr = CeedFree(&op->data); CeedChk(ierr);
4521617c04Sjeremylt   return 0;
4621617c04Sjeremylt }
4721617c04Sjeremylt 
48*885ac19cSjeremylt /*
49*885ac19cSjeremylt   Setup infields or outfields
50*885ac19cSjeremylt  */
51*885ac19cSjeremylt static int CeedOperatorSetupFields_Ref(struct CeedQFunctionField qfields[16],
52*885ac19cSjeremylt                                        struct CeedOperatorField ofields[16],
53*885ac19cSjeremylt                                        CeedVector *evecs, CeedScalar **qdata,
54*885ac19cSjeremylt                                        CeedScalar **qdata_alloc, CeedScalar **indata,
55*885ac19cSjeremylt                                        CeedInt starti, CeedInt starte,
56*885ac19cSjeremylt                                        CeedInt startq, CeedInt numfields, CeedInt Q) {
57*885ac19cSjeremylt   CeedInt dim, ierr, ie=starte, iq=startq, ncomp;
5821617c04Sjeremylt 
59*885ac19cSjeremylt   // Loop over fields
60*885ac19cSjeremylt   for (CeedInt i=0; i<numfields; i++) {
61*885ac19cSjeremylt     if (ofields[i].Erestrict) {
62*885ac19cSjeremylt       ierr = CeedElemRestrictionCreateVector(ofields[i].Erestrict, NULL, &evecs[ie]);
6321617c04Sjeremylt       CeedChk(ierr);
64*885ac19cSjeremylt       ie++;
6521617c04Sjeremylt     }
66*885ac19cSjeremylt     CeedEvalMode emode = qfields[i].emode;
67*885ac19cSjeremylt     switch(emode) {
68*885ac19cSjeremylt     case CEED_EVAL_NONE:
69*885ac19cSjeremylt       break; // No action
70*885ac19cSjeremylt     case CEED_EVAL_INTERP:
71*885ac19cSjeremylt       ncomp = qfields[i].ncomp;
72*885ac19cSjeremylt       ierr = CeedMalloc(Q*ncomp, &qdata_alloc[iq]); CeedChk(ierr);
73*885ac19cSjeremylt       qdata[i + starti] = qdata_alloc[iq];
74*885ac19cSjeremylt       iq++;
75*885ac19cSjeremylt       break;
76*885ac19cSjeremylt     case CEED_EVAL_GRAD:
77*885ac19cSjeremylt       ncomp = qfields[i].ncomp;
78*885ac19cSjeremylt       dim = ofields[i].basis->dim;
79*885ac19cSjeremylt       ierr = CeedMalloc(Q*ncomp*dim, &qdata_alloc[iq]); CeedChk(ierr);
80*885ac19cSjeremylt       qdata[i + starti] = qdata_alloc[iq];
81*885ac19cSjeremylt       iq++;
82*885ac19cSjeremylt       break;
83*885ac19cSjeremylt     case CEED_EVAL_WEIGHT: // Only on input fields
84*885ac19cSjeremylt       ierr = CeedMalloc(Q, &qdata_alloc[iq]); CeedChk(ierr);
85*885ac19cSjeremylt       ierr = CeedBasisApply(ofields[iq].basis, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT,
86*885ac19cSjeremylt                             NULL, qdata_alloc[iq]); CeedChk(ierr);
87*885ac19cSjeremylt       qdata[i] = qdata_alloc[iq];
88*885ac19cSjeremylt       indata[i] = qdata[i];
89*885ac19cSjeremylt       iq++;
90*885ac19cSjeremylt       break;
91*885ac19cSjeremylt     case CEED_EVAL_DIV:
92*885ac19cSjeremylt       break; // Not implimented
93*885ac19cSjeremylt     case CEED_EVAL_CURL:
94*885ac19cSjeremylt       break; // Not implimented
9521617c04Sjeremylt     }
96*885ac19cSjeremylt   }
9721617c04Sjeremylt   return 0;
9821617c04Sjeremylt }
9921617c04Sjeremylt 
100*885ac19cSjeremylt /*
101*885ac19cSjeremylt   CeedOperator needs to connect all the named fields (be they active or passive)
102*885ac19cSjeremylt   to the named inputs and outputs of its CeedQFunction.
103*885ac19cSjeremylt  */
104*885ac19cSjeremylt static int CeedOperatorSetup_Ref(CeedOperator op) {
105*885ac19cSjeremylt   if (op->setupdone) return 0;
106*885ac19cSjeremylt   CeedOperator_Ref *opref = op->data;
107*885ac19cSjeremylt   CeedQFunction qf = op->qf;
108*885ac19cSjeremylt   CeedInt Q = op->numqpoints;
10921617c04Sjeremylt   int ierr;
11021617c04Sjeremylt 
111*885ac19cSjeremylt   // Count infield and outfield array sizes and evectors
112*885ac19cSjeremylt   for (CeedInt i=0; i<qf->numinputfields; i++) {
113*885ac19cSjeremylt     CeedEvalMode emode = qf->inputfields[i].emode;
114*885ac19cSjeremylt     opref->numqin += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD) + !!
115*885ac19cSjeremylt                      (emode & CEED_EVAL_WEIGHT);
116*885ac19cSjeremylt     opref->numein +=
117*885ac19cSjeremylt       !!op->inputfields[i].Erestrict; // Need E-vector when restriction exists
11821617c04Sjeremylt   }
119*885ac19cSjeremylt   for (CeedInt i=0; i<qf->numoutputfields; i++) {
120*885ac19cSjeremylt     CeedEvalMode emode = qf->outputfields[i].emode;
121*885ac19cSjeremylt     opref->numqout += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD);
122*885ac19cSjeremylt     opref->numeout += !!op->outputfields[i].Erestrict;
123*885ac19cSjeremylt   }
124*885ac19cSjeremylt 
125*885ac19cSjeremylt   // Allocate
126*885ac19cSjeremylt   ierr = CeedCalloc(opref->numein + opref->numeout, &opref->evecs); CeedChk(ierr);
127*885ac19cSjeremylt   ierr = CeedCalloc(qf->numinputfields + qf->numoutputfields, &opref->edata);
128*885ac19cSjeremylt   CeedChk(ierr);
129*885ac19cSjeremylt 
130*885ac19cSjeremylt   ierr = CeedCalloc(opref->numqin + opref->numqout, &opref->qdata_alloc);
131*885ac19cSjeremylt   CeedChk(ierr);
132*885ac19cSjeremylt   ierr = CeedCalloc(qf->numinputfields + qf->numoutputfields, &opref->qdata);
133*885ac19cSjeremylt   CeedChk(ierr);
134*885ac19cSjeremylt 
135*885ac19cSjeremylt   ierr = CeedCalloc(16, &opref->indata); CeedChk(ierr);
136*885ac19cSjeremylt   ierr = CeedCalloc(16, &opref->outdata); CeedChk(ierr);
137*885ac19cSjeremylt 
138*885ac19cSjeremylt   // Set up infield and outfield pointer arrays
139*885ac19cSjeremylt   // Infields
140*885ac19cSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf->inputfields, op->inputfields,
141*885ac19cSjeremylt                                      opref->evecs, opref->qdata, opref->qdata_alloc,
142*885ac19cSjeremylt                                      opref->indata, 0, 0, 0,
143*885ac19cSjeremylt                                      qf->numinputfields, Q); CeedChk(ierr);
144*885ac19cSjeremylt 
145*885ac19cSjeremylt   // Outfields
146*885ac19cSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf->outputfields, op->outputfields,
147*885ac19cSjeremylt                                      opref->evecs, opref->qdata, opref->qdata_alloc,
148*885ac19cSjeremylt                                      opref->indata, qf->numinputfields, opref->numein,
149*885ac19cSjeremylt                                      opref->numqin, qf->numoutputfields, Q); CeedChk(ierr);
150*885ac19cSjeremylt 
151*885ac19cSjeremylt   op->setupdone = 1;
152*885ac19cSjeremylt 
153*885ac19cSjeremylt   return 0;
154*885ac19cSjeremylt }
155*885ac19cSjeremylt 
156*885ac19cSjeremylt static int CeedOperatorApply_Ref(CeedOperator op, CeedVector invec,
157*885ac19cSjeremylt                                  CeedVector outvec, CeedRequest *request) {
158*885ac19cSjeremylt   CeedOperator_Ref *opref = op->data;
159*885ac19cSjeremylt   CeedInt Q = op->numqpoints, elemsize;
160*885ac19cSjeremylt   int ierr;
161*885ac19cSjeremylt   CeedQFunction qf = op->qf;
162*885ac19cSjeremylt   CeedTransposeMode lmode = CEED_NOTRANSPOSE;
163*885ac19cSjeremylt 
164*885ac19cSjeremylt   // Setup
165*885ac19cSjeremylt   ierr = CeedOperatorSetup_Ref(op); CeedChk(ierr);
166*885ac19cSjeremylt 
167*885ac19cSjeremylt   // Input Evecs and Restriction
168*885ac19cSjeremylt   for (CeedInt i=0,iein=0; i<qf->numinputfields; i++) {
169*885ac19cSjeremylt     // Restriction
170*885ac19cSjeremylt     if (op->inputfields[i].Erestrict) {
171*885ac19cSjeremylt       // Passive
172*885ac19cSjeremylt       if (op->inputfields[i].vec) {
173*885ac19cSjeremylt         ierr = CeedElemRestrictionApply(op->inputfields[i].Erestrict, CEED_NOTRANSPOSE,
174*885ac19cSjeremylt                                         lmode, op->inputfields[i].vec, opref->evecs[iein],
175*885ac19cSjeremylt                                         request); CeedChk(ierr);
176*885ac19cSjeremylt         ierr = CeedVectorGetArrayRead(opref->evecs[iein], CEED_MEM_HOST,
177*885ac19cSjeremylt                                       (const CeedScalar **) &opref->edata[i]); CeedChk(ierr);
178*885ac19cSjeremylt         iein++;
179*885ac19cSjeremylt       } else {
180*885ac19cSjeremylt         // Active
181*885ac19cSjeremylt         ierr = CeedElemRestrictionApply(op->inputfields[i].Erestrict, CEED_NOTRANSPOSE,
182*885ac19cSjeremylt                                         lmode, invec, opref->evecs[iein], request); CeedChk(ierr);
183*885ac19cSjeremylt         ierr = CeedVectorGetArrayRead(opref->evecs[iein], CEED_MEM_HOST,
184*885ac19cSjeremylt                                       (const CeedScalar **) &opref->edata[i]); CeedChk(ierr);
185*885ac19cSjeremylt         iein++;
186*885ac19cSjeremylt       }
187*885ac19cSjeremylt     } else {
188*885ac19cSjeremylt       // No restriction
189*885ac19cSjeremylt       CeedEvalMode emode = qf->inputfields[i].emode;
190*885ac19cSjeremylt       if (emode & CEED_EVAL_WEIGHT) {
191*885ac19cSjeremylt       } else {
192*885ac19cSjeremylt         ierr = CeedVectorGetArrayRead(op->inputfields[i].vec, CEED_MEM_HOST,
193*885ac19cSjeremylt                                       (const CeedScalar **) &opref->edata[i]); CeedChk(ierr);
194*885ac19cSjeremylt       }
195*885ac19cSjeremylt     }
196*885ac19cSjeremylt   }
197*885ac19cSjeremylt 
198*885ac19cSjeremylt   // Output Evecs
199*885ac19cSjeremylt   for (CeedInt i=0,ieout=opref->numein; i<qf->numoutputfields; i++) {
200*885ac19cSjeremylt     // Restriction
201*885ac19cSjeremylt     if (op->outputfields[i].Erestrict) {
202*885ac19cSjeremylt       ierr = CeedVectorGetArray(opref->evecs[ieout], CEED_MEM_HOST,
203*885ac19cSjeremylt                                 &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
204*885ac19cSjeremylt       ieout++;
205*885ac19cSjeremylt     } else {
206*885ac19cSjeremylt       // No restriction
207*885ac19cSjeremylt       // Passive
208*885ac19cSjeremylt       if (op->inputfields[i].vec) {
209*885ac19cSjeremylt         ierr = CeedVectorGetArray(op->inputfields[i].vec, CEED_MEM_HOST,
210*885ac19cSjeremylt                                   &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
211*885ac19cSjeremylt       } else {
212*885ac19cSjeremylt         // Active
213*885ac19cSjeremylt         ierr = CeedVectorGetArray(outvec, CEED_MEM_HOST,
214*885ac19cSjeremylt                                   &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
215*885ac19cSjeremylt       }
216*885ac19cSjeremylt     }
217*885ac19cSjeremylt   }
218*885ac19cSjeremylt 
219*885ac19cSjeremylt   // Output Qvecs
220*885ac19cSjeremylt   for (CeedInt i=0; i<qf->numoutputfields; i++) {
221*885ac19cSjeremylt     CeedEvalMode emode = qf->outputfields[i].emode;
222*885ac19cSjeremylt     if (emode != CEED_EVAL_NONE) {
223*885ac19cSjeremylt       opref->outdata[i] =  opref->qdata[i + qf->numinputfields];
224*885ac19cSjeremylt     }
225*885ac19cSjeremylt   }
226*885ac19cSjeremylt 
227*885ac19cSjeremylt   // Loop through elements
228*885ac19cSjeremylt   for (CeedInt e=0; e<op->numelements; e++) {
229*885ac19cSjeremylt     // Input basis apply if needed
230*885ac19cSjeremylt     for (CeedInt i=0; i<qf->numinputfields; i++) {
231*885ac19cSjeremylt       // Get elemsize
232*885ac19cSjeremylt       if (op->inputfields[i].Erestrict) {
233*885ac19cSjeremylt         elemsize = op->inputfields[i].Erestrict->elemsize;
234*885ac19cSjeremylt       } else {
235*885ac19cSjeremylt         elemsize = Q;
236*885ac19cSjeremylt       }
237*885ac19cSjeremylt       // Get emode, ncomp
238*885ac19cSjeremylt       CeedEvalMode emode = qf->inputfields[i].emode;
239*885ac19cSjeremylt       CeedInt ncomp = qf->inputfields[i].ncomp;
240*885ac19cSjeremylt       // Basis action
241*885ac19cSjeremylt       switch(emode) {
242*885ac19cSjeremylt       case CEED_EVAL_NONE:
243*885ac19cSjeremylt         opref->indata[i] = &opref->edata[i][e*Q*ncomp];
244*885ac19cSjeremylt         break;
245*885ac19cSjeremylt       case CEED_EVAL_INTERP:
246*885ac19cSjeremylt         ierr = CeedBasisApply(op->inputfields[i].basis, CEED_NOTRANSPOSE,
247*885ac19cSjeremylt                               CEED_EVAL_INTERP, &opref->edata[i][e*elemsize*ncomp], opref->qdata[i]);
248*885ac19cSjeremylt         CeedChk(ierr);
249*885ac19cSjeremylt         opref->indata[i] = opref->qdata[i];
250*885ac19cSjeremylt         break;
251*885ac19cSjeremylt       case CEED_EVAL_GRAD:
252*885ac19cSjeremylt         ierr = CeedBasisApply(op->inputfields[i].basis, CEED_NOTRANSPOSE,
253*885ac19cSjeremylt                               CEED_EVAL_GRAD, &opref->edata[i][e*elemsize*ncomp], opref->qdata[i]);
254*885ac19cSjeremylt         CeedChk(ierr);
255*885ac19cSjeremylt         opref->indata[i] = opref->qdata[i];
256*885ac19cSjeremylt         break;
257*885ac19cSjeremylt       case CEED_EVAL_WEIGHT:
258*885ac19cSjeremylt         break;  // No action
259*885ac19cSjeremylt       case CEED_EVAL_DIV:
260*885ac19cSjeremylt         break; // Not implimented
261*885ac19cSjeremylt       case CEED_EVAL_CURL:
262*885ac19cSjeremylt         break; // Not implimented
263*885ac19cSjeremylt       }
264*885ac19cSjeremylt     }
265*885ac19cSjeremylt     // Output pointers
266*885ac19cSjeremylt     for (CeedInt i=0; i<qf->numoutputfields; i++) {
267*885ac19cSjeremylt       CeedEvalMode emode = qf->outputfields[i].emode;
268*885ac19cSjeremylt       if (emode == CEED_EVAL_NONE) {
269*885ac19cSjeremylt         CeedInt ncomp = qf->outputfields[i].ncomp;
270*885ac19cSjeremylt         opref->outdata[i] = &opref->edata[i + qf->numinputfields][e*Q*ncomp];
271*885ac19cSjeremylt       }
272*885ac19cSjeremylt     }
273*885ac19cSjeremylt     // Q function
274*885ac19cSjeremylt     ierr = CeedQFunctionApply(op->qf, Q, (const CeedScalar * const*) opref->indata,
275*885ac19cSjeremylt                               opref->outdata); CeedChk(ierr);
276*885ac19cSjeremylt 
277*885ac19cSjeremylt     // Output basis apply if needed
278*885ac19cSjeremylt     for (CeedInt i=0; i<qf->numoutputfields; i++) {
279*885ac19cSjeremylt       // Get elemsize
280*885ac19cSjeremylt       if (op->outputfields[i].Erestrict) {
281*885ac19cSjeremylt         elemsize = op->outputfields[i].Erestrict->elemsize;
282*885ac19cSjeremylt       } else {
283*885ac19cSjeremylt         elemsize = Q;
284*885ac19cSjeremylt       }
285*885ac19cSjeremylt       // Get emode, ncomp
286*885ac19cSjeremylt       CeedInt ncomp = qf->outputfields[i].ncomp;
287*885ac19cSjeremylt       CeedEvalMode emode = qf->outputfields[i].emode;
288*885ac19cSjeremylt       // Basis action
289*885ac19cSjeremylt       switch(emode) {
290*885ac19cSjeremylt       case CEED_EVAL_NONE:
291*885ac19cSjeremylt         break; // No action
292*885ac19cSjeremylt       case CEED_EVAL_INTERP:
293*885ac19cSjeremylt         ierr = CeedBasisApply(op->outputfields[i].basis, CEED_TRANSPOSE,
294*885ac19cSjeremylt                               CEED_EVAL_INTERP, opref->outdata[i],
295*885ac19cSjeremylt                               &opref->edata[i + qf->numinputfields][e*elemsize*ncomp]); CeedChk(ierr);
296*885ac19cSjeremylt         break;
297*885ac19cSjeremylt       case CEED_EVAL_GRAD:
298*885ac19cSjeremylt         ierr = CeedBasisApply(op->outputfields[i].basis, CEED_TRANSPOSE, CEED_EVAL_GRAD,
299*885ac19cSjeremylt                               opref->outdata[i], &opref->edata[i + qf->numinputfields][e*elemsize*ncomp]);
300*885ac19cSjeremylt         CeedChk(ierr);
301*885ac19cSjeremylt         break;
302*885ac19cSjeremylt       case CEED_EVAL_WEIGHT:
303*885ac19cSjeremylt         break; // Should not occur
304*885ac19cSjeremylt       case CEED_EVAL_DIV:
305*885ac19cSjeremylt         break; // Not implimented
306*885ac19cSjeremylt       case CEED_EVAL_CURL:
307*885ac19cSjeremylt         break; // Not implimented
308*885ac19cSjeremylt       }
309*885ac19cSjeremylt     }
310*885ac19cSjeremylt   }
311*885ac19cSjeremylt 
312*885ac19cSjeremylt   // Output restriction
313*885ac19cSjeremylt   for (CeedInt i=0,ieout=opref->numein; i<qf->numoutputfields; i++) {
314*885ac19cSjeremylt     // Restriction
315*885ac19cSjeremylt     if (op->outputfields[i].Erestrict) {
316*885ac19cSjeremylt       // Passive
317*885ac19cSjeremylt       if (op->outputfields[i].vec) {
318*885ac19cSjeremylt         ierr = CeedVectorRestoreArray(opref->evecs[ieout],
319*885ac19cSjeremylt                                       &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
320*885ac19cSjeremylt         ierr = CeedElemRestrictionApply(op->outputfields[i].Erestrict, CEED_TRANSPOSE,
321*885ac19cSjeremylt                                         lmode, opref->evecs[ieout], op->outputfields[i].vec, request); CeedChk(ierr);
322*885ac19cSjeremylt         ieout++;
323*885ac19cSjeremylt       } else {
324*885ac19cSjeremylt         // Active
325*885ac19cSjeremylt         ierr = CeedVectorRestoreArray(opref->evecs[ieout],
326*885ac19cSjeremylt                                       &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
327*885ac19cSjeremylt         ierr = CeedElemRestrictionApply(op->outputfields[i].Erestrict, CEED_TRANSPOSE,
328*885ac19cSjeremylt                                         lmode, opref->evecs[ieout], outvec, request); CeedChk(ierr);
329*885ac19cSjeremylt         ieout++;
330*885ac19cSjeremylt       }
331*885ac19cSjeremylt     } else {
332*885ac19cSjeremylt       // No Restriction
333*885ac19cSjeremylt       // Passive
334*885ac19cSjeremylt       if (op->outputfields[i].vec) {
335*885ac19cSjeremylt         ierr = CeedVectorRestoreArray(op->outputfields[i].vec,
336*885ac19cSjeremylt                                       &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
337*885ac19cSjeremylt       } else {
338*885ac19cSjeremylt         // Active
339*885ac19cSjeremylt         ierr = CeedVectorRestoreArray(outvec, &opref->edata[i + qf->numinputfields]);
340*885ac19cSjeremylt         CeedChk(ierr);
341*885ac19cSjeremylt       }
342*885ac19cSjeremylt     }
343*885ac19cSjeremylt   }
344*885ac19cSjeremylt 
34521617c04Sjeremylt   return 0;
34621617c04Sjeremylt }
34721617c04Sjeremylt 
34821617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) {
34921617c04Sjeremylt   CeedOperator_Ref *impl;
35021617c04Sjeremylt   int ierr;
35121617c04Sjeremylt 
35221617c04Sjeremylt   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
35321617c04Sjeremylt   op->data = impl;
35421617c04Sjeremylt   op->Destroy = CeedOperatorDestroy_Ref;
35521617c04Sjeremylt   op->Apply = CeedOperatorApply_Ref;
35621617c04Sjeremylt   return 0;
35721617c04Sjeremylt }
358