xref: /libCEED/backends/ref/ceed-ref-operator.c (revision 91703d3f6e6cf8ee4d2bfaa1ca49093a23af4439)
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 
31aedaa0e5Sjeremylt   for (CeedInt i=0; i<impl->numein; i++) {
32*91703d3fSjeremylt     ierr = CeedVectorDestroy(&impl->evecsin[i]); CeedChk(ierr);
33aedaa0e5Sjeremylt     ierr = CeedVectorDestroy(&impl->qvecsin[i]); CeedChk(ierr);
34885ac19cSjeremylt   }
35*91703d3fSjeremylt   ierr = CeedFree(&impl->evecsin); CeedChk(ierr);
36aedaa0e5Sjeremylt   ierr = CeedFree(&impl->qvecsin); CeedChk(ierr);
37885ac19cSjeremylt 
38aedaa0e5Sjeremylt   for (CeedInt i=0; i<impl->numeout; i++) {
39*91703d3fSjeremylt     ierr = CeedVectorDestroy(&impl->evecsout[i]); CeedChk(ierr);
40aedaa0e5Sjeremylt     ierr = CeedVectorDestroy(&impl->qvecsout[i]); CeedChk(ierr);
41aedaa0e5Sjeremylt   }
42*91703d3fSjeremylt   ierr = CeedFree(&impl->evecsout); CeedChk(ierr);
43aedaa0e5Sjeremylt   ierr = CeedFree(&impl->qvecsout); CeedChk(ierr);
44885ac19cSjeremylt 
45fe2413ffSjeremylt   ierr = CeedFree(&impl); CeedChk(ierr);
4621617c04Sjeremylt   return 0;
4721617c04Sjeremylt }
4821617c04Sjeremylt 
49885ac19cSjeremylt /*
50885ac19cSjeremylt   Setup infields or outfields
51885ac19cSjeremylt  */
52fe2413ffSjeremylt static int CeedOperatorSetupFields_Ref(CeedQFunction qf, CeedOperator op,
53*91703d3fSjeremylt                                        bool inOrOut,
54*91703d3fSjeremylt                                        CeedVector *fullevecs, CeedVector *evecs,
55aedaa0e5Sjeremylt                                        CeedVector *qvecs, CeedInt starte,
56135a076eSjeremylt                                        CeedInt numfields, CeedInt Q) {
57aedaa0e5Sjeremylt   CeedInt dim, ierr, ncomp;
58aedaa0e5Sjeremylt   Ceed ceed;
59aedaa0e5Sjeremylt   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
60d1bcdac9Sjeremylt   CeedBasis basis;
61d1bcdac9Sjeremylt   CeedElemRestriction Erestrict;
62aedaa0e5Sjeremylt   CeedOperatorField *opfields;
63aedaa0e5Sjeremylt   CeedQFunctionField *qffields;
64fe2413ffSjeremylt   if (inOrOut) {
65aedaa0e5Sjeremylt     ierr = CeedOperatorGetFields(op, NULL, &opfields);
66fe2413ffSjeremylt     CeedChk(ierr);
67aedaa0e5Sjeremylt     ierr = CeedQFunctionGetFields(qf, NULL, &qffields);
68fe2413ffSjeremylt     CeedChk(ierr);
69fe2413ffSjeremylt   } else {
70aedaa0e5Sjeremylt     ierr = CeedOperatorGetFields(op, &opfields, NULL);
71fe2413ffSjeremylt     CeedChk(ierr);
72aedaa0e5Sjeremylt     ierr = CeedQFunctionGetFields(qf, &qffields, NULL);
73fe2413ffSjeremylt     CeedChk(ierr);
74fe2413ffSjeremylt   }
7521617c04Sjeremylt 
76885ac19cSjeremylt   // Loop over fields
77885ac19cSjeremylt   for (CeedInt i=0; i<numfields; i++) {
78d1bcdac9Sjeremylt     CeedEvalMode emode;
79aedaa0e5Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode); CeedChk(ierr);
80135a076eSjeremylt 
81135a076eSjeremylt     if (emode != CEED_EVAL_WEIGHT) {
82aedaa0e5Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opfields[i], &Erestrict);
83d1bcdac9Sjeremylt       CeedChk(ierr);
84d1bcdac9Sjeremylt       ierr = CeedElemRestrictionCreateVector(Erestrict, NULL,
85*91703d3fSjeremylt                                              &fullevecs[i+starte]);
86135a076eSjeremylt       CeedChk(ierr);
87135a076eSjeremylt     }
88135a076eSjeremylt 
89885ac19cSjeremylt     switch(emode) {
90885ac19cSjeremylt     case CEED_EVAL_NONE:
91aedaa0e5Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qffields[i], &ncomp);
92d1bcdac9Sjeremylt       CeedChk(ierr);
93aedaa0e5Sjeremylt       ierr = CeedVectorCreate(ceed, Q*ncomp, &qvecs[i]); CeedChk(ierr);
94aedaa0e5Sjeremylt       break;
95aedaa0e5Sjeremylt     case CEED_EVAL_INTERP:
96aedaa0e5Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qffields[i], &ncomp);
97aedaa0e5Sjeremylt       CeedChk(ierr);
98*91703d3fSjeremylt       ierr = CeedVectorCreate(ceed, Q*ncomp, &evecs[i]); CeedChk(ierr);
99aedaa0e5Sjeremylt       ierr = CeedVectorCreate(ceed, Q*ncomp, &qvecs[i]); CeedChk(ierr);
100885ac19cSjeremylt       break;
101885ac19cSjeremylt     case CEED_EVAL_GRAD:
102aedaa0e5Sjeremylt       ierr = CeedOperatorFieldGetBasis(opfields[i], &basis); CeedChk(ierr);
103aedaa0e5Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qffields[i], &ncomp);
104d1bcdac9Sjeremylt       ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
105*91703d3fSjeremylt       ierr = CeedVectorCreate(ceed, Q*ncomp, &evecs[i]); CeedChk(ierr);
106aedaa0e5Sjeremylt       ierr = CeedVectorCreate(ceed, Q*ncomp*dim, &qvecs[i]); CeedChk(ierr);
107885ac19cSjeremylt       break;
108885ac19cSjeremylt     case CEED_EVAL_WEIGHT: // Only on input fields
109aedaa0e5Sjeremylt       ierr = CeedOperatorFieldGetBasis(opfields[i], &basis); CeedChk(ierr);
110aedaa0e5Sjeremylt       ierr = CeedVectorCreate(ceed, Q, &qvecs[i]); CeedChk(ierr);
111d1bcdac9Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT,
112aedaa0e5Sjeremylt                             NULL, qvecs[i]); CeedChk(ierr);
113885ac19cSjeremylt       break;
114885ac19cSjeremylt     case CEED_EVAL_DIV:
115885ac19cSjeremylt       break; // Not implimented
116885ac19cSjeremylt     case CEED_EVAL_CURL:
117885ac19cSjeremylt       break; // Not implimented
11821617c04Sjeremylt     }
119885ac19cSjeremylt   }
12021617c04Sjeremylt   return 0;
12121617c04Sjeremylt }
12221617c04Sjeremylt 
123885ac19cSjeremylt /*
124885ac19cSjeremylt   CeedOperator needs to connect all the named fields (be they active or passive)
125885ac19cSjeremylt   to the named inputs and outputs of its CeedQFunction.
126885ac19cSjeremylt  */
127885ac19cSjeremylt static int CeedOperatorSetup_Ref(CeedOperator op) {
12821617c04Sjeremylt   int ierr;
1294ce2993fSjeremylt   bool setupdone;
1304ce2993fSjeremylt   ierr = CeedOperatorGetSetupStatus(op, &setupdone); CeedChk(ierr);
1314ce2993fSjeremylt   if (setupdone) return 0;
132aedaa0e5Sjeremylt   Ceed ceed;
133aedaa0e5Sjeremylt   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
1344ce2993fSjeremylt   CeedOperator_Ref *impl;
1354ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void*)&impl); CeedChk(ierr);
1364ce2993fSjeremylt   CeedQFunction qf;
1374ce2993fSjeremylt   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
1384ce2993fSjeremylt   CeedInt Q, numinputfields, numoutputfields;
1394ce2993fSjeremylt   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr);
140a8de75f0Sjeremylt   ierr = CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
141a8de75f0Sjeremylt   CeedChk(ierr);
142d1bcdac9Sjeremylt   CeedOperatorField *opinputfields, *opoutputfields;
143d1bcdac9Sjeremylt   ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields);
144d1bcdac9Sjeremylt   CeedChk(ierr);
145d1bcdac9Sjeremylt   CeedQFunctionField *qfinputfields, *qfoutputfields;
146d1bcdac9Sjeremylt   ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields);
147d1bcdac9Sjeremylt   CeedChk(ierr);
148885ac19cSjeremylt 
149885ac19cSjeremylt   // Allocate
150aedaa0e5Sjeremylt   ierr = CeedCalloc(numinputfields + numoutputfields, &impl->evecs);
151aedaa0e5Sjeremylt   CeedChk(ierr);
152aedaa0e5Sjeremylt   ierr = CeedCalloc(numinputfields + numoutputfields, &impl->edata);
153885ac19cSjeremylt   CeedChk(ierr);
154885ac19cSjeremylt 
155*91703d3fSjeremylt   ierr = CeedCalloc(16, &impl->evecsin); CeedChk(ierr);
156*91703d3fSjeremylt   ierr = CeedCalloc(16, &impl->evecsout); CeedChk(ierr);
157aedaa0e5Sjeremylt   ierr = CeedCalloc(16, &impl->qvecsin); CeedChk(ierr);
158aedaa0e5Sjeremylt   ierr = CeedCalloc(16, &impl->qvecsout); CeedChk(ierr);
159885ac19cSjeremylt 
160aedaa0e5Sjeremylt   impl->numein = numinputfields; impl->numeout = numoutputfields;
161885ac19cSjeremylt 
162aedaa0e5Sjeremylt   // Set up infield and outfield evecs and qvecs
163885ac19cSjeremylt   // Infields
164*91703d3fSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf, op, 0, impl->evecs,
165*91703d3fSjeremylt                                      impl->evecsin, impl->qvecsin, 0,
166aedaa0e5Sjeremylt                                      numinputfields, Q);
167aedaa0e5Sjeremylt   CeedChk(ierr);
168885ac19cSjeremylt 
169885ac19cSjeremylt   // Outfields
170*91703d3fSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf, op, 1, impl->evecs,
171*91703d3fSjeremylt                                      impl->evecsout, impl->qvecsout,
172aedaa0e5Sjeremylt                                      numinputfields, numoutputfields, Q);
173d1bcdac9Sjeremylt   CeedChk(ierr);
174885ac19cSjeremylt 
1754ce2993fSjeremylt   ierr = CeedOperatorSetSetupDone(op); CeedChk(ierr);
176885ac19cSjeremylt 
177885ac19cSjeremylt   return 0;
178885ac19cSjeremylt }
179885ac19cSjeremylt 
180885ac19cSjeremylt static int CeedOperatorApply_Ref(CeedOperator op, CeedVector invec,
181885ac19cSjeremylt                                  CeedVector outvec, CeedRequest *request) {
182885ac19cSjeremylt   int ierr;
1834ce2993fSjeremylt   CeedOperator_Ref *impl;
1844ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void*)&impl); CeedChk(ierr);
1854ce2993fSjeremylt   CeedQFunction qf;
1864ce2993fSjeremylt   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
187d1bcdac9Sjeremylt   CeedInt Q, numelements, elemsize, numinputfields, numoutputfields, ncomp;
1884ce2993fSjeremylt   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr);
1894ce2993fSjeremylt   ierr = CeedOperatorGetNumElements(op, &numelements); CeedChk(ierr);
1904ce2993fSjeremylt   ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
1914ce2993fSjeremylt   CeedChk(ierr);
1924dccadb6Sjeremylt   CeedTransposeMode lmode;
193d1bcdac9Sjeremylt   CeedOperatorField *opinputfields, *opoutputfields;
194d1bcdac9Sjeremylt   ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields);
195d1bcdac9Sjeremylt   CeedChk(ierr);
196d1bcdac9Sjeremylt   CeedQFunctionField *qfinputfields, *qfoutputfields;
197d1bcdac9Sjeremylt   ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields);
198d1bcdac9Sjeremylt   CeedChk(ierr);
199d1bcdac9Sjeremylt   CeedEvalMode emode;
200d1bcdac9Sjeremylt   CeedVector vec;
201d1bcdac9Sjeremylt   CeedBasis basis;
202d1bcdac9Sjeremylt   CeedElemRestriction Erestrict;
203885ac19cSjeremylt 
204885ac19cSjeremylt   // Setup
205885ac19cSjeremylt   ierr = CeedOperatorSetup_Ref(op); CeedChk(ierr);
206885ac19cSjeremylt 
207885ac19cSjeremylt   // Input Evecs and Restriction
2081a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
209d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
210d1bcdac9Sjeremylt     CeedChk(ierr);
211135a076eSjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
212668048e2SJed Brown     } else {
213d1bcdac9Sjeremylt       // Get input vector
214d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetVector(opinputfields[i], &vec); CeedChk(ierr);
215d1bcdac9Sjeremylt       if (vec == CEED_VECTOR_ACTIVE)
216d1bcdac9Sjeremylt         vec = invec;
217668048e2SJed Brown       // Restrict
218d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opinputfields[i], &Erestrict);
219d1bcdac9Sjeremylt       CeedChk(ierr);
2204dccadb6Sjeremylt       ierr = CeedOperatorFieldGetLMode(opinputfields[i], &lmode); CeedChk(ierr);
221d1bcdac9Sjeremylt       ierr = CeedElemRestrictionApply(Erestrict, CEED_NOTRANSPOSE,
222d1bcdac9Sjeremylt                                       lmode, vec, impl->evecs[i],
223668048e2SJed Brown                                       request); CeedChk(ierr);
224668048e2SJed Brown       // Get evec
225a2b73c81Sjeremylt       ierr = CeedVectorGetArrayRead(impl->evecs[i], CEED_MEM_HOST,
226d1bcdac9Sjeremylt                                     (const CeedScalar **) &impl->edata[i]);
227d1bcdac9Sjeremylt       CeedChk(ierr);
228885ac19cSjeremylt     }
229885ac19cSjeremylt   }
230885ac19cSjeremylt 
231885ac19cSjeremylt   // Output Evecs
2321a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
233a2b73c81Sjeremylt     ierr = CeedVectorGetArray(impl->evecs[i+impl->numein], CEED_MEM_HOST,
2341a4ead9bSjeremylt                               &impl->edata[i + numinputfields]); CeedChk(ierr);
235885ac19cSjeremylt   }
236885ac19cSjeremylt 
237885ac19cSjeremylt   // Loop through elements
2384ce2993fSjeremylt   for (CeedInt e=0; e<numelements; e++) {
239885ac19cSjeremylt     // Input basis apply if needed
2401a4ead9bSjeremylt     for (CeedInt i=0; i<numinputfields; i++) {
241135a076eSjeremylt       // Get elemsize, emode, ncomp
242d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opinputfields[i], &Erestrict);
243d1bcdac9Sjeremylt       CeedChk(ierr);
244d1bcdac9Sjeremylt       ierr = CeedElemRestrictionGetElementSize(Erestrict, &elemsize);
245d1bcdac9Sjeremylt       CeedChk(ierr);
246d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
247d1bcdac9Sjeremylt       CeedChk(ierr);
248d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qfinputfields[i], &ncomp);
249d1bcdac9Sjeremylt       CeedChk(ierr);
250885ac19cSjeremylt       // Basis action
251885ac19cSjeremylt       switch(emode) {
252885ac19cSjeremylt       case CEED_EVAL_NONE:
253aedaa0e5Sjeremylt         ierr = CeedVectorSetArray(impl->qvecsin[i], CEED_MEM_HOST,
254aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
255aedaa0e5Sjeremylt                                   &impl->edata[i][e*Q*ncomp]); CeedChk(ierr);
256885ac19cSjeremylt         break;
257885ac19cSjeremylt       case CEED_EVAL_INTERP:
258d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); CeedChk(ierr);
259*91703d3fSjeremylt         ierr = CeedVectorSetArray(impl->evecsin[i], CEED_MEM_HOST,
260aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
261aedaa0e5Sjeremylt                                   &impl->edata[i][e*elemsize*ncomp]);
262aedaa0e5Sjeremylt         CeedChk(ierr);
263d1bcdac9Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE,
264*91703d3fSjeremylt                               CEED_EVAL_INTERP, impl->evecsin[i],
265aedaa0e5Sjeremylt                               impl->qvecsin[i]); CeedChk(ierr);
266885ac19cSjeremylt         break;
267885ac19cSjeremylt       case CEED_EVAL_GRAD:
268d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); CeedChk(ierr);
269*91703d3fSjeremylt         ierr = CeedVectorSetArray(impl->evecsin[i], CEED_MEM_HOST,
270aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
271aedaa0e5Sjeremylt                                   &impl->edata[i][e*elemsize*ncomp]);
272aedaa0e5Sjeremylt         CeedChk(ierr);
273d1bcdac9Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE,
274*91703d3fSjeremylt                               CEED_EVAL_GRAD, impl->evecsin[i],
275aedaa0e5Sjeremylt                               impl->qvecsin[i]); CeedChk(ierr);
276885ac19cSjeremylt         break;
277885ac19cSjeremylt       case CEED_EVAL_WEIGHT:
278885ac19cSjeremylt         break;  // No action
279885ac19cSjeremylt       case CEED_EVAL_DIV:
280885ac19cSjeremylt         break; // Not implimented
281885ac19cSjeremylt       case CEED_EVAL_CURL:
282885ac19cSjeremylt         break; // Not implimented
283885ac19cSjeremylt       }
284885ac19cSjeremylt     }
285885ac19cSjeremylt     // Output pointers
2861a4ead9bSjeremylt     for (CeedInt i=0; i<numoutputfields; i++) {
287d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode);
288d1bcdac9Sjeremylt       CeedChk(ierr);
289885ac19cSjeremylt       if (emode == CEED_EVAL_NONE) {
290d1bcdac9Sjeremylt         ierr = CeedQFunctionFieldGetNumComponents(qfoutputfields[i], &ncomp);
291d1bcdac9Sjeremylt         CeedChk(ierr);
292aedaa0e5Sjeremylt         ierr = CeedVectorSetArray(impl->qvecsout[i], CEED_MEM_HOST,
293aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
294aedaa0e5Sjeremylt                                   &impl->edata[i + numinputfields][e*Q*ncomp]);
295aedaa0e5Sjeremylt         CeedChk(ierr);
296885ac19cSjeremylt       }
297885ac19cSjeremylt     }
298885ac19cSjeremylt     // Q function
299aedaa0e5Sjeremylt     ierr = CeedQFunctionApply(qf, Q, impl->qvecsin, impl->qvecsout); CeedChk(ierr);
300885ac19cSjeremylt 
301885ac19cSjeremylt     // Output basis apply if needed
3021a4ead9bSjeremylt     for (CeedInt i=0; i<numoutputfields; i++) {
303135a076eSjeremylt       // Get elemsize, emode, ncomp
304d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opoutputfields[i], &Erestrict);
305d1bcdac9Sjeremylt       CeedChk(ierr);
306d1bcdac9Sjeremylt       ierr = CeedElemRestrictionGetElementSize(Erestrict, &elemsize);
307d1bcdac9Sjeremylt       CeedChk(ierr);
308d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode);
309d1bcdac9Sjeremylt       CeedChk(ierr);
310d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qfoutputfields[i], &ncomp);
311d1bcdac9Sjeremylt       CeedChk(ierr);
312885ac19cSjeremylt       // Basis action
313885ac19cSjeremylt       switch(emode) {
314885ac19cSjeremylt       case CEED_EVAL_NONE:
315885ac19cSjeremylt         break; // No action
316885ac19cSjeremylt       case CEED_EVAL_INTERP:
317d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opoutputfields[i], &basis);
318d1bcdac9Sjeremylt         CeedChk(ierr);
319*91703d3fSjeremylt         ierr = CeedVectorSetArray(impl->evecsout[i], CEED_MEM_HOST,
320aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
3211a4ead9bSjeremylt                                   &impl->edata[i + numinputfields][e*elemsize*ncomp]);
322aedaa0e5Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
323aedaa0e5Sjeremylt                               CEED_EVAL_INTERP, impl->qvecsout[i],
324*91703d3fSjeremylt                               impl->evecsout[i]); CeedChk(ierr);
325885ac19cSjeremylt         break;
326885ac19cSjeremylt       case CEED_EVAL_GRAD:
327d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opoutputfields[i], &basis);
328d1bcdac9Sjeremylt         CeedChk(ierr);
329*91703d3fSjeremylt         ierr = CeedVectorSetArray(impl->evecsout[i], CEED_MEM_HOST,
330aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
331d1bcdac9Sjeremylt                                   &impl->edata[i + numinputfields][e*elemsize*ncomp]);
332aedaa0e5Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
333aedaa0e5Sjeremylt                               CEED_EVAL_GRAD, impl->qvecsout[i],
334*91703d3fSjeremylt                               impl->evecsout[i]); CeedChk(ierr);
335885ac19cSjeremylt         break;
3364ce2993fSjeremylt       case CEED_EVAL_WEIGHT: {
3374ce2993fSjeremylt         Ceed ceed;
3384ce2993fSjeremylt         ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
3394ce2993fSjeremylt         return CeedError(ceed, 1,
3408d94b059Sjeremylt                          "CEED_EVAL_WEIGHT cannot be an output evaluation mode");
341885ac19cSjeremylt         break; // Should not occur
3424ce2993fSjeremylt       }
343885ac19cSjeremylt       case CEED_EVAL_DIV:
344885ac19cSjeremylt         break; // Not implimented
345885ac19cSjeremylt       case CEED_EVAL_CURL:
346885ac19cSjeremylt         break; // Not implimented
347885ac19cSjeremylt       }
348885ac19cSjeremylt     }
349885ac19cSjeremylt   }
350885ac19cSjeremylt 
35142ecf959Sjeremylt   // Zero lvecs
352d1bcdac9Sjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
353d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); CeedChk(ierr);
354d1bcdac9Sjeremylt     if (vec == CEED_VECTOR_ACTIVE)
355d1bcdac9Sjeremylt       vec = outvec;
356d1bcdac9Sjeremylt     ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
35742ecf959Sjeremylt   }
35842ecf959Sjeremylt 
359885ac19cSjeremylt   // Output restriction
3601a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
361a2b73c81Sjeremylt     // Restore evec
362a2b73c81Sjeremylt     ierr = CeedVectorRestoreArray(impl->evecs[i+impl->numein],
363d1bcdac9Sjeremylt                                   &impl->edata[i + numinputfields]);
364d1bcdac9Sjeremylt     CeedChk(ierr);
365d1bcdac9Sjeremylt     // Get output vector
366d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); CeedChk(ierr);
367668048e2SJed Brown     // Active
368d1bcdac9Sjeremylt     if (vec == CEED_VECTOR_ACTIVE)
369d1bcdac9Sjeremylt       vec = outvec;
3707ca8db16Sjeremylt     // Restrict
371d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetElemRestriction(opoutputfields[i], &Erestrict);
372d1bcdac9Sjeremylt     CeedChk(ierr);
3734dccadb6Sjeremylt     ierr = CeedOperatorFieldGetLMode(opoutputfields[i], &lmode); CeedChk(ierr);
374d1bcdac9Sjeremylt     ierr = CeedElemRestrictionApply(Erestrict, CEED_TRANSPOSE,
375d1bcdac9Sjeremylt                                     lmode, impl->evecs[i+impl->numein], vec,
376668048e2SJed Brown                                     request); CeedChk(ierr);
377885ac19cSjeremylt   }
378885ac19cSjeremylt 
3797ca8db16Sjeremylt   // Restore input arrays
3801a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
381d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
382d1bcdac9Sjeremylt     CeedChk(ierr);
383135a076eSjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
3847ca8db16Sjeremylt     } else {
385a2b73c81Sjeremylt       ierr = CeedVectorRestoreArrayRead(impl->evecs[i],
386d1bcdac9Sjeremylt                                         (const CeedScalar **) &impl->edata[i]);
387d1bcdac9Sjeremylt       CeedChk(ierr);
3887ca8db16Sjeremylt     }
3897ca8db16Sjeremylt   }
3907ca8db16Sjeremylt 
39121617c04Sjeremylt   return 0;
39221617c04Sjeremylt }
39321617c04Sjeremylt 
39421617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) {
39521617c04Sjeremylt   int ierr;
396fe2413ffSjeremylt   Ceed ceed;
397fe2413ffSjeremylt   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
3984ce2993fSjeremylt   CeedOperator_Ref *impl;
39921617c04Sjeremylt 
40021617c04Sjeremylt   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
401fe2413ffSjeremylt   ierr = CeedOperatorSetData(op, (void*)&impl);
402fe2413ffSjeremylt 
403fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Apply",
404fe2413ffSjeremylt                                 CeedOperatorApply_Ref); CeedChk(ierr);
405fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Destroy",
406fe2413ffSjeremylt                                 CeedOperatorDestroy_Ref); CeedChk(ierr);
40721617c04Sjeremylt   return 0;
40821617c04Sjeremylt }
409