xref: /libCEED/backends/ref/ceed-ref-operator.c (revision 52d6035f927efec34920a771ebaa7a03e4ffa966) !
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);
308d713cf6Sjeremylt   ierr = CeedFree(&impl->inputstate); CeedChk(ierr);
31885ac19cSjeremylt 
32aedaa0e5Sjeremylt   for (CeedInt i=0; i<impl->numein; i++) {
3391703d3fSjeremylt     ierr = CeedVectorDestroy(&impl->evecsin[i]); CeedChk(ierr);
34aedaa0e5Sjeremylt     ierr = CeedVectorDestroy(&impl->qvecsin[i]); CeedChk(ierr);
35885ac19cSjeremylt   }
3691703d3fSjeremylt   ierr = CeedFree(&impl->evecsin); CeedChk(ierr);
37aedaa0e5Sjeremylt   ierr = CeedFree(&impl->qvecsin); CeedChk(ierr);
38885ac19cSjeremylt 
39aedaa0e5Sjeremylt   for (CeedInt i=0; i<impl->numeout; i++) {
4091703d3fSjeremylt     ierr = CeedVectorDestroy(&impl->evecsout[i]); CeedChk(ierr);
41aedaa0e5Sjeremylt     ierr = CeedVectorDestroy(&impl->qvecsout[i]); CeedChk(ierr);
42aedaa0e5Sjeremylt   }
4391703d3fSjeremylt   ierr = CeedFree(&impl->evecsout); CeedChk(ierr);
44aedaa0e5Sjeremylt   ierr = CeedFree(&impl->qvecsout); CeedChk(ierr);
45885ac19cSjeremylt 
46fe2413ffSjeremylt   ierr = CeedFree(&impl); CeedChk(ierr);
4721617c04Sjeremylt   return 0;
4821617c04Sjeremylt }
4921617c04Sjeremylt 
50885ac19cSjeremylt /*
51885ac19cSjeremylt   Setup infields or outfields
52885ac19cSjeremylt  */
53fe2413ffSjeremylt static int CeedOperatorSetupFields_Ref(CeedQFunction qf, CeedOperator op,
5491703d3fSjeremylt                                        bool inOrOut,
5591703d3fSjeremylt                                        CeedVector *fullevecs, CeedVector *evecs,
56aedaa0e5Sjeremylt                                        CeedVector *qvecs, CeedInt starte,
57135a076eSjeremylt                                        CeedInt numfields, CeedInt Q) {
584d1cd9fcSJeremy L Thompson   CeedInt dim, ierr, ncomp, P;
59aedaa0e5Sjeremylt   Ceed ceed;
60aedaa0e5Sjeremylt   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
61d1bcdac9Sjeremylt   CeedBasis basis;
62d1bcdac9Sjeremylt   CeedElemRestriction Erestrict;
63aedaa0e5Sjeremylt   CeedOperatorField *opfields;
64aedaa0e5Sjeremylt   CeedQFunctionField *qffields;
65fe2413ffSjeremylt   if (inOrOut) {
66aedaa0e5Sjeremylt     ierr = CeedOperatorGetFields(op, NULL, &opfields);
67fe2413ffSjeremylt     CeedChk(ierr);
68aedaa0e5Sjeremylt     ierr = CeedQFunctionGetFields(qf, NULL, &qffields);
69fe2413ffSjeremylt     CeedChk(ierr);
70fe2413ffSjeremylt   } else {
71aedaa0e5Sjeremylt     ierr = CeedOperatorGetFields(op, &opfields, NULL);
72fe2413ffSjeremylt     CeedChk(ierr);
73aedaa0e5Sjeremylt     ierr = CeedQFunctionGetFields(qf, &qffields, NULL);
74fe2413ffSjeremylt     CeedChk(ierr);
75fe2413ffSjeremylt   }
7621617c04Sjeremylt 
77885ac19cSjeremylt   // Loop over fields
78885ac19cSjeremylt   for (CeedInt i=0; i<numfields; i++) {
79d1bcdac9Sjeremylt     CeedEvalMode emode;
80aedaa0e5Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode); CeedChk(ierr);
81135a076eSjeremylt 
82135a076eSjeremylt     if (emode != CEED_EVAL_WEIGHT) {
83aedaa0e5Sjeremylt       ierr = CeedOperatorFieldGetElemRestriction(opfields[i], &Erestrict);
84d1bcdac9Sjeremylt       CeedChk(ierr);
85d1bcdac9Sjeremylt       ierr = CeedElemRestrictionCreateVector(Erestrict, NULL,
8691703d3fSjeremylt                                              &fullevecs[i+starte]);
87135a076eSjeremylt       CeedChk(ierr);
88135a076eSjeremylt     }
89135a076eSjeremylt 
90885ac19cSjeremylt     switch(emode) {
91885ac19cSjeremylt     case CEED_EVAL_NONE:
92aedaa0e5Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qffields[i], &ncomp);
93d1bcdac9Sjeremylt       CeedChk(ierr);
94aedaa0e5Sjeremylt       ierr = CeedVectorCreate(ceed, Q*ncomp, &qvecs[i]); CeedChk(ierr);
95aedaa0e5Sjeremylt       break;
96aedaa0e5Sjeremylt     case CEED_EVAL_INTERP:
97aedaa0e5Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qffields[i], &ncomp);
98aedaa0e5Sjeremylt       CeedChk(ierr);
994d1cd9fcSJeremy L Thompson       ierr = CeedElemRestrictionGetElementSize(Erestrict, &P);
1004d1cd9fcSJeremy L Thompson       CeedChk(ierr);
1014d1cd9fcSJeremy L Thompson       ierr = CeedVectorCreate(ceed, P*ncomp, &evecs[i]); CeedChk(ierr);
102aedaa0e5Sjeremylt       ierr = CeedVectorCreate(ceed, Q*ncomp, &qvecs[i]); CeedChk(ierr);
103885ac19cSjeremylt       break;
104885ac19cSjeremylt     case CEED_EVAL_GRAD:
105aedaa0e5Sjeremylt       ierr = CeedOperatorFieldGetBasis(opfields[i], &basis); CeedChk(ierr);
106aedaa0e5Sjeremylt       ierr = CeedQFunctionFieldGetNumComponents(qffields[i], &ncomp);
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]);
334aedaa0e5Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
335aedaa0e5Sjeremylt                               CEED_EVAL_INTERP, impl->qvecsout[i],
33691703d3fSjeremylt                               impl->evecsout[i]); CeedChk(ierr);
337885ac19cSjeremylt         break;
338885ac19cSjeremylt       case CEED_EVAL_GRAD:
339d1bcdac9Sjeremylt         ierr = CeedOperatorFieldGetBasis(opoutputfields[i], &basis);
340d1bcdac9Sjeremylt         CeedChk(ierr);
34191703d3fSjeremylt         ierr = CeedVectorSetArray(impl->evecsout[i], CEED_MEM_HOST,
342aedaa0e5Sjeremylt                                   CEED_USE_POINTER,
343d1bcdac9Sjeremylt                                   &impl->edata[i + numinputfields][e*elemsize*ncomp]);
344aedaa0e5Sjeremylt         ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
345aedaa0e5Sjeremylt                               CEED_EVAL_GRAD, impl->qvecsout[i],
34691703d3fSjeremylt                               impl->evecsout[i]); CeedChk(ierr);
347885ac19cSjeremylt         break;
3484ce2993fSjeremylt       case CEED_EVAL_WEIGHT: {
3494ce2993fSjeremylt         Ceed ceed;
3504ce2993fSjeremylt         ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
3514ce2993fSjeremylt         return CeedError(ceed, 1,
3528d94b059Sjeremylt                          "CEED_EVAL_WEIGHT cannot be an output evaluation mode");
353885ac19cSjeremylt         break; // Should not occur
3544ce2993fSjeremylt       }
355885ac19cSjeremylt       case CEED_EVAL_DIV:
356885ac19cSjeremylt         break; // Not implimented
357885ac19cSjeremylt       case CEED_EVAL_CURL:
358885ac19cSjeremylt         break; // Not implimented
359885ac19cSjeremylt       }
360885ac19cSjeremylt     }
361885ac19cSjeremylt   }
362885ac19cSjeremylt 
36342ecf959Sjeremylt   // Zero lvecs
364d1bcdac9Sjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
365d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); CeedChk(ierr);
366*52d6035fSJeremy L Thompson     if (vec == CEED_VECTOR_ACTIVE) {
367*52d6035fSJeremy L Thompson       if (!impl->add) {
368d1bcdac9Sjeremylt         vec = outvec;
369d1bcdac9Sjeremylt         ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
37042ecf959Sjeremylt       }
371*52d6035fSJeremy L Thompson     } else {
372*52d6035fSJeremy L Thompson       ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
373*52d6035fSJeremy L Thompson     }
374*52d6035fSJeremy L Thompson   }
375*52d6035fSJeremy L Thompson   impl->add = false;
37642ecf959Sjeremylt 
377885ac19cSjeremylt   // Output restriction
3781a4ead9bSjeremylt   for (CeedInt i=0; i<numoutputfields; i++) {
379a2b73c81Sjeremylt     // Restore evec
380a2b73c81Sjeremylt     ierr = CeedVectorRestoreArray(impl->evecs[i+impl->numein],
381d1bcdac9Sjeremylt                                   &impl->edata[i + numinputfields]);
382d1bcdac9Sjeremylt     CeedChk(ierr);
383d1bcdac9Sjeremylt     // Get output vector
384d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); CeedChk(ierr);
385668048e2SJed Brown     // Active
386d1bcdac9Sjeremylt     if (vec == CEED_VECTOR_ACTIVE)
387d1bcdac9Sjeremylt       vec = outvec;
3887ca8db16Sjeremylt     // Restrict
389d1bcdac9Sjeremylt     ierr = CeedOperatorFieldGetElemRestriction(opoutputfields[i], &Erestrict);
390d1bcdac9Sjeremylt     CeedChk(ierr);
3914dccadb6Sjeremylt     ierr = CeedOperatorFieldGetLMode(opoutputfields[i], &lmode); CeedChk(ierr);
392d1bcdac9Sjeremylt     ierr = CeedElemRestrictionApply(Erestrict, CEED_TRANSPOSE,
393d1bcdac9Sjeremylt                                     lmode, impl->evecs[i+impl->numein], vec,
394668048e2SJed Brown                                     request); CeedChk(ierr);
395885ac19cSjeremylt   }
396885ac19cSjeremylt 
3977ca8db16Sjeremylt   // Restore input arrays
3981a4ead9bSjeremylt   for (CeedInt i=0; i<numinputfields; i++) {
399d1bcdac9Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode);
400d1bcdac9Sjeremylt     CeedChk(ierr);
401135a076eSjeremylt     if (emode == CEED_EVAL_WEIGHT) { // Skip
4027ca8db16Sjeremylt     } else {
403a2b73c81Sjeremylt       ierr = CeedVectorRestoreArrayRead(impl->evecs[i],
404d1bcdac9Sjeremylt                                         (const CeedScalar **) &impl->edata[i]);
405d1bcdac9Sjeremylt       CeedChk(ierr);
4067ca8db16Sjeremylt     }
4077ca8db16Sjeremylt   }
4087ca8db16Sjeremylt 
40921617c04Sjeremylt   return 0;
41021617c04Sjeremylt }
41121617c04Sjeremylt 
412*52d6035fSJeremy L Thompson static int CeedCompositeOperatorApply_Ref(CeedOperator op, CeedVector invec,
413*52d6035fSJeremy L Thompson     CeedVector outvec,
414*52d6035fSJeremy L Thompson     CeedRequest *request) {
415*52d6035fSJeremy L Thompson   int ierr;
416*52d6035fSJeremy L Thompson   CeedInt numsub;
417*52d6035fSJeremy L Thompson   CeedOperator_Ref *impl;
418*52d6035fSJeremy L Thompson   CeedOperator *suboperators;
419*52d6035fSJeremy L Thompson   ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
420*52d6035fSJeremy L Thompson   ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
421*52d6035fSJeremy L Thompson 
422*52d6035fSJeremy L Thompson   // Overwrite outvec with first output
423*52d6035fSJeremy L Thompson   ierr = CeedOperatorApply(suboperators[0], invec, outvec, request);
424*52d6035fSJeremy L Thompson   CeedChk(ierr);
425*52d6035fSJeremy L Thompson   // Add to outvec with subsequent outputs
426*52d6035fSJeremy L Thompson   for (CeedInt i=1; i<numsub; i++) {
427*52d6035fSJeremy L Thompson     ierr = CeedOperatorGetData(suboperators[i], (void *)&impl);
428*52d6035fSJeremy L Thompson     impl->add = true;
429*52d6035fSJeremy L Thompson     ierr = CeedOperatorApply(suboperators[i], invec, outvec, request);
430*52d6035fSJeremy L Thompson     CeedChk(ierr);
431*52d6035fSJeremy L Thompson   }
432*52d6035fSJeremy L Thompson 
433*52d6035fSJeremy L Thompson   return 0;
434*52d6035fSJeremy L Thompson }
435*52d6035fSJeremy L Thompson 
43621617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) {
43721617c04Sjeremylt   int ierr;
438fe2413ffSjeremylt   Ceed ceed;
439fe2413ffSjeremylt   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
4404ce2993fSjeremylt   CeedOperator_Ref *impl;
44121617c04Sjeremylt 
44221617c04Sjeremylt   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
443*52d6035fSJeremy L Thompson   impl->add = false;
444fe2413ffSjeremylt   ierr = CeedOperatorSetData(op, (void *)&impl);
445fe2413ffSjeremylt 
446fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Apply",
447fe2413ffSjeremylt                                 CeedOperatorApply_Ref); CeedChk(ierr);
448fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Destroy",
449fe2413ffSjeremylt                                 CeedOperatorDestroy_Ref); CeedChk(ierr);
45021617c04Sjeremylt   return 0;
45121617c04Sjeremylt }
452*52d6035fSJeremy L Thompson 
453*52d6035fSJeremy L Thompson int CeedCompositeOperatorCreate_Ref(CeedOperator op) {
454*52d6035fSJeremy L Thompson   int ierr;
455*52d6035fSJeremy L Thompson   Ceed ceed;
456*52d6035fSJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
457*52d6035fSJeremy L Thompson 
458*52d6035fSJeremy L Thompson   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Apply",
459*52d6035fSJeremy L Thompson                                 CeedCompositeOperatorApply_Ref); CeedChk(ierr);
460*52d6035fSJeremy L Thompson   return 0;
461*52d6035fSJeremy L Thompson }
462