xref: /libCEED/backends/ref/ceed-ref-operator.c (revision 8c91a0c98588ec4c767fca1c07a5e6e035c21fe6)
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-ref.h"
1821617c04Sjeremylt 
1921617c04Sjeremylt static int CeedOperatorDestroy_Ref(CeedOperator op) {
2021617c04Sjeremylt   int ierr;
214ce2993fSjeremylt   CeedOperator_Ref *impl;
224ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void *)&impl); CeedChk(ierr);
2321617c04Sjeremylt 
24885ac19cSjeremylt   for (CeedInt i=0; i<impl->numein+impl->numeout; i++) {
25885ac19cSjeremylt     ierr = CeedVectorDestroy(&impl->evecs[i]); CeedChk(ierr);
26885ac19cSjeremylt   }
27885ac19cSjeremylt   ierr = CeedFree(&impl->evecs); CeedChk(ierr);
28885ac19cSjeremylt   ierr = CeedFree(&impl->edata); CeedChk(ierr);
298d713cf6Sjeremylt   ierr = CeedFree(&impl->inputstate); CeedChk(ierr);
30885ac19cSjeremylt 
31aedaa0e5Sjeremylt   for (CeedInt i=0; i<impl->numein; i++) {
3291703d3fSjeremylt     ierr = CeedVectorDestroy(&impl->evecsin[i]); CeedChk(ierr);
33aedaa0e5Sjeremylt     ierr = CeedVectorDestroy(&impl->qvecsin[i]); CeedChk(ierr);
34885ac19cSjeremylt   }
3591703d3fSjeremylt   ierr = CeedFree(&impl->evecsin); CeedChk(ierr);
36aedaa0e5Sjeremylt   ierr = CeedFree(&impl->qvecsin); CeedChk(ierr);
37885ac19cSjeremylt 
38aedaa0e5Sjeremylt   for (CeedInt i=0; i<impl->numeout; i++) {
3991703d3fSjeremylt     ierr = CeedVectorDestroy(&impl->evecsout[i]); CeedChk(ierr);
40aedaa0e5Sjeremylt     ierr = CeedVectorDestroy(&impl->qvecsout[i]); CeedChk(ierr);
41aedaa0e5Sjeremylt   }
4291703d3fSjeremylt   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,
5391703d3fSjeremylt                                        bool inOrOut,
5491703d3fSjeremylt                                        CeedVector *fullevecs, CeedVector *evecs,
55aedaa0e5Sjeremylt                                        CeedVector *qvecs, CeedInt starte,
56135a076eSjeremylt                                        CeedInt numfields, CeedInt Q) {
574d1cd9fcSJeremy L Thompson   CeedInt dim, ierr, ncomp, P;
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,
8591703d3fSjeremylt                                              &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);
984d1cd9fcSJeremy L Thompson       ierr = CeedElemRestrictionGetElementSize(Erestrict, &P);
994d1cd9fcSJeremy L Thompson       CeedChk(ierr);
1004d1cd9fcSJeremy L Thompson       ierr = CeedVectorCreate(ceed, P*ncomp, &evecs[i]); CeedChk(ierr);
101aedaa0e5Sjeremylt       ierr = CeedVectorCreate(ceed, Q*ncomp, &qvecs[i]); CeedChk(ierr);
102885ac19cSjeremylt       break;
103885ac19cSjeremylt     case CEED_EVAL_GRAD:
104aedaa0e5Sjeremylt       ierr = CeedOperatorFieldGetBasis(opfields[i], &basis); CeedChk(ierr);
105aedaa0e5Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qffields[i], &ncomp);
106de686571SJeremy L Thompson       CeedChk(ierr);
107d1bcdac9Sjeremylt       ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
1084d1cd9fcSJeremy L Thompson       ierr = CeedElemRestrictionGetElementSize(Erestrict, &P);
1094d1cd9fcSJeremy L Thompson       CeedChk(ierr);
1104d1cd9fcSJeremy L Thompson       ierr = CeedVectorCreate(ceed, P*ncomp, &evecs[i]); CeedChk(ierr);
111aedaa0e5Sjeremylt       ierr = CeedVectorCreate(ceed, Q*ncomp*dim, &qvecs[i]); CeedChk(ierr);
112885ac19cSjeremylt       break;
113885ac19cSjeremylt     case CEED_EVAL_WEIGHT: // Only on input fields
114aedaa0e5Sjeremylt       ierr = CeedOperatorFieldGetBasis(opfields[i], &basis); CeedChk(ierr);
115aedaa0e5Sjeremylt       ierr = CeedVectorCreate(ceed, Q, &qvecs[i]); CeedChk(ierr);
116d1bcdac9Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT,
117aedaa0e5Sjeremylt                             NULL, qvecs[i]); CeedChk(ierr);
118885ac19cSjeremylt       break;
119885ac19cSjeremylt     case CEED_EVAL_DIV:
120885ac19cSjeremylt       break; // Not implimented
121885ac19cSjeremylt     case CEED_EVAL_CURL:
122885ac19cSjeremylt       break; // Not implimented
12321617c04Sjeremylt     }
124885ac19cSjeremylt   }
12521617c04Sjeremylt   return 0;
12621617c04Sjeremylt }
12721617c04Sjeremylt 
128885ac19cSjeremylt /*
129885ac19cSjeremylt   CeedOperator needs to connect all the named fields (be they active or passive)
130885ac19cSjeremylt   to the named inputs and outputs of its CeedQFunction.
131885ac19cSjeremylt  */
132885ac19cSjeremylt static int CeedOperatorSetup_Ref(CeedOperator op) {
13321617c04Sjeremylt   int ierr;
1344ce2993fSjeremylt   bool setupdone;
1354ce2993fSjeremylt   ierr = CeedOperatorGetSetupStatus(op, &setupdone); CeedChk(ierr);
1364ce2993fSjeremylt   if (setupdone) return 0;
137aedaa0e5Sjeremylt   Ceed ceed;
138aedaa0e5Sjeremylt   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
1394ce2993fSjeremylt   CeedOperator_Ref *impl;
1404ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void *)&impl); CeedChk(ierr);
1414ce2993fSjeremylt   CeedQFunction qf;
1424ce2993fSjeremylt   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
1434ce2993fSjeremylt   CeedInt Q, numinputfields, numoutputfields;
1444ce2993fSjeremylt   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr);
145a8de75f0Sjeremylt   ierr = CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
146a8de75f0Sjeremylt   CeedChk(ierr);
147d1bcdac9Sjeremylt   CeedOperatorField *opinputfields, *opoutputfields;
148d1bcdac9Sjeremylt   ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields);
149d1bcdac9Sjeremylt   CeedChk(ierr);
150d1bcdac9Sjeremylt   CeedQFunctionField *qfinputfields, *qfoutputfields;
151d1bcdac9Sjeremylt   ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields);
152d1bcdac9Sjeremylt   CeedChk(ierr);
153885ac19cSjeremylt 
154885ac19cSjeremylt   // Allocate
155aedaa0e5Sjeremylt   ierr = CeedCalloc(numinputfields + numoutputfields, &impl->evecs);
156aedaa0e5Sjeremylt   CeedChk(ierr);
157aedaa0e5Sjeremylt   ierr = CeedCalloc(numinputfields + numoutputfields, &impl->edata);
158885ac19cSjeremylt   CeedChk(ierr);
159885ac19cSjeremylt 
1608d713cf6Sjeremylt   ierr = CeedCalloc(16, &impl->inputstate); CeedChk(ierr);
16191703d3fSjeremylt   ierr = CeedCalloc(16, &impl->evecsin); CeedChk(ierr);
16291703d3fSjeremylt   ierr = CeedCalloc(16, &impl->evecsout); CeedChk(ierr);
163aedaa0e5Sjeremylt   ierr = CeedCalloc(16, &impl->qvecsin); CeedChk(ierr);
164aedaa0e5Sjeremylt   ierr = CeedCalloc(16, &impl->qvecsout); CeedChk(ierr);
165885ac19cSjeremylt 
166aedaa0e5Sjeremylt   impl->numein = numinputfields; impl->numeout = numoutputfields;
167885ac19cSjeremylt 
168aedaa0e5Sjeremylt   // Set up infield and outfield evecs and qvecs
169885ac19cSjeremylt   // Infields
17091703d3fSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf, op, 0, impl->evecs,
17191703d3fSjeremylt                                      impl->evecsin, impl->qvecsin, 0,
172aedaa0e5Sjeremylt                                      numinputfields, Q);
173aedaa0e5Sjeremylt   CeedChk(ierr);
174885ac19cSjeremylt 
175885ac19cSjeremylt   // Outfields
17691703d3fSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf, op, 1, impl->evecs,
17791703d3fSjeremylt                                      impl->evecsout, impl->qvecsout,
178aedaa0e5Sjeremylt                                      numinputfields, numoutputfields, Q);
179d1bcdac9Sjeremylt   CeedChk(ierr);
180885ac19cSjeremylt 
1814ce2993fSjeremylt   ierr = CeedOperatorSetSetupDone(op); CeedChk(ierr);
182885ac19cSjeremylt 
183885ac19cSjeremylt   return 0;
184885ac19cSjeremylt }
185885ac19cSjeremylt 
186885ac19cSjeremylt static int CeedOperatorApply_Ref(CeedOperator op, CeedVector invec,
187885ac19cSjeremylt                                  CeedVector outvec, CeedRequest *request) {
188885ac19cSjeremylt   int ierr;
1894ce2993fSjeremylt   CeedOperator_Ref *impl;
1904ce2993fSjeremylt   ierr = CeedOperatorGetData(op, (void *)&impl); CeedChk(ierr);
1914ce2993fSjeremylt   CeedQFunction qf;
1924ce2993fSjeremylt   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
193d1bcdac9Sjeremylt   CeedInt Q, numelements, elemsize, numinputfields, numoutputfields, ncomp;
1944ce2993fSjeremylt   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr);
1954ce2993fSjeremylt   ierr = CeedOperatorGetNumElements(op, &numelements); CeedChk(ierr);
1964ce2993fSjeremylt   ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
1974ce2993fSjeremylt   CeedChk(ierr);
1984dccadb6Sjeremylt   CeedTransposeMode lmode;
199d1bcdac9Sjeremylt   CeedOperatorField *opinputfields, *opoutputfields;
200d1bcdac9Sjeremylt   ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields);
201d1bcdac9Sjeremylt   CeedChk(ierr);
202d1bcdac9Sjeremylt   CeedQFunctionField *qfinputfields, *qfoutputfields;
203d1bcdac9Sjeremylt   ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields);
204d1bcdac9Sjeremylt   CeedChk(ierr);
205d1bcdac9Sjeremylt   CeedEvalMode emode;
206d1bcdac9Sjeremylt   CeedVector vec;
207d1bcdac9Sjeremylt   CeedBasis basis;
208d1bcdac9Sjeremylt   CeedElemRestriction Erestrict;
2098d713cf6Sjeremylt   uint64_t state;
210885ac19cSjeremylt 
211885ac19cSjeremylt   // Setup
212885ac19cSjeremylt   ierr = CeedOperatorSetup_Ref(op); CeedChk(ierr);
213885ac19cSjeremylt 
214885ac19cSjeremylt   // Input Evecs and Restriction
2151a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
216d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
217d1bcdac9Sjeremylt     CeedChk(ierr);
218135a076eSjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
219668048e2SJed Brown     } else {
220d1bcdac9Sjeremylt       // Get input vector
221d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetVector(opinputfields[i], &vec); CeedChk(ierr);
222d1bcdac9Sjeremylt       if (vec == CEED_VECTOR_ACTIVE)
223d1bcdac9Sjeremylt         vec = invec;
224668048e2SJed Brown       // Restrict
2258d713cf6Sjeremylt       ierr = CeedVectorGetState(vec, &state); CeedChk(ierr);
2268d713cf6Sjeremylt       // Skip restriction if input is unchanged
2278d713cf6Sjeremylt       if (state != impl->inputstate[i] || vec == invec) {
228d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetElemRestriction(opinputfields[i], &Erestrict);
229d1bcdac9Sjeremylt         CeedChk(ierr);
2304dccadb6Sjeremylt         ierr = CeedOperatorFieldGetLMode(opinputfields[i], &lmode); CeedChk(ierr);
231d1bcdac9Sjeremylt         ierr = CeedElemRestrictionApply(Erestrict, CEED_NOTRANSPOSE,
232d1bcdac9Sjeremylt                                         lmode, vec, impl->evecs[i],
233668048e2SJed Brown                                         request); CeedChk(ierr);
2348d713cf6Sjeremylt         impl->inputstate[i] = state;
2358d713cf6Sjeremylt       }
236668048e2SJed Brown       // Get evec
237a2b73c81Sjeremylt       ierr = CeedVectorGetArrayRead(impl->evecs[i], CEED_MEM_HOST,
238d1bcdac9Sjeremylt                                     (const CeedScalar **) &impl->edata[i]);
239d1bcdac9Sjeremylt       CeedChk(ierr);
240885ac19cSjeremylt     }
241885ac19cSjeremylt   }
242885ac19cSjeremylt 
243885ac19cSjeremylt   // Output Evecs
2441a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
245a2b73c81Sjeremylt     ierr = CeedVectorGetArray(impl->evecs[i+impl->numein], CEED_MEM_HOST,
2461a4ead9bSjeremylt                               &impl->edata[i + numinputfields]); CeedChk(ierr);
247885ac19cSjeremylt   }
248885ac19cSjeremylt 
249885ac19cSjeremylt   // Loop through elements
2504ce2993fSjeremylt   for (CeedInt e=0; e<numelements; e++) {
251885ac19cSjeremylt     // Input basis apply if needed
2521a4ead9bSjeremylt     for (CeedInt i=0; i<numinputfields; i++) {
253135a076eSjeremylt       // Get elemsize, emode, ncomp
254d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opinputfields[i], &Erestrict);
255d1bcdac9Sjeremylt       CeedChk(ierr);
256d1bcdac9Sjeremylt       ierr = CeedElemRestrictionGetElementSize(Erestrict, &elemsize);
257d1bcdac9Sjeremylt       CeedChk(ierr);
258d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
259d1bcdac9Sjeremylt       CeedChk(ierr);
260d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qfinputfields[i], &ncomp);
261d1bcdac9Sjeremylt       CeedChk(ierr);
262885ac19cSjeremylt       // Basis action
263885ac19cSjeremylt       switch(emode) {
264885ac19cSjeremylt       case CEED_EVAL_NONE:
265aedaa0e5Sjeremylt         ierr = CeedVectorSetArray(impl->qvecsin[i], CEED_MEM_HOST,
266aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
267aedaa0e5Sjeremylt                                   &impl->edata[i][e*Q*ncomp]); CeedChk(ierr);
268885ac19cSjeremylt         break;
269885ac19cSjeremylt       case CEED_EVAL_INTERP:
270d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); CeedChk(ierr);
27191703d3fSjeremylt         ierr = CeedVectorSetArray(impl->evecsin[i], CEED_MEM_HOST,
272aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
273aedaa0e5Sjeremylt                                   &impl->edata[i][e*elemsize*ncomp]);
274aedaa0e5Sjeremylt         CeedChk(ierr);
275d1bcdac9Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE,
27691703d3fSjeremylt                               CEED_EVAL_INTERP, impl->evecsin[i],
277aedaa0e5Sjeremylt                               impl->qvecsin[i]); CeedChk(ierr);
278885ac19cSjeremylt         break;
279885ac19cSjeremylt       case CEED_EVAL_GRAD:
280d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); CeedChk(ierr);
28191703d3fSjeremylt         ierr = CeedVectorSetArray(impl->evecsin[i], CEED_MEM_HOST,
282aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
283aedaa0e5Sjeremylt                                   &impl->edata[i][e*elemsize*ncomp]);
284aedaa0e5Sjeremylt         CeedChk(ierr);
285d1bcdac9Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE,
28691703d3fSjeremylt                               CEED_EVAL_GRAD, impl->evecsin[i],
287aedaa0e5Sjeremylt                               impl->qvecsin[i]); CeedChk(ierr);
288885ac19cSjeremylt         break;
289885ac19cSjeremylt       case CEED_EVAL_WEIGHT:
290885ac19cSjeremylt         break;  // No action
291885ac19cSjeremylt       case CEED_EVAL_DIV:
292885ac19cSjeremylt         break; // Not implimented
293885ac19cSjeremylt       case CEED_EVAL_CURL:
294885ac19cSjeremylt         break; // Not implimented
295885ac19cSjeremylt       }
296885ac19cSjeremylt     }
297885ac19cSjeremylt     // Output pointers
2981a4ead9bSjeremylt     for (CeedInt i=0; i<numoutputfields; i++) {
299d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode);
300d1bcdac9Sjeremylt       CeedChk(ierr);
301885ac19cSjeremylt       if (emode == CEED_EVAL_NONE) {
302d1bcdac9Sjeremylt         ierr = CeedQFunctionFieldGetNumComponents(qfoutputfields[i], &ncomp);
303d1bcdac9Sjeremylt         CeedChk(ierr);
304aedaa0e5Sjeremylt         ierr = CeedVectorSetArray(impl->qvecsout[i], CEED_MEM_HOST,
305aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
306aedaa0e5Sjeremylt                                   &impl->edata[i + numinputfields][e*Q*ncomp]);
307aedaa0e5Sjeremylt         CeedChk(ierr);
308885ac19cSjeremylt       }
309885ac19cSjeremylt     }
310885ac19cSjeremylt     // Q function
311aedaa0e5Sjeremylt     ierr = CeedQFunctionApply(qf, Q, impl->qvecsin, impl->qvecsout); CeedChk(ierr);
312885ac19cSjeremylt 
313885ac19cSjeremylt     // Output basis apply if needed
3141a4ead9bSjeremylt     for (CeedInt i=0; i<numoutputfields; i++) {
315135a076eSjeremylt       // Get elemsize, emode, ncomp
316d1bcdac9Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opoutputfields[i], &Erestrict);
317d1bcdac9Sjeremylt       CeedChk(ierr);
318d1bcdac9Sjeremylt       ierr = CeedElemRestrictionGetElementSize(Erestrict, &elemsize);
319d1bcdac9Sjeremylt       CeedChk(ierr);
320d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode);
321d1bcdac9Sjeremylt       CeedChk(ierr);
322d1bcdac9Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qfoutputfields[i], &ncomp);
323d1bcdac9Sjeremylt       CeedChk(ierr);
324885ac19cSjeremylt       // Basis action
325885ac19cSjeremylt       switch(emode) {
326885ac19cSjeremylt       case CEED_EVAL_NONE:
327885ac19cSjeremylt         break; // No action
328885ac19cSjeremylt       case CEED_EVAL_INTERP:
329d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opoutputfields[i], &basis);
330d1bcdac9Sjeremylt         CeedChk(ierr);
33191703d3fSjeremylt         ierr = CeedVectorSetArray(impl->evecsout[i], CEED_MEM_HOST,
332aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
3331a4ead9bSjeremylt                                   &impl->edata[i + numinputfields][e*elemsize*ncomp]);
334de686571SJeremy L Thompson         CeedChk(ierr);
335aedaa0e5Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
336aedaa0e5Sjeremylt                               CEED_EVAL_INTERP, impl->qvecsout[i],
33791703d3fSjeremylt                               impl->evecsout[i]); CeedChk(ierr);
338885ac19cSjeremylt         break;
339885ac19cSjeremylt       case CEED_EVAL_GRAD:
340d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opoutputfields[i], &basis);
341d1bcdac9Sjeremylt         CeedChk(ierr);
34291703d3fSjeremylt         ierr = CeedVectorSetArray(impl->evecsout[i], CEED_MEM_HOST,
343aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
344d1bcdac9Sjeremylt                                   &impl->edata[i + numinputfields][e*elemsize*ncomp]);
345de686571SJeremy L Thompson         CeedChk(ierr);
346aedaa0e5Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
347aedaa0e5Sjeremylt                               CEED_EVAL_GRAD, impl->qvecsout[i],
34891703d3fSjeremylt                               impl->evecsout[i]); CeedChk(ierr);
349885ac19cSjeremylt         break;
3504ce2993fSjeremylt       case CEED_EVAL_WEIGHT: {
3514ce2993fSjeremylt         Ceed ceed;
3524ce2993fSjeremylt         ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
3534ce2993fSjeremylt         return CeedError(ceed, 1,
3548d94b059Sjeremylt                          "CEED_EVAL_WEIGHT cannot be an output evaluation mode");
355885ac19cSjeremylt         break; // Should not occur
3564ce2993fSjeremylt       }
357885ac19cSjeremylt       case CEED_EVAL_DIV:
358*8c91a0c9SJeremy L Thompson         break; // Not implemented
359885ac19cSjeremylt       case CEED_EVAL_CURL:
360*8c91a0c9SJeremy L Thompson         break; // Not implemented
361885ac19cSjeremylt       }
362885ac19cSjeremylt     }
363885ac19cSjeremylt   }
364885ac19cSjeremylt 
36542ecf959Sjeremylt   // Zero lvecs
366d1bcdac9Sjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
367d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); CeedChk(ierr);
36852d6035fSJeremy L Thompson     if (vec == CEED_VECTOR_ACTIVE) {
36952d6035fSJeremy L Thompson       if (!impl->add) {
370d1bcdac9Sjeremylt         vec = outvec;
371d1bcdac9Sjeremylt         ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
37242ecf959Sjeremylt       }
37352d6035fSJeremy L Thompson     } else {
37452d6035fSJeremy L Thompson       ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
37552d6035fSJeremy L Thompson     }
37652d6035fSJeremy L Thompson   }
37752d6035fSJeremy L Thompson   impl->add = false;
37842ecf959Sjeremylt 
379885ac19cSjeremylt   // Output restriction
3801a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
381a2b73c81Sjeremylt     // Restore evec
382a2b73c81Sjeremylt     ierr = CeedVectorRestoreArray(impl->evecs[i+impl->numein],
383d1bcdac9Sjeremylt                                   &impl->edata[i + numinputfields]);
384d1bcdac9Sjeremylt     CeedChk(ierr);
385d1bcdac9Sjeremylt     // Get output vector
386d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); CeedChk(ierr);
387668048e2SJed Brown     // Active
388d1bcdac9Sjeremylt     if (vec == CEED_VECTOR_ACTIVE)
389d1bcdac9Sjeremylt       vec = outvec;
3907ca8db16Sjeremylt     // Restrict
391d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetElemRestriction(opoutputfields[i], &Erestrict);
392d1bcdac9Sjeremylt     CeedChk(ierr);
3934dccadb6Sjeremylt     ierr = CeedOperatorFieldGetLMode(opoutputfields[i], &lmode); CeedChk(ierr);
394d1bcdac9Sjeremylt     ierr = CeedElemRestrictionApply(Erestrict, CEED_TRANSPOSE,
395d1bcdac9Sjeremylt                                     lmode, impl->evecs[i+impl->numein], vec,
396668048e2SJed Brown                                     request); CeedChk(ierr);
397885ac19cSjeremylt   }
398885ac19cSjeremylt 
3997ca8db16Sjeremylt   // Restore input arrays
4001a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
401d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
402d1bcdac9Sjeremylt     CeedChk(ierr);
403135a076eSjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
4047ca8db16Sjeremylt     } else {
405a2b73c81Sjeremylt       ierr = CeedVectorRestoreArrayRead(impl->evecs[i],
406d1bcdac9Sjeremylt                                         (const CeedScalar **) &impl->edata[i]);
407d1bcdac9Sjeremylt       CeedChk(ierr);
4087ca8db16Sjeremylt     }
4097ca8db16Sjeremylt   }
4107ca8db16Sjeremylt 
41121617c04Sjeremylt   return 0;
41221617c04Sjeremylt }
41321617c04Sjeremylt 
41452d6035fSJeremy L Thompson static int CeedCompositeOperatorApply_Ref(CeedOperator op, CeedVector invec,
41552d6035fSJeremy L Thompson     CeedVector outvec,
41652d6035fSJeremy L Thompson     CeedRequest *request) {
41752d6035fSJeremy L Thompson   int ierr;
41852d6035fSJeremy L Thompson   CeedInt numsub;
41952d6035fSJeremy L Thompson   CeedOperator_Ref *impl;
42052d6035fSJeremy L Thompson   CeedOperator *suboperators;
42152d6035fSJeremy L Thompson   ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
42252d6035fSJeremy L Thompson   ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
42352d6035fSJeremy L Thompson 
42452d6035fSJeremy L Thompson   // Overwrite outvec with first output
42552d6035fSJeremy L Thompson   ierr = CeedOperatorApply(suboperators[0], invec, outvec, request);
42652d6035fSJeremy L Thompson   CeedChk(ierr);
42752d6035fSJeremy L Thompson   // Add to outvec with subsequent outputs
42852d6035fSJeremy L Thompson   for (CeedInt i=1; i<numsub; i++) {
429de686571SJeremy L Thompson     ierr = CeedOperatorGetData(suboperators[i], (void *)&impl); CeedChk(ierr);
43052d6035fSJeremy L Thompson     impl->add = true;
43152d6035fSJeremy L Thompson     ierr = CeedOperatorApply(suboperators[i], invec, outvec, request);
43252d6035fSJeremy L Thompson     CeedChk(ierr);
43352d6035fSJeremy L Thompson   }
43452d6035fSJeremy L Thompson 
43552d6035fSJeremy L Thompson   return 0;
43652d6035fSJeremy L Thompson }
43752d6035fSJeremy L Thompson 
43821617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) {
43921617c04Sjeremylt   int ierr;
440fe2413ffSjeremylt   Ceed ceed;
441fe2413ffSjeremylt   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
4424ce2993fSjeremylt   CeedOperator_Ref *impl;
44321617c04Sjeremylt 
44421617c04Sjeremylt   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
44552d6035fSJeremy L Thompson   impl->add = false;
446de686571SJeremy L Thompson   ierr = CeedOperatorSetData(op, (void *)&impl); CeedChk(ierr);
447fe2413ffSjeremylt 
448fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Apply",
449fe2413ffSjeremylt                                 CeedOperatorApply_Ref); CeedChk(ierr);
450fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Destroy",
451fe2413ffSjeremylt                                 CeedOperatorDestroy_Ref); CeedChk(ierr);
45221617c04Sjeremylt   return 0;
45321617c04Sjeremylt }
45452d6035fSJeremy L Thompson 
45552d6035fSJeremy L Thompson int CeedCompositeOperatorCreate_Ref(CeedOperator op) {
45652d6035fSJeremy L Thompson   int ierr;
45752d6035fSJeremy L Thompson   Ceed ceed;
45852d6035fSJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
45952d6035fSJeremy L Thompson 
46052d6035fSJeremy L Thompson   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Apply",
46152d6035fSJeremy L Thompson                                 CeedCompositeOperatorApply_Ref); CeedChk(ierr);
46252d6035fSJeremy L Thompson   return 0;
46352d6035fSJeremy L Thompson }
464