xref: /libCEED/rust/libceed-sys/c-src/backends/ref/ceed-ref-operator.c (revision 668048e27b58d44193c5f81ff89fb0cef74dc84e)
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   CeedOperator_Ref *impl = op->data;
2321617c04Sjeremylt   int 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  */
47885ac19cSjeremylt static int CeedOperatorSetupFields_Ref(struct CeedQFunctionField qfields[16],
48885ac19cSjeremylt                                        struct CeedOperatorField ofields[16],
49885ac19cSjeremylt                                        CeedVector *evecs, CeedScalar **qdata,
50885ac19cSjeremylt                                        CeedScalar **qdata_alloc, CeedScalar **indata,
51885ac19cSjeremylt                                        CeedInt starti, CeedInt starte,
52885ac19cSjeremylt                                        CeedInt startq, CeedInt numfields, CeedInt Q) {
53885ac19cSjeremylt   CeedInt dim, ierr, ie=starte, iq=startq, ncomp;
5421617c04Sjeremylt 
55885ac19cSjeremylt   // Loop over fields
56885ac19cSjeremylt   for (CeedInt i=0; i<numfields; i++) {
57*668048e2SJed Brown     if (ofields[i].Erestrict != CEED_RESTRICTION_IDENTITY) {
58885ac19cSjeremylt       ierr = CeedElemRestrictionCreateVector(ofields[i].Erestrict, NULL, &evecs[ie]);
5921617c04Sjeremylt       CeedChk(ierr);
60885ac19cSjeremylt       ie++;
6121617c04Sjeremylt     }
62885ac19cSjeremylt     CeedEvalMode emode = qfields[i].emode;
63885ac19cSjeremylt     switch(emode) {
64885ac19cSjeremylt     case CEED_EVAL_NONE:
65885ac19cSjeremylt       break; // No action
66885ac19cSjeremylt     case CEED_EVAL_INTERP:
67885ac19cSjeremylt       ncomp = qfields[i].ncomp;
68885ac19cSjeremylt       ierr = CeedMalloc(Q*ncomp, &qdata_alloc[iq]); CeedChk(ierr);
69885ac19cSjeremylt       qdata[i + starti] = qdata_alloc[iq];
70885ac19cSjeremylt       iq++;
71885ac19cSjeremylt       break;
72885ac19cSjeremylt     case CEED_EVAL_GRAD:
73885ac19cSjeremylt       ncomp = qfields[i].ncomp;
74885ac19cSjeremylt       dim = ofields[i].basis->dim;
75885ac19cSjeremylt       ierr = CeedMalloc(Q*ncomp*dim, &qdata_alloc[iq]); CeedChk(ierr);
76885ac19cSjeremylt       qdata[i + starti] = qdata_alloc[iq];
77885ac19cSjeremylt       iq++;
78885ac19cSjeremylt       break;
79885ac19cSjeremylt     case CEED_EVAL_WEIGHT: // Only on input fields
80885ac19cSjeremylt       ierr = CeedMalloc(Q, &qdata_alloc[iq]); CeedChk(ierr);
81885ac19cSjeremylt       ierr = CeedBasisApply(ofields[iq].basis, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT,
82885ac19cSjeremylt                             NULL, qdata_alloc[iq]); CeedChk(ierr);
83885ac19cSjeremylt       qdata[i] = qdata_alloc[iq];
84885ac19cSjeremylt       indata[i] = qdata[i];
85885ac19cSjeremylt       iq++;
86885ac19cSjeremylt       break;
87885ac19cSjeremylt     case CEED_EVAL_DIV:
88885ac19cSjeremylt       break; // Not implimented
89885ac19cSjeremylt     case CEED_EVAL_CURL:
90885ac19cSjeremylt       break; // Not implimented
9121617c04Sjeremylt     }
92885ac19cSjeremylt   }
9321617c04Sjeremylt   return 0;
9421617c04Sjeremylt }
9521617c04Sjeremylt 
96885ac19cSjeremylt /*
97885ac19cSjeremylt   CeedOperator needs to connect all the named fields (be they active or passive)
98885ac19cSjeremylt   to the named inputs and outputs of its CeedQFunction.
99885ac19cSjeremylt  */
100885ac19cSjeremylt static int CeedOperatorSetup_Ref(CeedOperator op) {
101885ac19cSjeremylt   if (op->setupdone) return 0;
102885ac19cSjeremylt   CeedOperator_Ref *opref = op->data;
103885ac19cSjeremylt   CeedQFunction qf = op->qf;
104885ac19cSjeremylt   CeedInt Q = op->numqpoints;
10521617c04Sjeremylt   int ierr;
10621617c04Sjeremylt 
107885ac19cSjeremylt   // Count infield and outfield array sizes and evectors
108885ac19cSjeremylt   for (CeedInt i=0; i<qf->numinputfields; i++) {
109885ac19cSjeremylt     CeedEvalMode emode = qf->inputfields[i].emode;
110885ac19cSjeremylt     opref->numqin += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD) + !!
111885ac19cSjeremylt                      (emode & CEED_EVAL_WEIGHT);
112885ac19cSjeremylt     opref->numein +=
113*668048e2SJed Brown       !!(op->inputfields[i].Erestrict != CEED_RESTRICTION_IDENTITY); // Need E-vector when non-identity restriction exists
11421617c04Sjeremylt   }
115885ac19cSjeremylt   for (CeedInt i=0; i<qf->numoutputfields; i++) {
116885ac19cSjeremylt     CeedEvalMode emode = qf->outputfields[i].emode;
117885ac19cSjeremylt     opref->numqout += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD);
118*668048e2SJed Brown     opref->numeout += !!(op->outputfields[i].Erestrict != CEED_RESTRICTION_IDENTITY);
119885ac19cSjeremylt   }
120885ac19cSjeremylt 
121885ac19cSjeremylt   // Allocate
122885ac19cSjeremylt   ierr = CeedCalloc(opref->numein + opref->numeout, &opref->evecs); CeedChk(ierr);
123885ac19cSjeremylt   ierr = CeedCalloc(qf->numinputfields + qf->numoutputfields, &opref->edata);
124885ac19cSjeremylt   CeedChk(ierr);
125885ac19cSjeremylt 
126885ac19cSjeremylt   ierr = CeedCalloc(opref->numqin + opref->numqout, &opref->qdata_alloc);
127885ac19cSjeremylt   CeedChk(ierr);
128885ac19cSjeremylt   ierr = CeedCalloc(qf->numinputfields + qf->numoutputfields, &opref->qdata);
129885ac19cSjeremylt   CeedChk(ierr);
130885ac19cSjeremylt 
131885ac19cSjeremylt   ierr = CeedCalloc(16, &opref->indata); CeedChk(ierr);
132885ac19cSjeremylt   ierr = CeedCalloc(16, &opref->outdata); CeedChk(ierr);
133885ac19cSjeremylt 
134885ac19cSjeremylt   // Set up infield and outfield pointer arrays
135885ac19cSjeremylt   // Infields
136885ac19cSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf->inputfields, op->inputfields,
137885ac19cSjeremylt                                      opref->evecs, opref->qdata, opref->qdata_alloc,
138885ac19cSjeremylt                                      opref->indata, 0, 0, 0,
139885ac19cSjeremylt                                      qf->numinputfields, Q); CeedChk(ierr);
140885ac19cSjeremylt 
141885ac19cSjeremylt   // Outfields
142885ac19cSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf->outputfields, op->outputfields,
143885ac19cSjeremylt                                      opref->evecs, opref->qdata, opref->qdata_alloc,
144885ac19cSjeremylt                                      opref->indata, qf->numinputfields, opref->numein,
145885ac19cSjeremylt                                      opref->numqin, qf->numoutputfields, Q); CeedChk(ierr);
146885ac19cSjeremylt 
1477ca8db16Sjeremylt   // Output Qvecs
1487ca8db16Sjeremylt   for (CeedInt i=0; i<qf->numoutputfields; i++) {
1497ca8db16Sjeremylt     CeedEvalMode emode = qf->outputfields[i].emode;
1507ca8db16Sjeremylt     if (emode != CEED_EVAL_NONE) {
1517ca8db16Sjeremylt       opref->outdata[i] =  opref->qdata[i + qf->numinputfields];
1527ca8db16Sjeremylt     }
1537ca8db16Sjeremylt   }
1547ca8db16Sjeremylt 
155885ac19cSjeremylt   op->setupdone = 1;
156885ac19cSjeremylt 
157885ac19cSjeremylt   return 0;
158885ac19cSjeremylt }
159885ac19cSjeremylt 
160885ac19cSjeremylt static int CeedOperatorApply_Ref(CeedOperator op, CeedVector invec,
161885ac19cSjeremylt                                  CeedVector outvec, CeedRequest *request) {
162885ac19cSjeremylt   CeedOperator_Ref *opref = op->data;
163885ac19cSjeremylt   CeedInt Q = op->numqpoints, elemsize;
164885ac19cSjeremylt   int ierr;
165885ac19cSjeremylt   CeedQFunction qf = op->qf;
166885ac19cSjeremylt   CeedTransposeMode lmode = CEED_NOTRANSPOSE;
1677ca8db16Sjeremylt   CeedScalar *vec_temp;
168885ac19cSjeremylt 
169885ac19cSjeremylt   // Setup
170885ac19cSjeremylt   ierr = CeedOperatorSetup_Ref(op); CeedChk(ierr);
171885ac19cSjeremylt 
172885ac19cSjeremylt   // Input Evecs and Restriction
173885ac19cSjeremylt   for (CeedInt i=0,iein=0; i<qf->numinputfields; i++) {
174*668048e2SJed Brown     // No Restriction
175*668048e2SJed Brown     if (op->inputfields[i].Erestrict == CEED_RESTRICTION_IDENTITY) {
176*668048e2SJed Brown       CeedEvalMode emode = qf->inputfields[i].emode;
177*668048e2SJed Brown       if (emode & CEED_EVAL_WEIGHT) {
178*668048e2SJed Brown       } else {
179*668048e2SJed Brown         // Active
180*668048e2SJed Brown         if (op->inputfields[i].vec == CEED_VECTOR_ACTIVE) {
181*668048e2SJed Brown           ierr = CeedVectorGetArrayRead(invec, CEED_MEM_HOST,
182*668048e2SJed Brown                                         (const CeedScalar **) &opref->edata[i]); CeedChk(ierr);
183*668048e2SJed Brown           // Passive
184*668048e2SJed Brown         } else {
185*668048e2SJed Brown           ierr = CeedVectorGetArrayRead(op->inputfields[i].vec, CEED_MEM_HOST,
186*668048e2SJed Brown                                         (const CeedScalar **) &opref->edata[i]); CeedChk(ierr);
187*668048e2SJed Brown         }
188*668048e2SJed Brown       }
189*668048e2SJed Brown     } else {
190885ac19cSjeremylt       // Restriction
1917ca8db16Sjeremylt       // Zero evec
1920f5de9e9Sjeremylt       ierr = CeedVectorGetArray(opref->evecs[iein], CEED_MEM_HOST, &vec_temp);
1930f5de9e9Sjeremylt       CeedChk(ierr);
1947ca8db16Sjeremylt       for (CeedInt j=0; j<opref->evecs[iein]->length; j++)
1957ca8db16Sjeremylt         vec_temp[j] = 0.;
1967ca8db16Sjeremylt       ierr = CeedVectorRestoreArray(opref->evecs[iein], &vec_temp); CeedChk(ierr);
197*668048e2SJed Brown       // Active
198*668048e2SJed Brown       if (op->inputfields[i].vec == CEED_VECTOR_ACTIVE) {
199*668048e2SJed Brown         // Restrict
200*668048e2SJed Brown         ierr = CeedElemRestrictionApply(op->inputfields[i].Erestrict, CEED_NOTRANSPOSE,
201*668048e2SJed Brown                                         lmode, invec, opref->evecs[iein],
202*668048e2SJed Brown                                         request); CeedChk(ierr);
203*668048e2SJed Brown         // Get evec
204*668048e2SJed Brown         ierr = CeedVectorGetArrayRead(opref->evecs[iein], CEED_MEM_HOST,
205*668048e2SJed Brown                                       (const CeedScalar **) &opref->edata[i]); CeedChk(ierr);
206*668048e2SJed Brown         iein++;
207*668048e2SJed Brown       } else {
208885ac19cSjeremylt         // Passive
2097ca8db16Sjeremylt         // Restrict
210885ac19cSjeremylt         ierr = CeedElemRestrictionApply(op->inputfields[i].Erestrict, CEED_NOTRANSPOSE,
211885ac19cSjeremylt                                         lmode, op->inputfields[i].vec, opref->evecs[iein],
212885ac19cSjeremylt                                         request); CeedChk(ierr);
2137ca8db16Sjeremylt         // Get evec
214885ac19cSjeremylt         ierr = CeedVectorGetArrayRead(opref->evecs[iein], CEED_MEM_HOST,
215885ac19cSjeremylt                                       (const CeedScalar **) &opref->edata[i]); CeedChk(ierr);
216885ac19cSjeremylt         iein++;
217885ac19cSjeremylt       }
218885ac19cSjeremylt     }
219885ac19cSjeremylt   }
220885ac19cSjeremylt 
221885ac19cSjeremylt   // Output Evecs
222885ac19cSjeremylt   for (CeedInt i=0,ieout=opref->numein; i<qf->numoutputfields; i++) {
223*668048e2SJed Brown     // No Restriction
224*668048e2SJed Brown     if (op->outputfields[i].Erestrict == CEED_RESTRICTION_IDENTITY) {
225*668048e2SJed Brown       // Active
226*668048e2SJed Brown       if (op->outputfields[i].vec == CEED_VECTOR_ACTIVE) {
227*668048e2SJed Brown         ierr = CeedVectorGetArray(outvec, CEED_MEM_HOST,
228*668048e2SJed Brown                                   &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
229*668048e2SJed Brown       } else {
230*668048e2SJed Brown         // Passive
231*668048e2SJed Brown         ierr = CeedVectorGetArray(op->outputfields[i].vec, CEED_MEM_HOST,
232*668048e2SJed Brown                                   &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
233*668048e2SJed Brown       }
234*668048e2SJed Brown     } else {
235885ac19cSjeremylt       // Restriction
236885ac19cSjeremylt       ierr = CeedVectorGetArray(opref->evecs[ieout], CEED_MEM_HOST,
237885ac19cSjeremylt                                 &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
238885ac19cSjeremylt       ieout++;
239885ac19cSjeremylt     }
240885ac19cSjeremylt   }
241885ac19cSjeremylt 
242885ac19cSjeremylt   // Loop through elements
243885ac19cSjeremylt   for (CeedInt e=0; e<op->numelements; e++) {
244885ac19cSjeremylt     // Input basis apply if needed
245885ac19cSjeremylt     for (CeedInt i=0; i<qf->numinputfields; i++) {
246885ac19cSjeremylt       // Get elemsize
247*668048e2SJed Brown       if (op->inputfields[i].Erestrict != CEED_RESTRICTION_IDENTITY) {
248885ac19cSjeremylt         elemsize = op->inputfields[i].Erestrict->elemsize;
249885ac19cSjeremylt       } else {
250885ac19cSjeremylt         elemsize = Q;
251885ac19cSjeremylt       }
252885ac19cSjeremylt       // Get emode, ncomp
253885ac19cSjeremylt       CeedEvalMode emode = qf->inputfields[i].emode;
254885ac19cSjeremylt       CeedInt ncomp = qf->inputfields[i].ncomp;
255885ac19cSjeremylt       // Basis action
256885ac19cSjeremylt       switch(emode) {
257885ac19cSjeremylt       case CEED_EVAL_NONE:
258885ac19cSjeremylt         opref->indata[i] = &opref->edata[i][e*Q*ncomp];
259885ac19cSjeremylt         break;
260885ac19cSjeremylt       case CEED_EVAL_INTERP:
261885ac19cSjeremylt         ierr = CeedBasisApply(op->inputfields[i].basis, CEED_NOTRANSPOSE,
262885ac19cSjeremylt                               CEED_EVAL_INTERP, &opref->edata[i][e*elemsize*ncomp], opref->qdata[i]);
263885ac19cSjeremylt         CeedChk(ierr);
264885ac19cSjeremylt         opref->indata[i] = opref->qdata[i];
265885ac19cSjeremylt         break;
266885ac19cSjeremylt       case CEED_EVAL_GRAD:
267885ac19cSjeremylt         ierr = CeedBasisApply(op->inputfields[i].basis, CEED_NOTRANSPOSE,
268885ac19cSjeremylt                               CEED_EVAL_GRAD, &opref->edata[i][e*elemsize*ncomp], opref->qdata[i]);
269885ac19cSjeremylt         CeedChk(ierr);
270885ac19cSjeremylt         opref->indata[i] = opref->qdata[i];
271885ac19cSjeremylt         break;
272885ac19cSjeremylt       case CEED_EVAL_WEIGHT:
273885ac19cSjeremylt         break;  // No action
274885ac19cSjeremylt       case CEED_EVAL_DIV:
275885ac19cSjeremylt         break; // Not implimented
276885ac19cSjeremylt       case CEED_EVAL_CURL:
277885ac19cSjeremylt         break; // Not implimented
278885ac19cSjeremylt       }
279885ac19cSjeremylt     }
280885ac19cSjeremylt     // Output pointers
281885ac19cSjeremylt     for (CeedInt i=0; i<qf->numoutputfields; i++) {
282885ac19cSjeremylt       CeedEvalMode emode = qf->outputfields[i].emode;
283885ac19cSjeremylt       if (emode == CEED_EVAL_NONE) {
284885ac19cSjeremylt         CeedInt ncomp = qf->outputfields[i].ncomp;
285885ac19cSjeremylt         opref->outdata[i] = &opref->edata[i + qf->numinputfields][e*Q*ncomp];
286885ac19cSjeremylt       }
287885ac19cSjeremylt     }
288885ac19cSjeremylt     // Q function
289885ac19cSjeremylt     ierr = CeedQFunctionApply(op->qf, Q, (const CeedScalar * const*) opref->indata,
290885ac19cSjeremylt                               opref->outdata); CeedChk(ierr);
291885ac19cSjeremylt 
292885ac19cSjeremylt     // Output basis apply if needed
293885ac19cSjeremylt     for (CeedInt i=0; i<qf->numoutputfields; i++) {
294885ac19cSjeremylt       // Get elemsize
295*668048e2SJed Brown       if (op->outputfields[i].Erestrict != CEED_RESTRICTION_IDENTITY) {
296885ac19cSjeremylt         elemsize = op->outputfields[i].Erestrict->elemsize;
297885ac19cSjeremylt       } else {
298885ac19cSjeremylt         elemsize = Q;
299885ac19cSjeremylt       }
300885ac19cSjeremylt       // Get emode, ncomp
301885ac19cSjeremylt       CeedInt ncomp = qf->outputfields[i].ncomp;
302885ac19cSjeremylt       CeedEvalMode emode = qf->outputfields[i].emode;
303885ac19cSjeremylt       // Basis action
304885ac19cSjeremylt       switch(emode) {
305885ac19cSjeremylt       case CEED_EVAL_NONE:
306885ac19cSjeremylt         break; // No action
307885ac19cSjeremylt       case CEED_EVAL_INTERP:
308885ac19cSjeremylt         ierr = CeedBasisApply(op->outputfields[i].basis, CEED_TRANSPOSE,
309885ac19cSjeremylt                               CEED_EVAL_INTERP, opref->outdata[i],
310885ac19cSjeremylt                               &opref->edata[i + qf->numinputfields][e*elemsize*ncomp]); CeedChk(ierr);
311885ac19cSjeremylt         break;
312885ac19cSjeremylt       case CEED_EVAL_GRAD:
313885ac19cSjeremylt         ierr = CeedBasisApply(op->outputfields[i].basis, CEED_TRANSPOSE, CEED_EVAL_GRAD,
314885ac19cSjeremylt                               opref->outdata[i], &opref->edata[i + qf->numinputfields][e*elemsize*ncomp]);
315885ac19cSjeremylt         CeedChk(ierr);
316885ac19cSjeremylt         break;
317885ac19cSjeremylt       case CEED_EVAL_WEIGHT:
318885ac19cSjeremylt         break; // Should not occur
319885ac19cSjeremylt       case CEED_EVAL_DIV:
320885ac19cSjeremylt         break; // Not implimented
321885ac19cSjeremylt       case CEED_EVAL_CURL:
322885ac19cSjeremylt         break; // Not implimented
323885ac19cSjeremylt       }
324885ac19cSjeremylt     }
325885ac19cSjeremylt   }
326885ac19cSjeremylt 
327885ac19cSjeremylt   // Output restriction
328885ac19cSjeremylt   for (CeedInt i=0,ieout=opref->numein; i<qf->numoutputfields; i++) {
329*668048e2SJed Brown     // No Restriction
330*668048e2SJed Brown     if (op->outputfields[i].Erestrict == CEED_RESTRICTION_IDENTITY) {
331885ac19cSjeremylt       // Active
332*668048e2SJed Brown       if (op->outputfields[i].vec == CEED_VECTOR_ACTIVE) {
333*668048e2SJed Brown         ierr = CeedVectorRestoreArray(outvec, &opref->edata[i + qf->numinputfields]);
334*668048e2SJed Brown         CeedChk(ierr);
335*668048e2SJed Brown       } else {
336*668048e2SJed Brown         // Passive
337*668048e2SJed Brown         ierr = CeedVectorRestoreArray(op->outputfields[i].vec,
338*668048e2SJed Brown                                       &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
339*668048e2SJed Brown       }
340*668048e2SJed Brown     } else {
341*668048e2SJed Brown       // Restriction
342*668048e2SJed Brown       // Active
343*668048e2SJed Brown       if (op->outputfields[i].vec == CEED_VECTOR_ACTIVE) {
3447ca8db16Sjeremylt         // Restore evec
345885ac19cSjeremylt         ierr = CeedVectorRestoreArray(opref->evecs[ieout],
346885ac19cSjeremylt                                       &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
3477ca8db16Sjeremylt         // Zero lvec
3487ca8db16Sjeremylt         ierr = CeedVectorGetArray(outvec, CEED_MEM_HOST, &vec_temp); CeedChk(ierr);
3497ca8db16Sjeremylt         for (CeedInt j=0; j<outvec->length; j++)
3507ca8db16Sjeremylt           vec_temp[j] = 0.;
3517ca8db16Sjeremylt         ierr = CeedVectorRestoreArray(outvec, &vec_temp); CeedChk(ierr);
3527ca8db16Sjeremylt         // Restrict
353885ac19cSjeremylt         ierr = CeedElemRestrictionApply(op->outputfields[i].Erestrict, CEED_TRANSPOSE,
354885ac19cSjeremylt                                         lmode, opref->evecs[ieout], outvec, request); CeedChk(ierr);
355885ac19cSjeremylt         ieout++;
356885ac19cSjeremylt       } else {
357885ac19cSjeremylt         // Passive
358*668048e2SJed Brown         // Restore evec
359*668048e2SJed Brown         ierr = CeedVectorRestoreArray(opref->evecs[ieout],
360885ac19cSjeremylt                                       &opref->edata[i + qf->numinputfields]); CeedChk(ierr);
361*668048e2SJed Brown         // Zero lvec
362*668048e2SJed Brown         ierr = CeedVectorGetArray(op->outputfields[i].vec, CEED_MEM_HOST, &vec_temp);
363885ac19cSjeremylt         CeedChk(ierr);
364*668048e2SJed Brown         for (CeedInt j=0; j<op->outputfields[i].vec->length; j++)
365*668048e2SJed Brown           vec_temp[j] = 0.;
366*668048e2SJed Brown         ierr = CeedVectorRestoreArray(op->outputfields[i].vec, &vec_temp);
367*668048e2SJed Brown         CeedChk(ierr);
368*668048e2SJed Brown         // Restrict
369*668048e2SJed Brown         ierr = CeedElemRestrictionApply(op->outputfields[i].Erestrict, CEED_TRANSPOSE,
370*668048e2SJed Brown                                         lmode, opref->evecs[ieout], op->outputfields[i].vec,
371*668048e2SJed Brown                                         request); CeedChk(ierr);
372*668048e2SJed Brown         ieout++;
373885ac19cSjeremylt       }
374885ac19cSjeremylt     }
375885ac19cSjeremylt   }
376885ac19cSjeremylt 
3777ca8db16Sjeremylt   // Restore input arrays
3787ca8db16Sjeremylt   for (CeedInt i=0,iein=0; i<qf->numinputfields; i++) {
379*668048e2SJed Brown     // No Restriction
380*668048e2SJed Brown     if (op->inputfields[i].Erestrict == CEED_RESTRICTION_IDENTITY) {
3817ca8db16Sjeremylt       CeedEvalMode emode = qf->inputfields[i].emode;
3827ca8db16Sjeremylt       if (emode & CEED_EVAL_WEIGHT) {
3837ca8db16Sjeremylt       } else {
3847ca8db16Sjeremylt         // Active
385*668048e2SJed Brown         if (op->inputfields[i].vec == CEED_VECTOR_ACTIVE) {
3867ca8db16Sjeremylt           ierr = CeedVectorRestoreArrayRead(invec,
3877ca8db16Sjeremylt                                             (const CeedScalar **) &opref->edata[i]); CeedChk(ierr);
388*668048e2SJed Brown           // Passive
389*668048e2SJed Brown         } else {
390*668048e2SJed Brown           ierr = CeedVectorRestoreArrayRead(op->inputfields[i].vec,
391*668048e2SJed Brown                                             (const CeedScalar **) &opref->edata[i]); CeedChk(ierr);
3927ca8db16Sjeremylt         }
3937ca8db16Sjeremylt       }
394*668048e2SJed Brown     } else {
395*668048e2SJed Brown       // Restriction
396*668048e2SJed Brown       ierr = CeedVectorRestoreArrayRead(opref->evecs[iein],
397*668048e2SJed Brown                                         (const CeedScalar **) &opref->edata[i]); CeedChk(ierr);
398*668048e2SJed Brown       iein++;
3997ca8db16Sjeremylt     }
4007ca8db16Sjeremylt   }
4017ca8db16Sjeremylt 
40221617c04Sjeremylt   return 0;
40321617c04Sjeremylt }
40421617c04Sjeremylt 
40521617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) {
40621617c04Sjeremylt   CeedOperator_Ref *impl;
40721617c04Sjeremylt   int ierr;
40821617c04Sjeremylt 
40921617c04Sjeremylt   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
41021617c04Sjeremylt   op->data = impl;
41121617c04Sjeremylt   op->Destroy = CeedOperatorDestroy_Ref;
41221617c04Sjeremylt   op->Apply = CeedOperatorApply_Ref;
41321617c04Sjeremylt   return 0;
41421617c04Sjeremylt }
415