xref: /libCEED/backends/ref/ceed-ref-operator.c (revision 4ce2993fee6e7bc9b86526ee90098d0dc489fc60)
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 
2121617c04Sjeremylt static int CeedOperatorDestroy_Ref(CeedOperator op) {
2221617c04Sjeremylt   int ierr;
23*4ce2993fSjeremylt   CeedOperator_Ref *impl;
24*4ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void*)&impl); CeedChk(ierr);
2521617c04Sjeremylt 
26885ac19cSjeremylt   for (CeedInt i=0; i<impl->numein+impl->numeout; i++) {
27885ac19cSjeremylt     ierr = CeedVectorDestroy(&impl->evecs[i]); CeedChk(ierr);
28885ac19cSjeremylt   }
29885ac19cSjeremylt   ierr = CeedFree(&impl->evecs); CeedChk(ierr);
30885ac19cSjeremylt   ierr = CeedFree(&impl->edata); CeedChk(ierr);
31885ac19cSjeremylt 
32885ac19cSjeremylt   for (CeedInt i=0; i<impl->numqin+impl->numqout; i++) {
33885ac19cSjeremylt     ierr = CeedFree(&impl->qdata_alloc[i]); CeedChk(ierr);
34885ac19cSjeremylt   }
35885ac19cSjeremylt   ierr = CeedFree(&impl->qdata_alloc); CeedChk(ierr);
36885ac19cSjeremylt   ierr = CeedFree(&impl->qdata); CeedChk(ierr);
37885ac19cSjeremylt 
38885ac19cSjeremylt   ierr = CeedFree(&impl->indata); CeedChk(ierr);
39885ac19cSjeremylt   ierr = CeedFree(&impl->outdata); CeedChk(ierr);
40885ac19cSjeremylt 
4121617c04Sjeremylt   ierr = CeedFree(&op->data); CeedChk(ierr);
4221617c04Sjeremylt   return 0;
4321617c04Sjeremylt }
4421617c04Sjeremylt 
45885ac19cSjeremylt /*
46885ac19cSjeremylt   Setup infields or outfields
47885ac19cSjeremylt  */
48885ac19cSjeremylt static int CeedOperatorSetupFields_Ref(struct CeedQFunctionField qfields[16],
49885ac19cSjeremylt                                        struct CeedOperatorField ofields[16],
50885ac19cSjeremylt                                        CeedVector *evecs, CeedScalar **qdata,
51885ac19cSjeremylt                                        CeedScalar **qdata_alloc, CeedScalar **indata,
52135a076eSjeremylt                                        CeedInt starti, CeedInt startq,
53135a076eSjeremylt                                        CeedInt numfields, CeedInt Q) {
54135a076eSjeremylt   CeedInt dim, ierr, iq=startq, ncomp;
5521617c04Sjeremylt 
56885ac19cSjeremylt   // Loop over fields
57885ac19cSjeremylt   for (CeedInt i=0; i<numfields; i++) {
58885ac19cSjeremylt     CeedEvalMode emode = qfields[i].emode;
59135a076eSjeremylt 
60135a076eSjeremylt     if (emode != CEED_EVAL_WEIGHT) {
614b8bea3bSJed Brown       ierr = CeedElemRestrictionCreateVector(ofields[i].Erestrict, NULL,
624b8bea3bSJed Brown                                              &evecs[i+starti]);
63135a076eSjeremylt       CeedChk(ierr);
64135a076eSjeremylt     }
65135a076eSjeremylt 
66885ac19cSjeremylt     switch(emode) {
67885ac19cSjeremylt     case CEED_EVAL_NONE:
68885ac19cSjeremylt       break; // No action
69885ac19cSjeremylt     case CEED_EVAL_INTERP:
70885ac19cSjeremylt       ncomp = qfields[i].ncomp;
71885ac19cSjeremylt       ierr = CeedMalloc(Q*ncomp, &qdata_alloc[iq]); CeedChk(ierr);
72885ac19cSjeremylt       qdata[i + starti] = qdata_alloc[iq];
73885ac19cSjeremylt       iq++;
74885ac19cSjeremylt       break;
75885ac19cSjeremylt     case CEED_EVAL_GRAD:
76885ac19cSjeremylt       ncomp = qfields[i].ncomp;
77*4ce2993fSjeremylt       ierr = CeedBasisGetDimension(ofields[i].basis, &dim); CeedChk(ierr);
78885ac19cSjeremylt       ierr = CeedMalloc(Q*ncomp*dim, &qdata_alloc[iq]); CeedChk(ierr);
79885ac19cSjeremylt       qdata[i + starti] = qdata_alloc[iq];
80885ac19cSjeremylt       iq++;
81885ac19cSjeremylt       break;
82885ac19cSjeremylt     case CEED_EVAL_WEIGHT: // Only on input fields
83885ac19cSjeremylt       ierr = CeedMalloc(Q, &qdata_alloc[iq]); CeedChk(ierr);
84d3181881Sjeremylt       ierr = CeedBasisApply(ofields[iq].basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT,
85885ac19cSjeremylt                             NULL, qdata_alloc[iq]); CeedChk(ierr);
86885ac19cSjeremylt       qdata[i] = qdata_alloc[iq];
87885ac19cSjeremylt       indata[i] = qdata[i];
88885ac19cSjeremylt       iq++;
89885ac19cSjeremylt       break;
90885ac19cSjeremylt     case CEED_EVAL_DIV:
91885ac19cSjeremylt       break; // Not implimented
92885ac19cSjeremylt     case CEED_EVAL_CURL:
93885ac19cSjeremylt       break; // Not implimented
9421617c04Sjeremylt     }
95885ac19cSjeremylt   }
9621617c04Sjeremylt   return 0;
9721617c04Sjeremylt }
9821617c04Sjeremylt 
99885ac19cSjeremylt /*
100885ac19cSjeremylt   CeedOperator needs to connect all the named fields (be they active or passive)
101885ac19cSjeremylt   to the named inputs and outputs of its CeedQFunction.
102885ac19cSjeremylt  */
103885ac19cSjeremylt static int CeedOperatorSetup_Ref(CeedOperator op) {
10421617c04Sjeremylt   int ierr;
105*4ce2993fSjeremylt   bool setupdone;
106*4ce2993fSjeremylt   ierr = CeedOperatorGetSetupStatus(op, &setupdone); CeedChk(ierr);
107*4ce2993fSjeremylt   if (setupdone) return 0;
108*4ce2993fSjeremylt   CeedOperator_Ref *impl;
109*4ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void*)&impl); CeedChk(ierr);
110*4ce2993fSjeremylt   CeedQFunction qf;
111*4ce2993fSjeremylt   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
112*4ce2993fSjeremylt   CeedInt Q, numinputfields, numoutputfields;
113*4ce2993fSjeremylt   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr);
114a8de75f0Sjeremylt   ierr = CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
115a8de75f0Sjeremylt   CeedChk(ierr);
116*4ce2993fSjeremylt 
117*4ce2993fSjeremylt   // Count infield and outfield array sizes and evectors
1181a4ead9bSjeremylt   impl->numein = numinputfields;
1191a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
120885ac19cSjeremylt     CeedEvalMode emode = qf->inputfields[i].emode;
1218d94b059Sjeremylt     impl->numqin += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD) +
1228d94b059Sjeremylt                     !!(emode & CEED_EVAL_WEIGHT);
12321617c04Sjeremylt   }
1241a4ead9bSjeremylt   impl->numeout = numoutputfields;
1251a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
126885ac19cSjeremylt     CeedEvalMode emode = qf->outputfields[i].emode;
127a2b73c81Sjeremylt     impl->numqout += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD);
128885ac19cSjeremylt   }
129885ac19cSjeremylt 
130885ac19cSjeremylt   // Allocate
131a2b73c81Sjeremylt   ierr = CeedCalloc(impl->numein + impl->numeout, &impl->evecs); CeedChk(ierr);
132a2b73c81Sjeremylt   ierr = CeedCalloc(impl->numein + impl->numeout, &impl->edata);
133885ac19cSjeremylt   CeedChk(ierr);
134885ac19cSjeremylt 
135a2b73c81Sjeremylt   ierr = CeedCalloc(impl->numqin + impl->numqout, &impl->qdata_alloc);
136885ac19cSjeremylt   CeedChk(ierr);
1371a4ead9bSjeremylt   ierr = CeedCalloc(numinputfields + numoutputfields, &impl->qdata);
138885ac19cSjeremylt   CeedChk(ierr);
139885ac19cSjeremylt 
140a2b73c81Sjeremylt   ierr = CeedCalloc(16, &impl->indata); CeedChk(ierr);
141a2b73c81Sjeremylt   ierr = CeedCalloc(16, &impl->outdata); CeedChk(ierr);
142885ac19cSjeremylt 
143885ac19cSjeremylt   // Set up infield and outfield pointer arrays
144885ac19cSjeremylt   // Infields
145885ac19cSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf->inputfields, op->inputfields,
146a2b73c81Sjeremylt                                      impl->evecs, impl->qdata, impl->qdata_alloc,
147a2b73c81Sjeremylt                                      impl->indata, 0, 0,
1481a4ead9bSjeremylt                                      numinputfields, Q); CeedChk(ierr);
149885ac19cSjeremylt 
150885ac19cSjeremylt   // Outfields
151885ac19cSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf->outputfields, op->outputfields,
152a2b73c81Sjeremylt                                      impl->evecs, impl->qdata, impl->qdata_alloc,
1531a4ead9bSjeremylt                                      impl->indata, numinputfields,
1541a4ead9bSjeremylt                                      impl->numqin, numoutputfields, Q); CeedChk(ierr);
155885ac19cSjeremylt 
1568d94b059Sjeremylt   // Input Qvecs
1571a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
1588d94b059Sjeremylt     CeedEvalMode emode = qf->inputfields[i].emode;
1598d94b059Sjeremylt     if ((emode != CEED_EVAL_NONE) && (emode != CEED_EVAL_WEIGHT))
1608d94b059Sjeremylt       impl->indata[i] =  impl->qdata[i];
1618d94b059Sjeremylt   }
1627ca8db16Sjeremylt   // Output Qvecs
1631a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
1647ca8db16Sjeremylt     CeedEvalMode emode = qf->outputfields[i].emode;
1658d94b059Sjeremylt     if (emode != CEED_EVAL_NONE)
1661a4ead9bSjeremylt       impl->outdata[i] =  impl->qdata[i + numinputfields];
1677ca8db16Sjeremylt   }
1687ca8db16Sjeremylt 
169*4ce2993fSjeremylt   ierr = CeedOperatorSetSetupDone(op); CeedChk(ierr);
170885ac19cSjeremylt 
171885ac19cSjeremylt   return 0;
172885ac19cSjeremylt }
173885ac19cSjeremylt 
174885ac19cSjeremylt static int CeedOperatorApply_Ref(CeedOperator op, CeedVector invec,
175885ac19cSjeremylt                                  CeedVector outvec, CeedRequest *request) {
176885ac19cSjeremylt   int ierr;
177*4ce2993fSjeremylt   CeedOperator_Ref *impl;
178*4ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void*)&impl); CeedChk(ierr);
179*4ce2993fSjeremylt   CeedQFunction qf;
180*4ce2993fSjeremylt   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
181*4ce2993fSjeremylt   CeedInt Q, numelements, elemsize, numinputfields, numoutputfields;
182*4ce2993fSjeremylt   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr);
183*4ce2993fSjeremylt   ierr = CeedOperatorGetNumElements(op, &numelements); CeedChk(ierr);
184*4ce2993fSjeremylt   ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
185*4ce2993fSjeremylt   CeedChk(ierr);
186885ac19cSjeremylt   CeedTransposeMode lmode = CEED_NOTRANSPOSE;
187885ac19cSjeremylt 
188885ac19cSjeremylt   // Setup
189885ac19cSjeremylt   ierr = CeedOperatorSetup_Ref(op); CeedChk(ierr);
190885ac19cSjeremylt 
191885ac19cSjeremylt   // Input Evecs and Restriction
1921a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
193668048e2SJed Brown     CeedEvalMode emode = qf->inputfields[i].emode;
194135a076eSjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
195668048e2SJed Brown     } else {
196668048e2SJed Brown       // Active
197668048e2SJed Brown       if (op->inputfields[i].vec == CEED_VECTOR_ACTIVE) {
198668048e2SJed Brown         // Restrict
199668048e2SJed Brown         ierr = CeedElemRestrictionApply(op->inputfields[i].Erestrict, CEED_NOTRANSPOSE,
200a2b73c81Sjeremylt                                         lmode, invec, impl->evecs[i],
201668048e2SJed Brown                                         request); CeedChk(ierr);
202668048e2SJed Brown         // Get evec
203a2b73c81Sjeremylt         ierr = CeedVectorGetArrayRead(impl->evecs[i], CEED_MEM_HOST,
204a2b73c81Sjeremylt                                       (const CeedScalar **) &impl->edata[i]); CeedChk(ierr);
205668048e2SJed Brown       } else {
206885ac19cSjeremylt         // Passive
2077ca8db16Sjeremylt         // Restrict
208885ac19cSjeremylt         ierr = CeedElemRestrictionApply(op->inputfields[i].Erestrict, CEED_NOTRANSPOSE,
209a2b73c81Sjeremylt                                         lmode, op->inputfields[i].vec, impl->evecs[i],
210885ac19cSjeremylt                                         request); CeedChk(ierr);
2117ca8db16Sjeremylt         // Get evec
212a2b73c81Sjeremylt         ierr = CeedVectorGetArrayRead(impl->evecs[i], CEED_MEM_HOST,
213a2b73c81Sjeremylt                                       (const CeedScalar **) &impl->edata[i]); CeedChk(ierr);
214885ac19cSjeremylt       }
215885ac19cSjeremylt     }
216885ac19cSjeremylt   }
217885ac19cSjeremylt 
218885ac19cSjeremylt   // Output Evecs
2191a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
220a2b73c81Sjeremylt     ierr = CeedVectorGetArray(impl->evecs[i+impl->numein], CEED_MEM_HOST,
2211a4ead9bSjeremylt                               &impl->edata[i + numinputfields]); CeedChk(ierr);
222885ac19cSjeremylt   }
223885ac19cSjeremylt 
224885ac19cSjeremylt   // Loop through elements
225*4ce2993fSjeremylt   for (CeedInt e=0; e<numelements; e++) {
226885ac19cSjeremylt     // Input basis apply if needed
2271a4ead9bSjeremylt     for (CeedInt i=0; i<numinputfields; i++) {
228135a076eSjeremylt       // Get elemsize, emode, ncomp
229*4ce2993fSjeremylt       ierr = CeedElemRestrictionGetElementSize(
230*4ce2993fSjeremylt                op->inputfields[i].Erestrict, &elemsize); CeedChk(ierr);
231885ac19cSjeremylt       CeedEvalMode emode = qf->inputfields[i].emode;
232885ac19cSjeremylt       CeedInt ncomp = qf->inputfields[i].ncomp;
233885ac19cSjeremylt       // Basis action
234885ac19cSjeremylt       switch(emode) {
235885ac19cSjeremylt       case CEED_EVAL_NONE:
236a2b73c81Sjeremylt         impl->indata[i] = &impl->edata[i][e*Q*ncomp];
237885ac19cSjeremylt         break;
238885ac19cSjeremylt       case CEED_EVAL_INTERP:
239d3181881Sjeremylt         ierr = CeedBasisApply(op->inputfields[i].basis, 1, CEED_NOTRANSPOSE,
240a2b73c81Sjeremylt                               CEED_EVAL_INTERP, &impl->edata[i][e*elemsize*ncomp], impl->qdata[i]);
241885ac19cSjeremylt         CeedChk(ierr);
242885ac19cSjeremylt         break;
243885ac19cSjeremylt       case CEED_EVAL_GRAD:
244d3181881Sjeremylt         ierr = CeedBasisApply(op->inputfields[i].basis, 1, CEED_NOTRANSPOSE,
245a2b73c81Sjeremylt                               CEED_EVAL_GRAD, &impl->edata[i][e*elemsize*ncomp], impl->qdata[i]);
246885ac19cSjeremylt         CeedChk(ierr);
247885ac19cSjeremylt         break;
248885ac19cSjeremylt       case CEED_EVAL_WEIGHT:
249885ac19cSjeremylt         break;  // No action
250885ac19cSjeremylt       case CEED_EVAL_DIV:
251885ac19cSjeremylt         break; // Not implimented
252885ac19cSjeremylt       case CEED_EVAL_CURL:
253885ac19cSjeremylt         break; // Not implimented
254885ac19cSjeremylt       }
255885ac19cSjeremylt     }
256885ac19cSjeremylt     // Output pointers
2571a4ead9bSjeremylt     for (CeedInt i=0; i<numoutputfields; i++) {
258885ac19cSjeremylt       CeedEvalMode emode = qf->outputfields[i].emode;
259885ac19cSjeremylt       if (emode == CEED_EVAL_NONE) {
260885ac19cSjeremylt         CeedInt ncomp = qf->outputfields[i].ncomp;
2611a4ead9bSjeremylt         impl->outdata[i] = &impl->edata[i + numinputfields][e*Q*ncomp];
262885ac19cSjeremylt       }
263885ac19cSjeremylt     }
264885ac19cSjeremylt     // Q function
265*4ce2993fSjeremylt     ierr = CeedQFunctionApply(qf, Q, (const CeedScalar * const*) impl->indata,
266a2b73c81Sjeremylt                               impl->outdata); CeedChk(ierr);
267885ac19cSjeremylt 
268885ac19cSjeremylt     // Output basis apply if needed
2691a4ead9bSjeremylt     for (CeedInt i=0; i<numoutputfields; i++) {
270135a076eSjeremylt       // Get elemsize, emode, ncomp
271*4ce2993fSjeremylt       ierr = CeedElemRestrictionGetElementSize(
272*4ce2993fSjeremylt                op->outputfields[i].Erestrict, &elemsize); CeedChk(ierr);
273885ac19cSjeremylt       CeedInt ncomp = qf->outputfields[i].ncomp;
274885ac19cSjeremylt       CeedEvalMode emode = qf->outputfields[i].emode;
275885ac19cSjeremylt       // Basis action
276885ac19cSjeremylt       switch(emode) {
277885ac19cSjeremylt       case CEED_EVAL_NONE:
278885ac19cSjeremylt         break; // No action
279885ac19cSjeremylt       case CEED_EVAL_INTERP:
280d3181881Sjeremylt         ierr = CeedBasisApply(op->outputfields[i].basis, 1, CEED_TRANSPOSE,
281a2b73c81Sjeremylt                               CEED_EVAL_INTERP, impl->outdata[i],
2821a4ead9bSjeremylt                               &impl->edata[i + numinputfields][e*elemsize*ncomp]);
2838d94b059Sjeremylt         CeedChk(ierr);
284885ac19cSjeremylt         break;
285885ac19cSjeremylt       case CEED_EVAL_GRAD:
2860c7a96bbSjeremylt         ierr = CeedBasisApply(op->outputfields[i].basis, 1, CEED_TRANSPOSE,
2870c7a96bbSjeremylt                               CEED_EVAL_GRAD,
2881a4ead9bSjeremylt                               impl->outdata[i], &impl->edata[i + numinputfields][e*elemsize*ncomp]);
289885ac19cSjeremylt         CeedChk(ierr);
290885ac19cSjeremylt         break;
291*4ce2993fSjeremylt       case CEED_EVAL_WEIGHT: {
292*4ce2993fSjeremylt         Ceed ceed;
293*4ce2993fSjeremylt         ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
294*4ce2993fSjeremylt         return CeedError(ceed, 1,
2958d94b059Sjeremylt                          "CEED_EVAL_WEIGHT cannot be an output evaluation mode");
296885ac19cSjeremylt         break; // Should not occur
297*4ce2993fSjeremylt       }
298885ac19cSjeremylt       case CEED_EVAL_DIV:
299885ac19cSjeremylt         break; // Not implimented
300885ac19cSjeremylt       case CEED_EVAL_CURL:
301885ac19cSjeremylt         break; // Not implimented
302885ac19cSjeremylt       }
303885ac19cSjeremylt     }
304885ac19cSjeremylt   }
305885ac19cSjeremylt 
30642ecf959Sjeremylt   // Zero lvecs
30742ecf959Sjeremylt   ierr = CeedVectorSetValue(outvec, 0.0); CeedChk(ierr);
308*4ce2993fSjeremylt   for (CeedInt i=0; i<numoutputfields; i++)
30942ecf959Sjeremylt     if (op->outputfields[i].vec != CEED_VECTOR_ACTIVE) {
31042ecf959Sjeremylt       ierr = CeedVectorSetValue(op->outputfields[i].vec, 0.0); CeedChk(ierr);
31142ecf959Sjeremylt     }
31242ecf959Sjeremylt 
313885ac19cSjeremylt   // Output restriction
3141a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
315a2b73c81Sjeremylt     // Restore evec
316a2b73c81Sjeremylt     ierr = CeedVectorRestoreArray(impl->evecs[i+impl->numein],
3171a4ead9bSjeremylt                                   &impl->edata[i + numinputfields]); CeedChk(ierr);
318668048e2SJed Brown     // Active
319668048e2SJed Brown     if (op->outputfields[i].vec == CEED_VECTOR_ACTIVE) {
3207ca8db16Sjeremylt       // Restrict
321885ac19cSjeremylt       ierr = CeedElemRestrictionApply(op->outputfields[i].Erestrict, CEED_TRANSPOSE,
322a2b73c81Sjeremylt                                       lmode, impl->evecs[i+impl->numein], outvec, request); CeedChk(ierr);
323885ac19cSjeremylt     } else {
324885ac19cSjeremylt       // Passive
325668048e2SJed Brown       // Restrict
326668048e2SJed Brown       ierr = CeedElemRestrictionApply(op->outputfields[i].Erestrict, CEED_TRANSPOSE,
327a2b73c81Sjeremylt                                       lmode, impl->evecs[i+impl->numein], op->outputfields[i].vec,
328668048e2SJed Brown                                       request); CeedChk(ierr);
329885ac19cSjeremylt     }
330885ac19cSjeremylt   }
331885ac19cSjeremylt 
3327ca8db16Sjeremylt   // Restore input arrays
3331a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
3347ca8db16Sjeremylt     CeedEvalMode emode = qf->inputfields[i].emode;
335135a076eSjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
3367ca8db16Sjeremylt     } else {
337a2b73c81Sjeremylt       ierr = CeedVectorRestoreArrayRead(impl->evecs[i],
338a2b73c81Sjeremylt                                         (const CeedScalar **) &impl->edata[i]); CeedChk(ierr);
3397ca8db16Sjeremylt     }
3407ca8db16Sjeremylt   }
3417ca8db16Sjeremylt 
34221617c04Sjeremylt   return 0;
34321617c04Sjeremylt }
34421617c04Sjeremylt 
34521617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) {
34621617c04Sjeremylt   int ierr;
347*4ce2993fSjeremylt   CeedOperator_Ref *impl;
34821617c04Sjeremylt 
34921617c04Sjeremylt   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
35021617c04Sjeremylt   op->data = impl;
35121617c04Sjeremylt   op->Destroy = CeedOperatorDestroy_Ref;
35221617c04Sjeremylt   op->Apply = CeedOperatorApply_Ref;
35321617c04Sjeremylt   return 0;
35421617c04Sjeremylt }
355