xref: /libCEED/interface/ceed-operator.c (revision 777ff853944a0dbc06f7f09486fdf4674828e728)
1d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details.
4d7b241e6Sjeremylt //
5d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
6d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
7d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and
8d7b241e6Sjeremylt // source code availability see http://github.com/ceed.
9d7b241e6Sjeremylt //
10d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
12d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
13d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
14d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early
15d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
16d7b241e6Sjeremylt 
17d7b241e6Sjeremylt #include <ceed-impl.h>
18d863ab9bSjeremylt #include <ceed-backend.h>
19d7b241e6Sjeremylt #include <string.h>
203bd813ffSjeremylt #include <math.h>
21d7b241e6Sjeremylt 
22dfdf5a53Sjeremylt /// @file
237a982d89SJeremy L. Thompson /// Implementation of CeedOperator interfaces
247a982d89SJeremy L. Thompson 
257a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
267a982d89SJeremy L. Thompson /// CeedOperator Library Internal Functions
277a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
287a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorDeveloper
297a982d89SJeremy L. Thompson /// @{
307a982d89SJeremy L. Thompson 
317a982d89SJeremy L. Thompson /**
327a982d89SJeremy L. Thompson   @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced
337a982d89SJeremy L. Thompson            CeedOperator functionality
347a982d89SJeremy L. Thompson 
357a982d89SJeremy L. Thompson   @param op           CeedOperator to create fallback for
367a982d89SJeremy L. Thompson 
377a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
387a982d89SJeremy L. Thompson 
397a982d89SJeremy L. Thompson   @ref Developer
407a982d89SJeremy L. Thompson **/
417a982d89SJeremy L. Thompson int CeedOperatorCreateFallback(CeedOperator op) {
427a982d89SJeremy L. Thompson   int ierr;
437a982d89SJeremy L. Thompson 
447a982d89SJeremy L. Thompson   // Fallback Ceed
457a982d89SJeremy L. Thompson   const char *resource, *fallbackresource;
467a982d89SJeremy L. Thompson   ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
477a982d89SJeremy L. Thompson   ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
487a982d89SJeremy L. Thompson   CeedChk(ierr);
497a982d89SJeremy L. Thompson   if (!strcmp(resource, fallbackresource))
507a982d89SJeremy L. Thompson     // LCOV_EXCL_START
517a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Backend %s cannot create an operator"
527a982d89SJeremy L. Thompson                      "fallback to resource %s", resource, fallbackresource);
537a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
547a982d89SJeremy L. Thompson 
557a982d89SJeremy L. Thompson   // Fallback Ceed
567a982d89SJeremy L. Thompson   Ceed ceedref;
577a982d89SJeremy L. Thompson   if (!op->ceed->opfallbackceed) {
587a982d89SJeremy L. Thompson     ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr);
597a982d89SJeremy L. Thompson     ceedref->opfallbackparent = op->ceed;
607a982d89SJeremy L. Thompson     op->ceed->opfallbackceed = ceedref;
617a982d89SJeremy L. Thompson   }
627a982d89SJeremy L. Thompson   ceedref = op->ceed->opfallbackceed;
637a982d89SJeremy L. Thompson 
647a982d89SJeremy L. Thompson   // Clone Op
657a982d89SJeremy L. Thompson   CeedOperator opref;
667a982d89SJeremy L. Thompson   ierr = CeedCalloc(1, &opref); CeedChk(ierr);
677a982d89SJeremy L. Thompson   memcpy(opref, op, sizeof(*opref)); CeedChk(ierr);
687a982d89SJeremy L. Thompson   opref->data = NULL;
697a982d89SJeremy L. Thompson   opref->setupdone = 0;
707a982d89SJeremy L. Thompson   opref->ceed = ceedref;
717a982d89SJeremy L. Thompson   ierr = ceedref->OperatorCreate(opref); CeedChk(ierr);
727a982d89SJeremy L. Thompson   op->opfallback = opref;
737a982d89SJeremy L. Thompson 
747a982d89SJeremy L. Thompson   // Clone QF
757a982d89SJeremy L. Thompson   CeedQFunction qfref;
767a982d89SJeremy L. Thompson   ierr = CeedCalloc(1, &qfref); CeedChk(ierr);
777a982d89SJeremy L. Thompson   memcpy(qfref, (op->qf), sizeof(*qfref)); CeedChk(ierr);
787a982d89SJeremy L. Thompson   qfref->data = NULL;
797a982d89SJeremy L. Thompson   qfref->ceed = ceedref;
807a982d89SJeremy L. Thompson   ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr);
817a982d89SJeremy L. Thompson   opref->qf = qfref;
827a982d89SJeremy L. Thompson   op->qffallback = qfref;
837a982d89SJeremy L. Thompson 
847a982d89SJeremy L. Thompson   return 0;
857a982d89SJeremy L. Thompson }
867a982d89SJeremy L. Thompson 
877a982d89SJeremy L. Thompson /**
887a982d89SJeremy L. Thompson   @brief Check if a CeedOperator is ready to be used.
897a982d89SJeremy L. Thompson 
907a982d89SJeremy L. Thompson   @param[in] ceed Ceed object for error handling
917a982d89SJeremy L. Thompson   @param[in] op   CeedOperator to check
927a982d89SJeremy L. Thompson 
937a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
947a982d89SJeremy L. Thompson 
957a982d89SJeremy L. Thompson   @ref Developer
967a982d89SJeremy L. Thompson **/
977a982d89SJeremy L. Thompson static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) {
987a982d89SJeremy L. Thompson   CeedQFunction qf = op->qf;
997a982d89SJeremy L. Thompson 
1007a982d89SJeremy L. Thompson   if (op->composite) {
1017a982d89SJeremy L. Thompson     if (!op->numsub)
1027a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1037a982d89SJeremy L. Thompson       return CeedError(ceed, 1, "No suboperators set");
1047a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1057a982d89SJeremy L. Thompson   } else {
1067a982d89SJeremy L. Thompson     if (op->nfields == 0)
1077a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1087a982d89SJeremy L. Thompson       return CeedError(ceed, 1, "No operator fields set");
1097a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1107a982d89SJeremy L. Thompson     if (op->nfields < qf->numinputfields + qf->numoutputfields)
1117a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1127a982d89SJeremy L. Thompson       return CeedError(ceed, 1, "Not all operator fields set");
1137a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1147a982d89SJeremy L. Thompson     if (!op->hasrestriction)
1157a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1167a982d89SJeremy L. Thompson       return CeedError(ceed, 1,"At least one restriction required");
1177a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1187a982d89SJeremy L. Thompson     if (op->numqpoints == 0)
1197a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1207a982d89SJeremy L. Thompson       return CeedError(ceed, 1,"At least one non-collocated basis required");
1217a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1227a982d89SJeremy L. Thompson   }
1237a982d89SJeremy L. Thompson 
1247a982d89SJeremy L. Thompson   return 0;
1257a982d89SJeremy L. Thompson }
1267a982d89SJeremy L. Thompson 
1277a982d89SJeremy L. Thompson /**
1287a982d89SJeremy L. Thompson   @brief View a field of a CeedOperator
1297a982d89SJeremy L. Thompson 
1307a982d89SJeremy L. Thompson   @param[in] field       Operator field to view
1314c4400c7SValeria Barra   @param[in] qffield     QFunction field (carries field name)
1327a982d89SJeremy L. Thompson   @param[in] fieldnumber Number of field being viewed
1334c4400c7SValeria Barra   @param[in] sub         true indicates sub-operator, which increases indentation; false for top-level operator
1344c4400c7SValeria Barra   @param[in] in          true for an input field; false for output field
1357a982d89SJeremy L. Thompson   @param[in] stream      Stream to view to, e.g., stdout
1367a982d89SJeremy L. Thompson 
1377a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1387a982d89SJeremy L. Thompson 
1397a982d89SJeremy L. Thompson   @ref Utility
1407a982d89SJeremy L. Thompson **/
1417a982d89SJeremy L. Thompson static int CeedOperatorFieldView(CeedOperatorField field,
1427a982d89SJeremy L. Thompson                                  CeedQFunctionField qffield,
1437a982d89SJeremy L. Thompson                                  CeedInt fieldnumber, bool sub, bool in,
1447a982d89SJeremy L. Thompson                                  FILE *stream) {
1457a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
1467a982d89SJeremy L. Thompson   const char *inout = in ? "Input" : "Output";
1477a982d89SJeremy L. Thompson 
1487a982d89SJeremy L. Thompson   fprintf(stream, "%s    %s Field [%d]:\n"
1497a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
1507a982d89SJeremy L. Thompson           pre, inout, fieldnumber, pre, qffield->fieldname);
1517a982d89SJeremy L. Thompson 
1527a982d89SJeremy L. Thompson   if (field->basis == CEED_BASIS_COLLOCATED)
1537a982d89SJeremy L. Thompson     fprintf(stream, "%s      Collocated basis\n", pre);
1547a982d89SJeremy L. Thompson 
1557a982d89SJeremy L. Thompson   if (field->vec == CEED_VECTOR_ACTIVE)
1567a982d89SJeremy L. Thompson     fprintf(stream, "%s      Active vector\n", pre);
1577a982d89SJeremy L. Thompson   else if (field->vec == CEED_VECTOR_NONE)
1587a982d89SJeremy L. Thompson     fprintf(stream, "%s      No vector\n", pre);
1597a982d89SJeremy L. Thompson 
1607a982d89SJeremy L. Thompson   return 0;
1617a982d89SJeremy L. Thompson }
1627a982d89SJeremy L. Thompson 
1637a982d89SJeremy L. Thompson /**
1647a982d89SJeremy L. Thompson   @brief View a single CeedOperator
1657a982d89SJeremy L. Thompson 
1667a982d89SJeremy L. Thompson   @param[in] op     CeedOperator to view
1677a982d89SJeremy L. Thompson   @param[in] sub    Boolean flag for sub-operator
1687a982d89SJeremy L. Thompson   @param[in] stream Stream to write; typically stdout/stderr or a file
1697a982d89SJeremy L. Thompson 
1707a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
1717a982d89SJeremy L. Thompson 
1727a982d89SJeremy L. Thompson   @ref Utility
1737a982d89SJeremy L. Thompson **/
1747a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
1757a982d89SJeremy L. Thompson   int ierr;
1767a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
1777a982d89SJeremy L. Thompson 
1787a982d89SJeremy L. Thompson   CeedInt totalfields;
1797a982d89SJeremy L. Thompson   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
1807a982d89SJeremy L. Thompson 
1817a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
1827a982d89SJeremy L. Thompson 
1837a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
1847a982d89SJeremy L. Thompson           op->qf->numinputfields>1 ? "s" : "");
1857a982d89SJeremy L. Thompson   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
1867a982d89SJeremy L. Thompson     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
1877a982d89SJeremy L. Thompson                                  i, sub, 1, stream); CeedChk(ierr);
1887a982d89SJeremy L. Thompson   }
1897a982d89SJeremy L. Thompson 
1907a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
1917a982d89SJeremy L. Thompson           op->qf->numoutputfields>1 ? "s" : "");
1927a982d89SJeremy L. Thompson   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
1937a982d89SJeremy L. Thompson     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i],
1947a982d89SJeremy L. Thompson                                  i, sub, 0, stream); CeedChk(ierr);
1957a982d89SJeremy L. Thompson   }
1967a982d89SJeremy L. Thompson 
1977a982d89SJeremy L. Thompson   return 0;
1987a982d89SJeremy L. Thompson }
1997a982d89SJeremy L. Thompson 
200d99fa3c5SJeremy L Thompson /**
201d99fa3c5SJeremy L Thompson   @brief Find the active vector basis for a CeedOperator
202d99fa3c5SJeremy L Thompson 
203d99fa3c5SJeremy L Thompson   @param[in] op            CeedOperator to find active basis for
204d99fa3c5SJeremy L Thompson   @param[out] activeBasis  Basis for active input vector
205d99fa3c5SJeremy L Thompson 
206d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
207d99fa3c5SJeremy L Thompson 
208d99fa3c5SJeremy L Thompson   @ ref Developer
209d99fa3c5SJeremy L Thompson **/
210d99fa3c5SJeremy L Thompson static int CeedOperatorGetActiveBasis(CeedOperator op,
211d99fa3c5SJeremy L Thompson                                       CeedBasis *activeBasis) {
212d99fa3c5SJeremy L Thompson   *activeBasis = NULL;
213d99fa3c5SJeremy L Thompson   for (int i = 0; i < op->qf->numinputfields; i++)
214d99fa3c5SJeremy L Thompson     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
215d99fa3c5SJeremy L Thompson       *activeBasis = op->inputfields[i]->basis;
216d99fa3c5SJeremy L Thompson       break;
217d99fa3c5SJeremy L Thompson     }
218d99fa3c5SJeremy L Thompson 
219d99fa3c5SJeremy L Thompson   if (!*activeBasis) {
220d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
221d99fa3c5SJeremy L Thompson     int ierr;
222d99fa3c5SJeremy L Thompson     Ceed ceed;
223d99fa3c5SJeremy L Thompson     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
224d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1,
225d99fa3c5SJeremy L Thompson                      "No active basis found for automatic multigrid setup");
226d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
227d99fa3c5SJeremy L Thompson   }
228d99fa3c5SJeremy L Thompson   return 0;
229d99fa3c5SJeremy L Thompson }
230d99fa3c5SJeremy L Thompson 
231d99fa3c5SJeremy L Thompson 
232d99fa3c5SJeremy L Thompson /**
233d99fa3c5SJeremy L Thompson   @brief Common code for creating a multigrid coarse operator and level
234d99fa3c5SJeremy L Thompson            transfer operators for a CeedOperator
235d99fa3c5SJeremy L Thompson 
236d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
237d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
238d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
239d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
240d99fa3c5SJeremy L Thompson   @param[in] basisCtoF    Basis for coarse to fine interpolation
241d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
242d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
243d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
244d99fa3c5SJeremy L Thompson 
245d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
246d99fa3c5SJeremy L Thompson 
247d99fa3c5SJeremy L Thompson   @ref Developer
248d99fa3c5SJeremy L Thompson **/
249d99fa3c5SJeremy L Thompson static int CeedOperatorMultigridLevel_Core(CeedOperator opFine,
250d99fa3c5SJeremy L Thompson     CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
251d99fa3c5SJeremy L Thompson     CeedBasis basisCtoF, CeedOperator *opCoarse, CeedOperator *opProlong,
252d99fa3c5SJeremy L Thompson     CeedOperator *opRestrict) {
253d99fa3c5SJeremy L Thompson   int ierr;
254d99fa3c5SJeremy L Thompson   Ceed ceed;
255d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
256d99fa3c5SJeremy L Thompson 
257d99fa3c5SJeremy L Thompson   // Check for composite operator
258d99fa3c5SJeremy L Thompson   bool isComposite;
259d99fa3c5SJeremy L Thompson   ierr = CeedOperatorIsComposite(opFine, &isComposite); CeedChk(ierr);
260d99fa3c5SJeremy L Thompson   if (isComposite)
261d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
262d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1,
263d99fa3c5SJeremy L Thompson                      "Automatic multigrid setup for composite operators not supported");
264d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
265d99fa3c5SJeremy L Thompson 
266d99fa3c5SJeremy L Thompson   // Coarse Grid
267d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, opFine->qf, opFine->dqf, opFine->dqfT,
268d99fa3c5SJeremy L Thompson                             opCoarse); CeedChk(ierr);
269d99fa3c5SJeremy L Thompson   CeedElemRestriction rstrFine = NULL;
270d99fa3c5SJeremy L Thompson   // -- Clone input fields
271d99fa3c5SJeremy L Thompson   for (int i = 0; i < opFine->qf->numinputfields; i++) {
272d99fa3c5SJeremy L Thompson     if (opFine->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
273d99fa3c5SJeremy L Thompson       rstrFine = opFine->inputfields[i]->Erestrict;
274d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname,
275d99fa3c5SJeremy L Thompson                                   rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE);
276d99fa3c5SJeremy L Thompson       CeedChk(ierr);
277d99fa3c5SJeremy L Thompson     } else {
278d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname,
279d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->Erestrict,
280d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->basis,
281d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->vec); CeedChk(ierr);
282d99fa3c5SJeremy L Thompson     }
283d99fa3c5SJeremy L Thompson   }
284d99fa3c5SJeremy L Thompson   // -- Clone output fields
285d99fa3c5SJeremy L Thompson   for (int i = 0; i < opFine->qf->numoutputfields; i++) {
286d99fa3c5SJeremy L Thompson     if (opFine->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
287d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname,
288d99fa3c5SJeremy L Thompson                                   rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE);
289d99fa3c5SJeremy L Thompson       CeedChk(ierr);
290d99fa3c5SJeremy L Thompson     } else {
291d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname,
292d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->Erestrict,
293d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->basis,
294d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->vec); CeedChk(ierr);
295d99fa3c5SJeremy L Thompson     }
296d99fa3c5SJeremy L Thompson   }
297d99fa3c5SJeremy L Thompson 
298d99fa3c5SJeremy L Thompson   // Multiplicity vector
299d99fa3c5SJeremy L Thompson   CeedVector multVec, multE;
300d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionCreateVector(rstrFine, &multVec, &multE);
301d99fa3c5SJeremy L Thompson   CeedChk(ierr);
302d99fa3c5SJeremy L Thompson   ierr = CeedVectorSetValue(multE, 0.0); CeedChk(ierr);
303d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrFine, CEED_NOTRANSPOSE, PMultFine, multE,
304d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
305d99fa3c5SJeremy L Thompson   ierr = CeedVectorSetValue(multVec, 0.0); CeedChk(ierr);
306d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrFine, CEED_TRANSPOSE, multE, multVec,
307d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
308d99fa3c5SJeremy L Thompson   ierr = CeedVectorDestroy(&multE); CeedChk(ierr);
309d99fa3c5SJeremy L Thompson   ierr = CeedVectorReciprocal(multVec); CeedChk(ierr);
310d99fa3c5SJeremy L Thompson 
311d99fa3c5SJeremy L Thompson   // Restriction
312d99fa3c5SJeremy L Thompson   CeedInt ncomp;
313d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisCoarse, &ncomp); CeedChk(ierr);
314d99fa3c5SJeremy L Thompson   CeedQFunction qfRestrict;
315d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfRestrict);
316d99fa3c5SJeremy L Thompson   CeedChk(ierr);
317*777ff853SJeremy L Thompson   CeedInt *ncompRData;
318*777ff853SJeremy L Thompson   ierr = CeedCalloc(1, &ncompRData); CeedChk(ierr);
319*777ff853SJeremy L Thompson   ncompRData[0] = ncomp;
320*777ff853SJeremy L Thompson   CeedQFunctionContext ctxR;
321*777ff853SJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctxR); CeedChk(ierr);
322*777ff853SJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctxR, CEED_MEM_HOST, CEED_OWN_POINTER,
323*777ff853SJeremy L Thompson                                      sizeof(*ncompRData), ncompRData);
324*777ff853SJeremy L Thompson   CeedChk(ierr);
325*777ff853SJeremy L Thompson   ierr = CeedQFunctionSetContext(qfRestrict, ctxR); CeedChk(ierr);
326*777ff853SJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctxR); CeedChk(ierr);
327d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfRestrict, "input", ncomp, CEED_EVAL_NONE);
328d99fa3c5SJeremy L Thompson   CeedChk(ierr);
329d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfRestrict, "scale", ncomp, CEED_EVAL_NONE);
330d99fa3c5SJeremy L Thompson   CeedChk(ierr);
331d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddOutput(qfRestrict, "output", ncomp, CEED_EVAL_INTERP);
332d99fa3c5SJeremy L Thompson   CeedChk(ierr);
333d99fa3c5SJeremy L Thompson 
334d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qfRestrict, CEED_QFUNCTION_NONE,
335d99fa3c5SJeremy L Thompson                             CEED_QFUNCTION_NONE, opRestrict);
336d99fa3c5SJeremy L Thompson   CeedChk(ierr);
337d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "input", rstrFine,
338d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
339d99fa3c5SJeremy L Thompson   CeedChk(ierr);
340d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "scale", rstrFine,
341d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, multVec);
342d99fa3c5SJeremy L Thompson   CeedChk(ierr);
343d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "output", rstrCoarse, basisCtoF,
344d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
345d99fa3c5SJeremy L Thompson 
346d99fa3c5SJeremy L Thompson   // Prolongation
347d99fa3c5SJeremy L Thompson   CeedQFunction qfProlong;
348d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfProlong);
349d99fa3c5SJeremy L Thompson   CeedChk(ierr);
350*777ff853SJeremy L Thompson   CeedInt *ncompPData;
351*777ff853SJeremy L Thompson   ierr = CeedCalloc(1, &ncompPData); CeedChk(ierr);
352*777ff853SJeremy L Thompson   ncompPData[0] = ncomp;
353*777ff853SJeremy L Thompson   CeedQFunctionContext ctxP;
354*777ff853SJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctxP); CeedChk(ierr);
355*777ff853SJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctxP, CEED_MEM_HOST, CEED_OWN_POINTER,
356*777ff853SJeremy L Thompson                                      sizeof(*ncompPData), ncompPData);
357*777ff853SJeremy L Thompson   CeedChk(ierr);
358*777ff853SJeremy L Thompson   ierr = CeedQFunctionSetContext(qfProlong, ctxP); CeedChk(ierr);
359*777ff853SJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctxP); CeedChk(ierr);
360d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfProlong, "input", ncomp, CEED_EVAL_INTERP);
361d99fa3c5SJeremy L Thompson   CeedChk(ierr);
362d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfProlong, "scale", ncomp, CEED_EVAL_NONE);
363d99fa3c5SJeremy L Thompson   CeedChk(ierr);
364d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddOutput(qfProlong, "output", ncomp, CEED_EVAL_NONE);
365d99fa3c5SJeremy L Thompson   CeedChk(ierr);
366d99fa3c5SJeremy L Thompson 
367d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qfProlong, CEED_QFUNCTION_NONE,
368d99fa3c5SJeremy L Thompson                             CEED_QFUNCTION_NONE, opProlong);
369d99fa3c5SJeremy L Thompson   CeedChk(ierr);
370d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "input", rstrCoarse, basisCtoF,
371d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
372d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "scale", rstrFine,
373d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, multVec);
374d99fa3c5SJeremy L Thompson   CeedChk(ierr);
375d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "output", rstrFine,
376d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
377d99fa3c5SJeremy L Thompson   CeedChk(ierr);
378d99fa3c5SJeremy L Thompson 
379d99fa3c5SJeremy L Thompson   // Cleanup
380d99fa3c5SJeremy L Thompson   ierr = CeedVectorDestroy(&multVec); CeedChk(ierr);
381d99fa3c5SJeremy L Thompson   ierr = CeedBasisDestroy(&basisCtoF); CeedChk(ierr);
382d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionDestroy(&qfRestrict); CeedChk(ierr);
383d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionDestroy(&qfProlong); CeedChk(ierr);
384d99fa3c5SJeremy L Thompson 
385d99fa3c5SJeremy L Thompson   return 0;
386d99fa3c5SJeremy L Thompson }
387d99fa3c5SJeremy L Thompson 
3887a982d89SJeremy L. Thompson /// @}
3897a982d89SJeremy L. Thompson 
3907a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3917a982d89SJeremy L. Thompson /// CeedOperator Backend API
3927a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3937a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
3947a982d89SJeremy L. Thompson /// @{
3957a982d89SJeremy L. Thompson 
3967a982d89SJeremy L. Thompson /**
3977a982d89SJeremy L. Thompson   @brief Get the Ceed associated with a CeedOperator
3987a982d89SJeremy L. Thompson 
3997a982d89SJeremy L. Thompson   @param op              CeedOperator
4007a982d89SJeremy L. Thompson   @param[out] ceed       Variable to store Ceed
4017a982d89SJeremy L. Thompson 
4027a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4037a982d89SJeremy L. Thompson 
4047a982d89SJeremy L. Thompson   @ref Backend
4057a982d89SJeremy L. Thompson **/
4067a982d89SJeremy L. Thompson 
4077a982d89SJeremy L. Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
4087a982d89SJeremy L. Thompson   *ceed = op->ceed;
4097a982d89SJeremy L. Thompson   return 0;
4107a982d89SJeremy L. Thompson }
4117a982d89SJeremy L. Thompson 
4127a982d89SJeremy L. Thompson /**
4137a982d89SJeremy L. Thompson   @brief Get the number of elements associated with a CeedOperator
4147a982d89SJeremy L. Thompson 
4157a982d89SJeremy L. Thompson   @param op              CeedOperator
4167a982d89SJeremy L. Thompson   @param[out] numelem    Variable to store number of elements
4177a982d89SJeremy L. Thompson 
4187a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4197a982d89SJeremy L. Thompson 
4207a982d89SJeremy L. Thompson   @ref Backend
4217a982d89SJeremy L. Thompson **/
4227a982d89SJeremy L. Thompson 
4237a982d89SJeremy L. Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
4247a982d89SJeremy L. Thompson   if (op->composite)
4257a982d89SJeremy L. Thompson     // LCOV_EXCL_START
4267a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
4277a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4287a982d89SJeremy L. Thompson 
4297a982d89SJeremy L. Thompson   *numelem = op->numelements;
4307a982d89SJeremy L. Thompson   return 0;
4317a982d89SJeremy L. Thompson }
4327a982d89SJeremy L. Thompson 
4337a982d89SJeremy L. Thompson /**
4347a982d89SJeremy L. Thompson   @brief Get the number of quadrature points associated with a CeedOperator
4357a982d89SJeremy L. Thompson 
4367a982d89SJeremy L. Thompson   @param op              CeedOperator
4377a982d89SJeremy L. Thompson   @param[out] numqpts    Variable to store vector number of quadrature points
4387a982d89SJeremy L. Thompson 
4397a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4407a982d89SJeremy L. Thompson 
4417a982d89SJeremy L. Thompson   @ref Backend
4427a982d89SJeremy L. Thompson **/
4437a982d89SJeremy L. Thompson 
4447a982d89SJeremy L. Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
4457a982d89SJeremy L. Thompson   if (op->composite)
4467a982d89SJeremy L. Thompson     // LCOV_EXCL_START
4477a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
4487a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4497a982d89SJeremy L. Thompson 
4507a982d89SJeremy L. Thompson   *numqpts = op->numqpoints;
4517a982d89SJeremy L. Thompson   return 0;
4527a982d89SJeremy L. Thompson }
4537a982d89SJeremy L. Thompson 
4547a982d89SJeremy L. Thompson /**
4557a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
4567a982d89SJeremy L. Thompson 
4577a982d89SJeremy L. Thompson   @param op              CeedOperator
4587a982d89SJeremy L. Thompson   @param[out] numargs    Variable to store vector number of arguments
4597a982d89SJeremy L. Thompson 
4607a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4617a982d89SJeremy L. Thompson 
4627a982d89SJeremy L. Thompson   @ref Backend
4637a982d89SJeremy L. Thompson **/
4647a982d89SJeremy L. Thompson 
4657a982d89SJeremy L. Thompson int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
4667a982d89SJeremy L. Thompson   if (op->composite)
4677a982d89SJeremy L. Thompson     // LCOV_EXCL_START
4687a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operators");
4697a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4707a982d89SJeremy L. Thompson 
4717a982d89SJeremy L. Thompson   *numargs = op->nfields;
4727a982d89SJeremy L. Thompson   return 0;
4737a982d89SJeremy L. Thompson }
4747a982d89SJeremy L. Thompson 
4757a982d89SJeremy L. Thompson /**
4767a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
4777a982d89SJeremy L. Thompson 
4787a982d89SJeremy L. Thompson   @param op                CeedOperator
479fd364f38SJeremy L Thompson   @param[out] issetupdone  Variable to store setup status
4807a982d89SJeremy L. Thompson 
4817a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4827a982d89SJeremy L. Thompson 
4837a982d89SJeremy L. Thompson   @ref Backend
4847a982d89SJeremy L. Thompson **/
4857a982d89SJeremy L. Thompson 
486fd364f38SJeremy L Thompson int CeedOperatorIsSetupDone(CeedOperator op, bool *issetupdone) {
487fd364f38SJeremy L Thompson   *issetupdone = op->setupdone;
4887a982d89SJeremy L. Thompson   return 0;
4897a982d89SJeremy L. Thompson }
4907a982d89SJeremy L. Thompson 
4917a982d89SJeremy L. Thompson /**
4927a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
4937a982d89SJeremy L. Thompson 
4947a982d89SJeremy L. Thompson   @param op              CeedOperator
4957a982d89SJeremy L. Thompson   @param[out] qf         Variable to store QFunction
4967a982d89SJeremy L. Thompson 
4977a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4987a982d89SJeremy L. Thompson 
4997a982d89SJeremy L. Thompson   @ref Backend
5007a982d89SJeremy L. Thompson **/
5017a982d89SJeremy L. Thompson 
5027a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
5037a982d89SJeremy L. Thompson   if (op->composite)
5047a982d89SJeremy L. Thompson     // LCOV_EXCL_START
5057a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
5067a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5077a982d89SJeremy L. Thompson 
5087a982d89SJeremy L. Thompson   *qf = op->qf;
5097a982d89SJeremy L. Thompson   return 0;
5107a982d89SJeremy L. Thompson }
5117a982d89SJeremy L. Thompson 
5127a982d89SJeremy L. Thompson /**
513c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
514c04a41a7SJeremy L Thompson 
515c04a41a7SJeremy L Thompson   @param op                CeedOperator
516fd364f38SJeremy L Thompson   @param[out] iscomposite  Variable to store composite status
517c04a41a7SJeremy L Thompson 
518c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
519c04a41a7SJeremy L Thompson 
520c04a41a7SJeremy L Thompson   @ref Backend
521c04a41a7SJeremy L Thompson **/
522c04a41a7SJeremy L Thompson 
523fd364f38SJeremy L Thompson int CeedOperatorIsComposite(CeedOperator op, bool *iscomposite) {
524fd364f38SJeremy L Thompson   *iscomposite = op->composite;
525c04a41a7SJeremy L Thompson   return 0;
526c04a41a7SJeremy L Thompson }
527c04a41a7SJeremy L Thompson 
528c04a41a7SJeremy L Thompson /**
5297a982d89SJeremy L. Thompson   @brief Get the number of suboperators associated with a CeedOperator
5307a982d89SJeremy L. Thompson 
5317a982d89SJeremy L. Thompson   @param op              CeedOperator
5327a982d89SJeremy L. Thompson   @param[out] numsub     Variable to store number of suboperators
5337a982d89SJeremy L. Thompson 
5347a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5357a982d89SJeremy L. Thompson 
5367a982d89SJeremy L. Thompson   @ref Backend
5377a982d89SJeremy L. Thompson **/
5387a982d89SJeremy L. Thompson 
5397a982d89SJeremy L. Thompson int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
5407a982d89SJeremy L. Thompson   if (!op->composite)
5417a982d89SJeremy L. Thompson     // LCOV_EXCL_START
5427a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
5437a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5447a982d89SJeremy L. Thompson 
5457a982d89SJeremy L. Thompson   *numsub = op->numsub;
5467a982d89SJeremy L. Thompson   return 0;
5477a982d89SJeremy L. Thompson }
5487a982d89SJeremy L. Thompson 
5497a982d89SJeremy L. Thompson /**
5507a982d89SJeremy L. Thompson   @brief Get the list of suboperators associated with a CeedOperator
5517a982d89SJeremy L. Thompson 
5527a982d89SJeremy L. Thompson   @param op                CeedOperator
5537a982d89SJeremy L. Thompson   @param[out] suboperators Variable to store list of suboperators
5547a982d89SJeremy L. Thompson 
5557a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5567a982d89SJeremy L. Thompson 
5577a982d89SJeremy L. Thompson   @ref Backend
5587a982d89SJeremy L. Thompson **/
5597a982d89SJeremy L. Thompson 
5607a982d89SJeremy L. Thompson int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
5617a982d89SJeremy L. Thompson   if (!op->composite)
5627a982d89SJeremy L. Thompson     // LCOV_EXCL_START
5637a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
5647a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5657a982d89SJeremy L. Thompson 
5667a982d89SJeremy L. Thompson   *suboperators = op->suboperators;
5677a982d89SJeremy L. Thompson   return 0;
5687a982d89SJeremy L. Thompson }
5697a982d89SJeremy L. Thompson 
5707a982d89SJeremy L. Thompson /**
5717a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
5727a982d89SJeremy L. Thompson 
5737a982d89SJeremy L. Thompson   @param op              CeedOperator
5747a982d89SJeremy L. Thompson   @param[out] data       Variable to store data
5757a982d89SJeremy L. Thompson 
5767a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5777a982d89SJeremy L. Thompson 
5787a982d89SJeremy L. Thompson   @ref Backend
5797a982d89SJeremy L. Thompson **/
5807a982d89SJeremy L. Thompson 
581*777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
582*777ff853SJeremy L Thompson   *(void **)data = op->data;
5837a982d89SJeremy L. Thompson   return 0;
5847a982d89SJeremy L. Thompson }
5857a982d89SJeremy L. Thompson 
5867a982d89SJeremy L. Thompson /**
5877a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
5887a982d89SJeremy L. Thompson 
5897a982d89SJeremy L. Thompson   @param[out] op         CeedOperator
5907a982d89SJeremy L. Thompson   @param data            Data to set
5917a982d89SJeremy L. Thompson 
5927a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5937a982d89SJeremy L. Thompson 
5947a982d89SJeremy L. Thompson   @ref Backend
5957a982d89SJeremy L. Thompson **/
5967a982d89SJeremy L. Thompson 
597*777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
598*777ff853SJeremy L Thompson   op->data = data;
5997a982d89SJeremy L. Thompson   return 0;
6007a982d89SJeremy L. Thompson }
6017a982d89SJeremy L. Thompson 
6027a982d89SJeremy L. Thompson /**
6037a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
6047a982d89SJeremy L. Thompson 
6057a982d89SJeremy L. Thompson   @param op              CeedOperator
6067a982d89SJeremy L. Thompson 
6077a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6087a982d89SJeremy L. Thompson 
6097a982d89SJeremy L. Thompson   @ref Backend
6107a982d89SJeremy L. Thompson **/
6117a982d89SJeremy L. Thompson 
6127a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
6137a982d89SJeremy L. Thompson   op->setupdone = 1;
6147a982d89SJeremy L. Thompson   return 0;
6157a982d89SJeremy L. Thompson }
6167a982d89SJeremy L. Thompson 
6177a982d89SJeremy L. Thompson /**
6187a982d89SJeremy L. Thompson   @brief Get the CeedOperatorFields of a CeedOperator
6197a982d89SJeremy L. Thompson 
6207a982d89SJeremy L. Thompson   @param op                 CeedOperator
6217a982d89SJeremy L. Thompson   @param[out] inputfields   Variable to store inputfields
6227a982d89SJeremy L. Thompson   @param[out] outputfields  Variable to store outputfields
6237a982d89SJeremy L. Thompson 
6247a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6257a982d89SJeremy L. Thompson 
6267a982d89SJeremy L. Thompson   @ref Backend
6277a982d89SJeremy L. Thompson **/
6287a982d89SJeremy L. Thompson 
6297a982d89SJeremy L. Thompson int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
6307a982d89SJeremy L. Thompson                           CeedOperatorField **outputfields) {
6317a982d89SJeremy L. Thompson   if (op->composite)
6327a982d89SJeremy L. Thompson     // LCOV_EXCL_START
6337a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
6347a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6357a982d89SJeremy L. Thompson 
6367a982d89SJeremy L. Thompson   if (inputfields) *inputfields = op->inputfields;
6377a982d89SJeremy L. Thompson   if (outputfields) *outputfields = op->outputfields;
6387a982d89SJeremy L. Thompson   return 0;
6397a982d89SJeremy L. Thompson }
6407a982d89SJeremy L. Thompson 
6417a982d89SJeremy L. Thompson /**
6427a982d89SJeremy L. Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
6437a982d89SJeremy L. Thompson 
6447a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
6457a982d89SJeremy L. Thompson   @param[out] rstr       Variable to store CeedElemRestriction
6467a982d89SJeremy L. Thompson 
6477a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6487a982d89SJeremy L. Thompson 
6497a982d89SJeremy L. Thompson   @ref Backend
6507a982d89SJeremy L. Thompson **/
6517a982d89SJeremy L. Thompson 
6527a982d89SJeremy L. Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
6537a982d89SJeremy L. Thompson                                         CeedElemRestriction *rstr) {
6547a982d89SJeremy L. Thompson   *rstr = opfield->Erestrict;
6557a982d89SJeremy L. Thompson   return 0;
6567a982d89SJeremy L. Thompson }
6577a982d89SJeremy L. Thompson 
6587a982d89SJeremy L. Thompson /**
6597a982d89SJeremy L. Thompson   @brief Get the CeedBasis of a CeedOperatorField
6607a982d89SJeremy L. Thompson 
6617a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
6627a982d89SJeremy L. Thompson   @param[out] basis      Variable to store CeedBasis
6637a982d89SJeremy L. Thompson 
6647a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6657a982d89SJeremy L. Thompson 
6667a982d89SJeremy L. Thompson   @ref Backend
6677a982d89SJeremy L. Thompson **/
6687a982d89SJeremy L. Thompson 
6697a982d89SJeremy L. Thompson int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
6707a982d89SJeremy L. Thompson   *basis = opfield->basis;
6717a982d89SJeremy L. Thompson   return 0;
6727a982d89SJeremy L. Thompson }
6737a982d89SJeremy L. Thompson 
6747a982d89SJeremy L. Thompson /**
6757a982d89SJeremy L. Thompson   @brief Get the CeedVector of a CeedOperatorField
6767a982d89SJeremy L. Thompson 
6777a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
6787a982d89SJeremy L. Thompson   @param[out] vec        Variable to store CeedVector
6797a982d89SJeremy L. Thompson 
6807a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6817a982d89SJeremy L. Thompson 
6827a982d89SJeremy L. Thompson   @ref Backend
6837a982d89SJeremy L. Thompson **/
6847a982d89SJeremy L. Thompson 
6857a982d89SJeremy L. Thompson int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
6867a982d89SJeremy L. Thompson   *vec = opfield->vec;
6877a982d89SJeremy L. Thompson   return 0;
6887a982d89SJeremy L. Thompson }
6897a982d89SJeremy L. Thompson 
6907a982d89SJeremy L. Thompson /// @}
6917a982d89SJeremy L. Thompson 
6927a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
6937a982d89SJeremy L. Thompson /// CeedOperator Public API
6947a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
6957a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
696dfdf5a53Sjeremylt /// @{
697d7b241e6Sjeremylt 
698d7b241e6Sjeremylt /**
6990219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
7000219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
7010219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
702d7b241e6Sjeremylt 
703b11c1e72Sjeremylt   @param ceed    A Ceed object where the CeedOperator will be created
704d7b241e6Sjeremylt   @param qf      QFunction defining the action of the operator at quadrature points
70534138859Sjeremylt   @param dqf     QFunction defining the action of the Jacobian of @a qf (or
7064cc79fe7SJed Brown                    @ref CEED_QFUNCTION_NONE)
707d7b241e6Sjeremylt   @param dqfT    QFunction defining the action of the transpose of the Jacobian
7084cc79fe7SJed Brown                    of @a qf (or @ref CEED_QFUNCTION_NONE)
709b11c1e72Sjeremylt   @param[out] op Address of the variable where the newly created
710b11c1e72Sjeremylt                      CeedOperator will be stored
711b11c1e72Sjeremylt 
712b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
713dfdf5a53Sjeremylt 
7147a982d89SJeremy L. Thompson   @ref User
715d7b241e6Sjeremylt  */
716d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
717d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
718d7b241e6Sjeremylt   int ierr;
719d7b241e6Sjeremylt 
7205fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
7215fe0d4faSjeremylt     Ceed delegate;
722aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
7235fe0d4faSjeremylt 
7245fe0d4faSjeremylt     if (!delegate)
725c042f62fSJeremy L Thompson       // LCOV_EXCL_START
7265fe0d4faSjeremylt       return CeedError(ceed, 1, "Backend does not support OperatorCreate");
727c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
7285fe0d4faSjeremylt 
7295fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
7305fe0d4faSjeremylt     return 0;
7315fe0d4faSjeremylt   }
7325fe0d4faSjeremylt 
733b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
734b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
735b3b7035fSJeremy L Thompson     return CeedError(ceed, 1, "Operator must have a valid QFunction.");
736b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
737d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
738d7b241e6Sjeremylt   (*op)->ceed = ceed;
739d7b241e6Sjeremylt   ceed->refcount++;
740d7b241e6Sjeremylt   (*op)->refcount = 1;
741d7b241e6Sjeremylt   (*op)->qf = qf;
742d7b241e6Sjeremylt   qf->refcount++;
743442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
744d7b241e6Sjeremylt     (*op)->dqf = dqf;
745442e7f0bSjeremylt     dqf->refcount++;
746442e7f0bSjeremylt   }
747442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
748d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
749442e7f0bSjeremylt     dqfT->refcount++;
750442e7f0bSjeremylt   }
751fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
752fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
753d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
754d7b241e6Sjeremylt   return 0;
755d7b241e6Sjeremylt }
756d7b241e6Sjeremylt 
757d7b241e6Sjeremylt /**
75852d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
75952d6035fSJeremy L Thompson 
76052d6035fSJeremy L Thompson   @param ceed    A Ceed object where the CeedOperator will be created
76152d6035fSJeremy L Thompson   @param[out] op Address of the variable where the newly created
76252d6035fSJeremy L Thompson                      Composite CeedOperator will be stored
76352d6035fSJeremy L Thompson 
76452d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
76552d6035fSJeremy L Thompson 
7667a982d89SJeremy L. Thompson   @ref User
76752d6035fSJeremy L Thompson  */
76852d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
76952d6035fSJeremy L Thompson   int ierr;
77052d6035fSJeremy L Thompson 
77152d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
77252d6035fSJeremy L Thompson     Ceed delegate;
773aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
77452d6035fSJeremy L Thompson 
775250756a7Sjeremylt     if (delegate) {
77652d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
77752d6035fSJeremy L Thompson       return 0;
77852d6035fSJeremy L Thompson     }
779250756a7Sjeremylt   }
78052d6035fSJeremy L Thompson 
78152d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
78252d6035fSJeremy L Thompson   (*op)->ceed = ceed;
78352d6035fSJeremy L Thompson   ceed->refcount++;
78452d6035fSJeremy L Thompson   (*op)->composite = true;
78552d6035fSJeremy L Thompson   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
786250756a7Sjeremylt 
787250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
78852d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
789250756a7Sjeremylt   }
79052d6035fSJeremy L Thompson   return 0;
79152d6035fSJeremy L Thompson }
79252d6035fSJeremy L Thompson 
79352d6035fSJeremy L Thompson /**
794b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
795d7b241e6Sjeremylt 
796d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
797d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
798d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
799d7b241e6Sjeremylt 
800d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
801d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
802d7b241e6Sjeremylt   input and at most one active output.
803d7b241e6Sjeremylt 
8048c91a0c9SJeremy L Thompson   @param op         CeedOperator on which to provide the field
8058795c945Sjeremylt   @param fieldname  Name of the field (to be matched with the name used by
8068795c945Sjeremylt                       CeedQFunction)
807b11c1e72Sjeremylt   @param r          CeedElemRestriction
8084cc79fe7SJed Brown   @param b          CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
809b11c1e72Sjeremylt                       if collocated with quadrature points
8104cc79fe7SJed Brown   @param v          CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
8114cc79fe7SJed Brown                       if field is active or @ref CEED_VECTOR_NONE if using
8124cc79fe7SJed Brown                       @ref CEED_EVAL_WEIGHT in the QFunction
813b11c1e72Sjeremylt 
814b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
815dfdf5a53Sjeremylt 
8167a982d89SJeremy L. Thompson   @ref User
817b11c1e72Sjeremylt **/
818d7b241e6Sjeremylt int CeedOperatorSetField(CeedOperator op, const char *fieldname,
819a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
820d7b241e6Sjeremylt   int ierr;
82152d6035fSJeremy L Thompson   if (op->composite)
822c042f62fSJeremy L Thompson     // LCOV_EXCL_START
82352d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Cannot add field to composite operator.");
824c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
8258b067b84SJed Brown   if (!r)
826c042f62fSJeremy L Thompson     // LCOV_EXCL_START
827c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1,
828c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
829c042f62fSJeremy L Thompson                      fieldname);
830c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
8318b067b84SJed Brown   if (!b)
832c042f62fSJeremy L Thompson     // LCOV_EXCL_START
833c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.",
834c042f62fSJeremy L Thompson                      fieldname);
835c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
8368b067b84SJed Brown   if (!v)
837c042f62fSJeremy L Thompson     // LCOV_EXCL_START
838c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.",
839c042f62fSJeremy L Thompson                      fieldname);
840c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
84152d6035fSJeremy L Thompson 
842d7b241e6Sjeremylt   CeedInt numelements;
843d7b241e6Sjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
84415910d16Sjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->hasrestriction &&
84515910d16Sjeremylt       op->numelements != numelements)
846c042f62fSJeremy L Thompson     // LCOV_EXCL_START
847d7b241e6Sjeremylt     return CeedError(op->ceed, 1,
8481d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
8491d102b48SJeremy L Thompson                      "%d elements", numelements, op->numelements);
850c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
85115910d16Sjeremylt   if (r != CEED_ELEMRESTRICTION_NONE) {
852d7b241e6Sjeremylt     op->numelements = numelements;
8532cb0afc5Sjeremylt     op->hasrestriction = true; // Restriction set, but numelements may be 0
85415910d16Sjeremylt   }
855d7b241e6Sjeremylt 
856783c99b3SValeria Barra   if (b != CEED_BASIS_COLLOCATED) {
857d7b241e6Sjeremylt     CeedInt numqpoints;
858d7b241e6Sjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
859d7b241e6Sjeremylt     if (op->numqpoints && op->numqpoints != numqpoints)
860c042f62fSJeremy L Thompson       // LCOV_EXCL_START
8611d102b48SJeremy L Thompson       return CeedError(op->ceed, 1, "Basis with %d quadrature points "
8621d102b48SJeremy L Thompson                        "incompatible with prior %d points", numqpoints,
8631d102b48SJeremy L Thompson                        op->numqpoints);
864c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
865d7b241e6Sjeremylt     op->numqpoints = numqpoints;
866d7b241e6Sjeremylt   }
86715910d16Sjeremylt   CeedQFunctionField qfield;
868d1bcdac9Sjeremylt   CeedOperatorField *ofield;
869d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
870fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
87115910d16Sjeremylt       qfield = op->qf->inputfields[i];
872d7b241e6Sjeremylt       ofield = &op->inputfields[i];
873d7b241e6Sjeremylt       goto found;
874d7b241e6Sjeremylt     }
875d7b241e6Sjeremylt   }
876d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
877fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
87815910d16Sjeremylt       qfield = op->qf->inputfields[i];
879d7b241e6Sjeremylt       ofield = &op->outputfields[i];
880d7b241e6Sjeremylt       goto found;
881d7b241e6Sjeremylt     }
882d7b241e6Sjeremylt   }
883c042f62fSJeremy L Thompson   // LCOV_EXCL_START
884d7b241e6Sjeremylt   return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'",
885d7b241e6Sjeremylt                    fieldname);
886c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
887d7b241e6Sjeremylt found:
88815910d16Sjeremylt   if (r == CEED_ELEMRESTRICTION_NONE && qfield->emode != CEED_EVAL_WEIGHT)
889b0d62198Sjeremylt     // LCOV_EXCL_START
89015910d16Sjeremylt     return CeedError(op->ceed, 1, "CEED_ELEMRESTRICTION_NONE can only be used "
89115910d16Sjeremylt                      "for a field with eval mode CEED_EVAL_WEIGHT");
892b0d62198Sjeremylt   // LCOV_EXCL_STOP
893fe2413ffSjeremylt   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
894fe2413ffSjeremylt   (*ofield)->Erestrict = r;
89571352a93Sjeremylt   r->refcount += 1;
896fe2413ffSjeremylt   (*ofield)->basis = b;
89771352a93Sjeremylt   if (b != CEED_BASIS_COLLOCATED)
89871352a93Sjeremylt     b->refcount += 1;
899fe2413ffSjeremylt   (*ofield)->vec = v;
90071352a93Sjeremylt   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE)
90171352a93Sjeremylt     v->refcount += 1;
902d7b241e6Sjeremylt   op->nfields += 1;
903d99fa3c5SJeremy L Thompson 
904d99fa3c5SJeremy L Thompson   size_t len = strlen(fieldname);
905d99fa3c5SJeremy L Thompson   char *tmp;
906d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
907d99fa3c5SJeremy L Thompson   memcpy(tmp, fieldname, len+1);
908d99fa3c5SJeremy L Thompson   (*ofield)->fieldname = tmp;
909d7b241e6Sjeremylt   return 0;
910d7b241e6Sjeremylt }
911d7b241e6Sjeremylt 
912d7b241e6Sjeremylt /**
91352d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
914288c0443SJeremy L Thompson 
91534138859Sjeremylt   @param[out] compositeop Composite CeedOperator
91634138859Sjeremylt   @param      subop       Sub-operator CeedOperator
91752d6035fSJeremy L Thompson 
91852d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
91952d6035fSJeremy L Thompson 
9207a982d89SJeremy L. Thompson   @ref User
92152d6035fSJeremy L Thompson  */
922692c2638Sjeremylt int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) {
92352d6035fSJeremy L Thompson   if (!compositeop->composite)
924c042f62fSJeremy L Thompson     // LCOV_EXCL_START
9251d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite "
9261d102b48SJeremy L Thompson                      "operator");
927c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
92852d6035fSJeremy L Thompson 
92952d6035fSJeremy L Thompson   if (compositeop->numsub == CEED_COMPOSITE_MAX)
930c042f62fSJeremy L Thompson     // LCOV_EXCL_START
9311d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators");
932c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
93352d6035fSJeremy L Thompson 
93452d6035fSJeremy L Thompson   compositeop->suboperators[compositeop->numsub] = subop;
93552d6035fSJeremy L Thompson   subop->refcount++;
93652d6035fSJeremy L Thompson   compositeop->numsub++;
93752d6035fSJeremy L Thompson   return 0;
93852d6035fSJeremy L Thompson }
93952d6035fSJeremy L Thompson 
94052d6035fSJeremy L Thompson /**
9411d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
9421d102b48SJeremy L Thompson 
9431d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
9441d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
9451d102b48SJeremy L Thompson     The vector 'assembled' is of shape
9461d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
9471d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
9481d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
9491d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
9504cc79fe7SJed Brown     For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
9511d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
9521d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
9531d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
9541d102b48SJeremy L Thompson 
9551d102b48SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
9561d102b48SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedQFunction at
9571d102b48SJeremy L Thompson                           quadrature points
9581d102b48SJeremy L Thompson   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
9591d102b48SJeremy L Thompson                           CeedQFunction
9601d102b48SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
9614cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
9621d102b48SJeremy L Thompson 
9631d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9641d102b48SJeremy L Thompson 
9657a982d89SJeremy L. Thompson   @ref User
9661d102b48SJeremy L Thompson **/
96780ac2e43SJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled,
9687f823360Sjeremylt                                         CeedElemRestriction *rstr,
9697f823360Sjeremylt                                         CeedRequest *request) {
9701d102b48SJeremy L Thompson   int ierr;
9711d102b48SJeremy L Thompson   Ceed ceed = op->ceed;
972250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
9731d102b48SJeremy L Thompson 
9747172caadSjeremylt   // Backend version
97580ac2e43SJeremy L Thompson   if (op->LinearAssembleQFunction) {
97680ac2e43SJeremy L Thompson     ierr = op->LinearAssembleQFunction(op, assembled, rstr, request);
9771d102b48SJeremy L Thompson     CeedChk(ierr);
9785107b09fSJeremy L Thompson   } else {
9795107b09fSJeremy L Thompson     // Fallback to reference Ceed
9805107b09fSJeremy L Thompson     if (!op->opfallback) {
9815107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
9825107b09fSJeremy L Thompson     }
9835107b09fSJeremy L Thompson     // Assemble
98480ac2e43SJeremy L Thompson     ierr = op->opfallback->LinearAssembleQFunction(op->opfallback, assembled,
9855107b09fSJeremy L Thompson            rstr, request); CeedChk(ierr);
9865107b09fSJeremy L Thompson   }
987250756a7Sjeremylt 
9881d102b48SJeremy L Thompson   return 0;
9891d102b48SJeremy L Thompson }
9901d102b48SJeremy L Thompson 
9911d102b48SJeremy L Thompson /**
992d965c7a7SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
993b7ec98d8SJeremy L Thompson 
9949e9210b8SJeremy L Thompson   This overwrites a CeedVector with the diagonal of a linear CeedOperator.
995b7ec98d8SJeremy L Thompson 
996c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
997c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
998d965c7a7SJeremy L Thompson 
999b7ec98d8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
1000b7ec98d8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
1001b7ec98d8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
10024cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
1003b7ec98d8SJeremy L Thompson 
1004b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1005b7ec98d8SJeremy L Thompson 
10067a982d89SJeremy L. Thompson   @ref User
1007b7ec98d8SJeremy L Thompson **/
10082bba3ffaSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled,
10097f823360Sjeremylt                                        CeedRequest *request) {
1010b7ec98d8SJeremy L Thompson   int ierr;
1011b7ec98d8SJeremy L Thompson   Ceed ceed = op->ceed;
1012250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1013b7ec98d8SJeremy L Thompson 
1014b7ec98d8SJeremy L Thompson   // Use backend version, if available
101580ac2e43SJeremy L Thompson   if (op->LinearAssembleDiagonal) {
101680ac2e43SJeremy L Thompson     ierr = op->LinearAssembleDiagonal(op, assembled, request); CeedChk(ierr);
10179e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddDiagonal) {
10189e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
10199e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
10209e9210b8SJeremy L Thompson   } else {
10219e9210b8SJeremy L Thompson     // Fallback to reference Ceed
10229e9210b8SJeremy L Thompson     if (!op->opfallback) {
10239e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
10249e9210b8SJeremy L Thompson     }
10259e9210b8SJeremy L Thompson     // Assemble
10269e9210b8SJeremy L Thompson     if (op->opfallback->LinearAssembleDiagonal) {
10279e9210b8SJeremy L Thompson       ierr = op->opfallback->LinearAssembleDiagonal(op->opfallback, assembled,
10289e9210b8SJeremy L Thompson              request); CeedChk(ierr);
10299e9210b8SJeremy L Thompson     } else {
10309e9210b8SJeremy L Thompson       ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
10319e9210b8SJeremy L Thompson       return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
10329e9210b8SJeremy L Thompson     }
10339e9210b8SJeremy L Thompson   }
10349e9210b8SJeremy L Thompson 
10359e9210b8SJeremy L Thompson   return 0;
10369e9210b8SJeremy L Thompson }
10379e9210b8SJeremy L Thompson 
10389e9210b8SJeremy L Thompson /**
10399e9210b8SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
10409e9210b8SJeremy L Thompson 
10419e9210b8SJeremy L Thompson   This sums into a CeedVector the diagonal of a linear CeedOperator.
10429e9210b8SJeremy L Thompson 
10439e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
10449e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
10459e9210b8SJeremy L Thompson 
10469e9210b8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
10479e9210b8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
10489e9210b8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
10499e9210b8SJeremy L Thompson                           @ref CEED_REQUEST_IMMEDIATE
10509e9210b8SJeremy L Thompson 
10519e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
10529e9210b8SJeremy L Thompson 
10539e9210b8SJeremy L Thompson   @ref User
10549e9210b8SJeremy L Thompson **/
10559e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled,
10569e9210b8SJeremy L Thompson     CeedRequest *request) {
10579e9210b8SJeremy L Thompson   int ierr;
10589e9210b8SJeremy L Thompson   Ceed ceed = op->ceed;
10599e9210b8SJeremy L Thompson   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
10609e9210b8SJeremy L Thompson 
10619e9210b8SJeremy L Thompson   // Use backend version, if available
10629e9210b8SJeremy L Thompson   if (op->LinearAssembleAddDiagonal) {
10639e9210b8SJeremy L Thompson     ierr = op->LinearAssembleAddDiagonal(op, assembled, request); CeedChk(ierr);
10647172caadSjeremylt   } else {
10657172caadSjeremylt     // Fallback to reference Ceed
10667172caadSjeremylt     if (!op->opfallback) {
10677172caadSjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1068b7ec98d8SJeremy L Thompson     }
10697172caadSjeremylt     // Assemble
10702bba3ffaSJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
10719e9210b8SJeremy L Thompson     ierr = op->opfallback->LinearAssembleAddDiagonal(op->opfallback, assembled,
10727172caadSjeremylt            request); CeedChk(ierr);
1073b7ec98d8SJeremy L Thompson   }
1074b7ec98d8SJeremy L Thompson 
1075b7ec98d8SJeremy L Thompson   return 0;
1076b7ec98d8SJeremy L Thompson }
1077b7ec98d8SJeremy L Thompson 
1078b7ec98d8SJeremy L Thompson /**
1079d965c7a7SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
1080d965c7a7SJeremy L Thompson 
10819e9210b8SJeremy L Thompson   This overwrites a CeedVector with the point block diagonal of a linear
1082d965c7a7SJeremy L Thompson     CeedOperator.
1083d965c7a7SJeremy L Thompson 
1084c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1085c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1086d965c7a7SJeremy L Thompson 
1087d965c7a7SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
1088d965c7a7SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator point block
1089d965c7a7SJeremy L Thompson                           diagonal, provided in row-major form with an
1090d965c7a7SJeremy L Thompson                           @a ncomp * @a ncomp block at each node. The dimensions
1091d965c7a7SJeremy L Thompson                           of this vector are derived from the active vector
1092d965c7a7SJeremy L Thompson                           for the CeedOperator. The array has shape
1093d965c7a7SJeremy L Thompson                           [nodes, component out, component in].
1094d965c7a7SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
1095d965c7a7SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
1096d965c7a7SJeremy L Thompson 
1097d965c7a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1098d965c7a7SJeremy L Thompson 
1099d965c7a7SJeremy L Thompson   @ref User
1100d965c7a7SJeremy L Thompson **/
110180ac2e43SJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op,
11022bba3ffaSJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
1103d965c7a7SJeremy L Thompson   int ierr;
1104d965c7a7SJeremy L Thompson   Ceed ceed = op->ceed;
1105d965c7a7SJeremy L Thompson   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1106d965c7a7SJeremy L Thompson 
1107d965c7a7SJeremy L Thompson   // Use backend version, if available
110880ac2e43SJeremy L Thompson   if (op->LinearAssemblePointBlockDiagonal) {
110980ac2e43SJeremy L Thompson     ierr = op->LinearAssemblePointBlockDiagonal(op, assembled, request);
1110d965c7a7SJeremy L Thompson     CeedChk(ierr);
11119e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddPointBlockDiagonal) {
11129e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
11139e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
11149e9210b8SJeremy L Thompson            request);
1115d965c7a7SJeremy L Thompson   } else {
1116d965c7a7SJeremy L Thompson     // Fallback to reference Ceed
1117d965c7a7SJeremy L Thompson     if (!op->opfallback) {
1118d965c7a7SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1119d965c7a7SJeremy L Thompson     }
1120d965c7a7SJeremy L Thompson     // Assemble
11219e9210b8SJeremy L Thompson     if (op->opfallback->LinearAssemblePointBlockDiagonal) {
112280ac2e43SJeremy L Thompson       ierr = op->opfallback->LinearAssemblePointBlockDiagonal(op->opfallback,
1123d965c7a7SJeremy L Thompson              assembled, request); CeedChk(ierr);
11249e9210b8SJeremy L Thompson     } else {
11259e9210b8SJeremy L Thompson       ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
11269e9210b8SJeremy L Thompson       return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
11279e9210b8SJeremy L Thompson              request);
11289e9210b8SJeremy L Thompson     }
11299e9210b8SJeremy L Thompson   }
11309e9210b8SJeremy L Thompson 
11319e9210b8SJeremy L Thompson   return 0;
11329e9210b8SJeremy L Thompson }
11339e9210b8SJeremy L Thompson 
11349e9210b8SJeremy L Thompson /**
11359e9210b8SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
11369e9210b8SJeremy L Thompson 
11379e9210b8SJeremy L Thompson   This sums into a CeedVector with the point block diagonal of a linear
11389e9210b8SJeremy L Thompson     CeedOperator.
11399e9210b8SJeremy L Thompson 
11409e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
11419e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
11429e9210b8SJeremy L Thompson 
11439e9210b8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
11449e9210b8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator point block
11459e9210b8SJeremy L Thompson                           diagonal, provided in row-major form with an
11469e9210b8SJeremy L Thompson                           @a ncomp * @a ncomp block at each node. The dimensions
11479e9210b8SJeremy L Thompson                           of this vector are derived from the active vector
11489e9210b8SJeremy L Thompson                           for the CeedOperator. The array has shape
11499e9210b8SJeremy L Thompson                           [nodes, component out, component in].
11509e9210b8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
11519e9210b8SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
11529e9210b8SJeremy L Thompson 
11539e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11549e9210b8SJeremy L Thompson 
11559e9210b8SJeremy L Thompson   @ref User
11569e9210b8SJeremy L Thompson **/
11579e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op,
11589e9210b8SJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
11599e9210b8SJeremy L Thompson   int ierr;
11609e9210b8SJeremy L Thompson   Ceed ceed = op->ceed;
11619e9210b8SJeremy L Thompson   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
11629e9210b8SJeremy L Thompson 
11639e9210b8SJeremy L Thompson   // Use backend version, if available
11649e9210b8SJeremy L Thompson   if (op->LinearAssembleAddPointBlockDiagonal) {
11659e9210b8SJeremy L Thompson     ierr = op->LinearAssembleAddPointBlockDiagonal(op, assembled, request);
11669e9210b8SJeremy L Thompson     CeedChk(ierr);
11679e9210b8SJeremy L Thompson   } else {
11689e9210b8SJeremy L Thompson     // Fallback to reference Ceed
11699e9210b8SJeremy L Thompson     if (!op->opfallback) {
11709e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11719e9210b8SJeremy L Thompson     }
11729e9210b8SJeremy L Thompson     // Assemble
11739e9210b8SJeremy L Thompson     ierr = op->opfallback->LinearAssembleAddPointBlockDiagonal(op->opfallback,
11749e9210b8SJeremy L Thompson            assembled, request); CeedChk(ierr);
1175d965c7a7SJeremy L Thompson   }
1176d965c7a7SJeremy L Thompson 
1177d965c7a7SJeremy L Thompson   return 0;
1178d965c7a7SJeremy L Thompson }
1179d965c7a7SJeremy L Thompson 
1180d965c7a7SJeremy L Thompson /**
1181d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1182d99fa3c5SJeremy L Thompson            for a CeedOperator, creating the prolongation basis from the
1183d99fa3c5SJeremy L Thompson            fine and coarse grid interpolation
1184d99fa3c5SJeremy L Thompson 
1185d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1186d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1187d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1188d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1189d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1190d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1191d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1192d99fa3c5SJeremy L Thompson 
1193d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1194d99fa3c5SJeremy L Thompson 
1195d99fa3c5SJeremy L Thompson   @ref User
1196d99fa3c5SJeremy L Thompson **/
1197d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreate(CeedOperator opFine, CeedVector PMultFine,
1198d99fa3c5SJeremy L Thompson                                      CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
1199d99fa3c5SJeremy L Thompson                                      CeedOperator *opCoarse, CeedOperator *opProlong, CeedOperator *opRestrict) {
1200d99fa3c5SJeremy L Thompson   int ierr;
1201d99fa3c5SJeremy L Thompson   Ceed ceed;
1202d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1203d99fa3c5SJeremy L Thompson 
1204d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1205d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1206d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1207d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1208d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1209d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1210d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1211d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1212d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1, "Bases must have compatible quadrature spaces");
1213d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1214d99fa3c5SJeremy L Thompson 
1215d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1216d99fa3c5SJeremy L Thompson   CeedInt Pf, Pc, Q = Qf;
1217d99fa3c5SJeremy L Thompson   bool isTensorF, isTensorC;
1218d99fa3c5SJeremy L Thompson   ierr = CeedBasisIsTensor(basisFine, &isTensorF); CeedChk(ierr);
1219d99fa3c5SJeremy L Thompson   ierr = CeedBasisIsTensor(basisCoarse, &isTensorC); CeedChk(ierr);
1220d99fa3c5SJeremy L Thompson   CeedScalar *interpC, *interpF, *interpCtoF, *tau;
1221d99fa3c5SJeremy L Thompson   if (isTensorF && isTensorC) {
1222d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basisFine, &Pf); CeedChk(ierr);
1223d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basisCoarse, &Pc); CeedChk(ierr);
1224d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumQuadraturePoints1D(basisCoarse, &Q); CeedChk(ierr);
1225d99fa3c5SJeremy L Thompson   } else if (!isTensorF && !isTensorC) {
1226d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes(basisFine, &Pf); CeedChk(ierr);
1227d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes(basisCoarse, &Pc); CeedChk(ierr);
1228d99fa3c5SJeremy L Thompson   } else {
1229d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1230d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1, "Bases must both be tensor or non-tensor");
1231d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
1232d99fa3c5SJeremy L Thompson   }
1233d99fa3c5SJeremy L Thompson 
1234d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q*Pf, &interpF); CeedChk(ierr);
1235d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q*Pc, &interpC); CeedChk(ierr);
1236d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(Pc*Pf, &interpCtoF); CeedChk(ierr);
1237d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q, &tau); CeedChk(ierr);
1238d99fa3c5SJeremy L Thompson   if (isTensorF) {
1239d99fa3c5SJeremy L Thompson     memcpy(interpF, basisFine->interp1d, Q*Pf*sizeof basisFine->interp1d[0]);
1240d99fa3c5SJeremy L Thompson     memcpy(interpC, basisCoarse->interp1d, Q*Pc*sizeof basisCoarse->interp1d[0]);
1241d99fa3c5SJeremy L Thompson   } else {
1242d99fa3c5SJeremy L Thompson     memcpy(interpF, basisFine->interp, Q*Pf*sizeof basisFine->interp[0]);
1243d99fa3c5SJeremy L Thompson     memcpy(interpC, basisCoarse->interp, Q*Pc*sizeof basisCoarse->interp[0]);
1244d99fa3c5SJeremy L Thompson   }
1245d99fa3c5SJeremy L Thompson 
1246d99fa3c5SJeremy L Thompson   // -- QR Factorization, interpF = Q R
1247d99fa3c5SJeremy L Thompson   ierr = CeedQRFactorization(ceed, interpF, tau, Q, Pf); CeedChk(ierr);
1248d99fa3c5SJeremy L Thompson 
1249d99fa3c5SJeremy L Thompson   // -- Apply Qtranspose, interpC = Qtranspose interpC
1250d99fa3c5SJeremy L Thompson   CeedHouseholderApplyQ(interpC, interpF, tau, CEED_TRANSPOSE,
1251d99fa3c5SJeremy L Thompson                         Q, Pc, Pf, Pc, 1);
1252d99fa3c5SJeremy L Thompson 
1253d99fa3c5SJeremy L Thompson   // -- Apply Rinv, interpCtoF = Rinv interpC
1254d99fa3c5SJeremy L Thompson   for (CeedInt j=0; j<Pc; j++) { // Column j
1255d99fa3c5SJeremy L Thompson     interpCtoF[j+Pc*(Pf-1)] = interpC[j+Pc*(Pf-1)]/interpF[Pf*Pf-1];
1256d99fa3c5SJeremy L Thompson     for (CeedInt i=Pf-2; i>=0; i--) { // Row i
1257d99fa3c5SJeremy L Thompson       interpCtoF[j+Pc*i] = interpC[j+Pc*i];
1258d99fa3c5SJeremy L Thompson       for (CeedInt k=i+1; k<Pf; k++)
1259d99fa3c5SJeremy L Thompson         interpCtoF[j+Pc*i] -= interpF[k+Pf*i]*interpCtoF[j+Pc*k];
1260d99fa3c5SJeremy L Thompson       interpCtoF[j+Pc*i] /= interpF[i+Pf*i];
1261d99fa3c5SJeremy L Thompson     }
1262d99fa3c5SJeremy L Thompson   }
1263d99fa3c5SJeremy L Thompson   ierr = CeedFree(&tau); CeedChk(ierr);
1264d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpC); CeedChk(ierr);
1265d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpF); CeedChk(ierr);
1266d99fa3c5SJeremy L Thompson 
1267d99fa3c5SJeremy L Thompson   // Fallback to interpCtoF versions of code
1268d99fa3c5SJeremy L Thompson   if (isTensorF) {
1269d99fa3c5SJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateTensorH1(opFine, PMultFine,
1270d99fa3c5SJeremy L Thompson            rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict);
1271d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1272d99fa3c5SJeremy L Thompson   } else {
1273d99fa3c5SJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateH1(opFine, PMultFine,
1274d99fa3c5SJeremy L Thompson            rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict);
1275d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1276d99fa3c5SJeremy L Thompson   }
1277d99fa3c5SJeremy L Thompson 
1278d99fa3c5SJeremy L Thompson   // Cleanup
1279d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpCtoF); CeedChk(ierr);
1280d99fa3c5SJeremy L Thompson   return 0;
1281d99fa3c5SJeremy L Thompson }
1282d99fa3c5SJeremy L Thompson 
1283d99fa3c5SJeremy L Thompson /**
1284d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1285d99fa3c5SJeremy L Thompson            for a CeedOperator with a tensor basis for the active basis
1286d99fa3c5SJeremy L Thompson 
1287d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1288d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1289d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1290d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1291d99fa3c5SJeremy L Thompson   @param[in] interpCtoF   Matrix for coarse to fine interpolation
1292d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1293d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1294d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1295d99fa3c5SJeremy L Thompson 
1296d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1297d99fa3c5SJeremy L Thompson 
1298d99fa3c5SJeremy L Thompson   @ref User
1299d99fa3c5SJeremy L Thompson **/
1300d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator opFine,
1301d99fa3c5SJeremy L Thompson     CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
1302d99fa3c5SJeremy L Thompson     const CeedScalar *interpCtoF, CeedOperator *opCoarse,
1303d99fa3c5SJeremy L Thompson     CeedOperator *opProlong, CeedOperator *opRestrict) {
1304d99fa3c5SJeremy L Thompson   int ierr;
1305d99fa3c5SJeremy L Thompson   Ceed ceed;
1306d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1307d99fa3c5SJeremy L Thompson 
1308d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1309d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1310d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1311d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1312d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1313d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1314d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1315d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1316d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1, "Bases must have compatible quadrature spaces");
1317d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1318d99fa3c5SJeremy L Thompson 
1319d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1320d99fa3c5SJeremy L Thompson   CeedInt dim, ncomp, nnodesCoarse, P1dFine, P1dCoarse;
1321d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr);
1322d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr);
1323d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumNodes1D(basisFine, &P1dFine); CeedChk(ierr);
1324d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse);
1325d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1326d99fa3c5SJeremy L Thompson   P1dCoarse = dim == 1 ? nnodesCoarse :
1327d99fa3c5SJeremy L Thompson               dim == 2 ? sqrt(nnodesCoarse) :
1328d99fa3c5SJeremy L Thompson               cbrt(nnodesCoarse);
1329d99fa3c5SJeremy L Thompson   CeedScalar *qref, *qweight, *grad;
1330d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine, &qref); CeedChk(ierr);
1331d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine, &qweight); CeedChk(ierr);
1332d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine*P1dCoarse*dim, &grad); CeedChk(ierr);
1333d99fa3c5SJeremy L Thompson   CeedBasis basisCtoF;
1334d99fa3c5SJeremy L Thompson   ierr = CeedBasisCreateTensorH1(ceed, dim, ncomp, P1dCoarse, P1dFine,
1335d99fa3c5SJeremy L Thompson                                  interpCtoF, grad, qref, qweight, &basisCtoF);
1336d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1337d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qref); CeedChk(ierr);
1338d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qweight); CeedChk(ierr);
1339d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
1340d99fa3c5SJeremy L Thompson 
1341d99fa3c5SJeremy L Thompson   // Core code
1342d99fa3c5SJeremy L Thompson   ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse,
1343d99fa3c5SJeremy L Thompson                                          basisCoarse, basisCtoF, opCoarse,
1344d99fa3c5SJeremy L Thompson                                          opProlong, opRestrict);
1345d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1346d99fa3c5SJeremy L Thompson   return 0;
1347d99fa3c5SJeremy L Thompson }
1348d99fa3c5SJeremy L Thompson 
1349d99fa3c5SJeremy L Thompson /**
1350d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1351d99fa3c5SJeremy L Thompson            for a CeedOperator with a non-tensor basis for the active vector
1352d99fa3c5SJeremy L Thompson 
1353d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1354d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1355d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1356d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1357d99fa3c5SJeremy L Thompson   @param[in] interpCtoF   Matrix for coarse to fine interpolation
1358d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1359d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1360d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1361d99fa3c5SJeremy L Thompson 
1362d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1363d99fa3c5SJeremy L Thompson 
1364d99fa3c5SJeremy L Thompson   @ref User
1365d99fa3c5SJeremy L Thompson **/
1366d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreateH1(CeedOperator opFine,
1367d99fa3c5SJeremy L Thompson                                        CeedVector PMultFine,
1368d99fa3c5SJeremy L Thompson                                        CeedElemRestriction rstrCoarse,
1369d99fa3c5SJeremy L Thompson                                        CeedBasis basisCoarse,
1370d99fa3c5SJeremy L Thompson                                        const CeedScalar *interpCtoF,
1371d99fa3c5SJeremy L Thompson                                        CeedOperator *opCoarse,
1372d99fa3c5SJeremy L Thompson                                        CeedOperator *opProlong,
1373d99fa3c5SJeremy L Thompson                                        CeedOperator *opRestrict) {
1374d99fa3c5SJeremy L Thompson   int ierr;
1375d99fa3c5SJeremy L Thompson   Ceed ceed;
1376d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1377d99fa3c5SJeremy L Thompson 
1378d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1379d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1380d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1381d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1382d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1383d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1384d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1385d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1386d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1, "Bases must have compatible quadrature spaces");
1387d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1388d99fa3c5SJeremy L Thompson 
1389d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1390d99fa3c5SJeremy L Thompson   CeedElemTopology topo;
1391d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetTopology(basisFine, &topo); CeedChk(ierr);
1392d99fa3c5SJeremy L Thompson   CeedInt dim, ncomp, nnodesCoarse, nnodesFine;
1393d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr);
1394d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr);
1395d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumNodes(basisFine, &nnodesFine); CeedChk(ierr);
1396d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse);
1397d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1398d99fa3c5SJeremy L Thompson   CeedScalar *qref, *qweight, *grad;
1399d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine, &qref); CeedChk(ierr);
1400d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine, &qweight); CeedChk(ierr);
1401d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine*nnodesCoarse*dim, &grad); CeedChk(ierr);
1402d99fa3c5SJeremy L Thompson   CeedBasis basisCtoF;
1403d99fa3c5SJeremy L Thompson   ierr = CeedBasisCreateH1(ceed, topo, ncomp, nnodesCoarse, nnodesFine,
1404d99fa3c5SJeremy L Thompson                            interpCtoF, grad, qref, qweight, &basisCtoF);
1405d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1406d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qref); CeedChk(ierr);
1407d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qweight); CeedChk(ierr);
1408d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
1409d99fa3c5SJeremy L Thompson 
1410d99fa3c5SJeremy L Thompson   // Core code
1411d99fa3c5SJeremy L Thompson   ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse,
1412d99fa3c5SJeremy L Thompson                                          basisCoarse, basisCtoF, opCoarse,
1413d99fa3c5SJeremy L Thompson                                          opProlong, opRestrict);
1414d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1415d99fa3c5SJeremy L Thompson   return 0;
1416d99fa3c5SJeremy L Thompson }
1417d99fa3c5SJeremy L Thompson 
1418d99fa3c5SJeremy L Thompson /**
14193bd813ffSjeremylt   @brief Build a FDM based approximate inverse for each element for a
14203bd813ffSjeremylt            CeedOperator
14213bd813ffSjeremylt 
14223bd813ffSjeremylt   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
14233bd813ffSjeremylt     Method based approximate inverse. This function obtains the simultaneous
14243bd813ffSjeremylt     diagonalization for the 1D mass and Laplacian operators,
14253bd813ffSjeremylt       M = V^T V, K = V^T S V.
14263bd813ffSjeremylt     The assembled QFunction is used to modify the eigenvalues from simultaneous
14273bd813ffSjeremylt     diagonalization and obtain an approximate inverse of the form
14283bd813ffSjeremylt       V^T S^hat V. The CeedOperator must be linear and non-composite. The
14293bd813ffSjeremylt     associated CeedQFunction must therefore also be linear.
14303bd813ffSjeremylt 
14313bd813ffSjeremylt   @param op             CeedOperator to create element inverses
14323bd813ffSjeremylt   @param[out] fdminv    CeedOperator to apply the action of a FDM based inverse
14333bd813ffSjeremylt                           for each element
14343bd813ffSjeremylt   @param request        Address of CeedRequest for non-blocking completion, else
14354cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
14363bd813ffSjeremylt 
14373bd813ffSjeremylt   @return An error code: 0 - success, otherwise - failure
14383bd813ffSjeremylt 
14397a982d89SJeremy L. Thompson   @ref Backend
14403bd813ffSjeremylt **/
14413bd813ffSjeremylt int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv,
14423bd813ffSjeremylt                                         CeedRequest *request) {
14433bd813ffSjeremylt   int ierr;
14443bd813ffSjeremylt   Ceed ceed = op->ceed;
1445713f43c3Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
14463bd813ffSjeremylt 
1447713f43c3Sjeremylt   // Use backend version, if available
1448713f43c3Sjeremylt   if (op->CreateFDMElementInverse) {
1449713f43c3Sjeremylt     ierr = op->CreateFDMElementInverse(op, fdminv, request); CeedChk(ierr);
1450713f43c3Sjeremylt   } else {
1451713f43c3Sjeremylt     // Fallback to reference Ceed
1452713f43c3Sjeremylt     if (!op->opfallback) {
1453713f43c3Sjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
14543bd813ffSjeremylt     }
1455713f43c3Sjeremylt     // Assemble
1456713f43c3Sjeremylt     ierr = op->opfallback->CreateFDMElementInverse(op->opfallback, fdminv,
14573bd813ffSjeremylt            request); CeedChk(ierr);
14583bd813ffSjeremylt   }
14593bd813ffSjeremylt 
14603bd813ffSjeremylt   return 0;
14613bd813ffSjeremylt }
14623bd813ffSjeremylt 
14637a982d89SJeremy L. Thompson /**
14647a982d89SJeremy L. Thompson   @brief View a CeedOperator
14657a982d89SJeremy L. Thompson 
14667a982d89SJeremy L. Thompson   @param[in] op     CeedOperator to view
14677a982d89SJeremy L. Thompson   @param[in] stream Stream to write; typically stdout/stderr or a file
14687a982d89SJeremy L. Thompson 
14697a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
14707a982d89SJeremy L. Thompson 
14717a982d89SJeremy L. Thompson   @ref User
14727a982d89SJeremy L. Thompson **/
14737a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
14747a982d89SJeremy L. Thompson   int ierr;
14757a982d89SJeremy L. Thompson 
14767a982d89SJeremy L. Thompson   if (op->composite) {
14777a982d89SJeremy L. Thompson     fprintf(stream, "Composite CeedOperator\n");
14787a982d89SJeremy L. Thompson 
14797a982d89SJeremy L. Thompson     for (CeedInt i=0; i<op->numsub; i++) {
14807a982d89SJeremy L. Thompson       fprintf(stream, "  SubOperator [%d]:\n", i);
14817a982d89SJeremy L. Thompson       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
14827a982d89SJeremy L. Thompson       CeedChk(ierr);
14837a982d89SJeremy L. Thompson     }
14847a982d89SJeremy L. Thompson   } else {
14857a982d89SJeremy L. Thompson     fprintf(stream, "CeedOperator\n");
14867a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
14877a982d89SJeremy L. Thompson   }
14887a982d89SJeremy L. Thompson 
14897a982d89SJeremy L. Thompson   return 0;
14907a982d89SJeremy L. Thompson }
14913bd813ffSjeremylt 
14923bd813ffSjeremylt /**
14933bd813ffSjeremylt   @brief Apply CeedOperator to a vector
1494d7b241e6Sjeremylt 
1495d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
1496d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1497d7b241e6Sjeremylt   CeedOperatorSetField().
1498d7b241e6Sjeremylt 
1499d7b241e6Sjeremylt   @param op        CeedOperator to apply
15004cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
150134138859Sjeremylt                   there are no active inputs
1502b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
15034cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
150434138859Sjeremylt                      active outputs
1505d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
15064cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1507b11c1e72Sjeremylt 
1508b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1509dfdf5a53Sjeremylt 
15107a982d89SJeremy L. Thompson   @ref User
1511b11c1e72Sjeremylt **/
1512692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
1513692c2638Sjeremylt                       CeedRequest *request) {
1514d7b241e6Sjeremylt   int ierr;
1515d7b241e6Sjeremylt   Ceed ceed = op->ceed;
1516250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1517d7b241e6Sjeremylt 
1518250756a7Sjeremylt   if (op->numelements)  {
1519250756a7Sjeremylt     // Standard Operator
1520cae8b89aSjeremylt     if (op->Apply) {
1521250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
1522cae8b89aSjeremylt     } else {
1523cae8b89aSjeremylt       // Zero all output vectors
1524250756a7Sjeremylt       CeedQFunction qf = op->qf;
1525cae8b89aSjeremylt       for (CeedInt i=0; i<qf->numoutputfields; i++) {
1526cae8b89aSjeremylt         CeedVector vec = op->outputfields[i]->vec;
1527cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
1528cae8b89aSjeremylt           vec = out;
1529cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
1530cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1531cae8b89aSjeremylt         }
1532cae8b89aSjeremylt       }
1533250756a7Sjeremylt       // Apply
1534250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1535250756a7Sjeremylt     }
1536250756a7Sjeremylt   } else if (op->composite) {
1537250756a7Sjeremylt     // Composite Operator
1538250756a7Sjeremylt     if (op->ApplyComposite) {
1539250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
1540250756a7Sjeremylt     } else {
1541250756a7Sjeremylt       CeedInt numsub;
1542250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1543250756a7Sjeremylt       CeedOperator *suboperators;
1544250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1545250756a7Sjeremylt 
1546250756a7Sjeremylt       // Zero all output vectors
1547250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
1548cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
1549cae8b89aSjeremylt       }
1550250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
1551250756a7Sjeremylt         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
1552250756a7Sjeremylt           CeedVector vec = suboperators[i]->outputfields[j]->vec;
1553250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
1554250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1555250756a7Sjeremylt           }
1556250756a7Sjeremylt         }
1557250756a7Sjeremylt       }
1558250756a7Sjeremylt       // Apply
1559250756a7Sjeremylt       for (CeedInt i=0; i<op->numsub; i++) {
1560250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
1561cae8b89aSjeremylt         CeedChk(ierr);
1562cae8b89aSjeremylt       }
1563cae8b89aSjeremylt     }
1564250756a7Sjeremylt   }
1565250756a7Sjeremylt 
1566cae8b89aSjeremylt   return 0;
1567cae8b89aSjeremylt }
1568cae8b89aSjeremylt 
1569cae8b89aSjeremylt /**
1570cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
1571cae8b89aSjeremylt 
1572cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
1573cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1574cae8b89aSjeremylt   CeedOperatorSetField().
1575cae8b89aSjeremylt 
1576cae8b89aSjeremylt   @param op        CeedOperator to apply
1577cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
1578cae8b89aSjeremylt                      active inputs
1579cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
1580cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
1581cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
15824cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1583cae8b89aSjeremylt 
1584cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
1585cae8b89aSjeremylt 
15867a982d89SJeremy L. Thompson   @ref User
1587cae8b89aSjeremylt **/
1588cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
1589cae8b89aSjeremylt                          CeedRequest *request) {
1590cae8b89aSjeremylt   int ierr;
1591cae8b89aSjeremylt   Ceed ceed = op->ceed;
1592250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1593cae8b89aSjeremylt 
1594250756a7Sjeremylt   if (op->numelements)  {
1595250756a7Sjeremylt     // Standard Operator
1596250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1597250756a7Sjeremylt   } else if (op->composite) {
1598250756a7Sjeremylt     // Composite Operator
1599250756a7Sjeremylt     if (op->ApplyAddComposite) {
1600250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
1601cae8b89aSjeremylt     } else {
1602250756a7Sjeremylt       CeedInt numsub;
1603250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1604250756a7Sjeremylt       CeedOperator *suboperators;
1605250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1606250756a7Sjeremylt 
1607250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
1608250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
1609cae8b89aSjeremylt         CeedChk(ierr);
16101d7d2407SJeremy L Thompson       }
1611250756a7Sjeremylt     }
1612250756a7Sjeremylt   }
1613250756a7Sjeremylt 
1614d7b241e6Sjeremylt   return 0;
1615d7b241e6Sjeremylt }
1616d7b241e6Sjeremylt 
1617d7b241e6Sjeremylt /**
1618b11c1e72Sjeremylt   @brief Destroy a CeedOperator
1619d7b241e6Sjeremylt 
1620d7b241e6Sjeremylt   @param op CeedOperator to destroy
1621b11c1e72Sjeremylt 
1622b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1623dfdf5a53Sjeremylt 
16247a982d89SJeremy L. Thompson   @ref User
1625b11c1e72Sjeremylt **/
1626d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1627d7b241e6Sjeremylt   int ierr;
1628d7b241e6Sjeremylt 
1629d7b241e6Sjeremylt   if (!*op || --(*op)->refcount > 0) return 0;
1630d7b241e6Sjeremylt   if ((*op)->Destroy) {
1631d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1632d7b241e6Sjeremylt   }
1633fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1634fe2413ffSjeremylt   // Free fields
16351d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
163652d6035fSJeremy L Thompson     if ((*op)->inputfields[i]) {
163715910d16Sjeremylt       if ((*op)->inputfields[i]->Erestrict != CEED_ELEMRESTRICTION_NONE) {
163871352a93Sjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
163971352a93Sjeremylt         CeedChk(ierr);
164015910d16Sjeremylt       }
164171352a93Sjeremylt       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
164271352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
164371352a93Sjeremylt       }
164471352a93Sjeremylt       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
164571352a93Sjeremylt           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
164671352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
164771352a93Sjeremylt       }
1648d99fa3c5SJeremy L Thompson       ierr = CeedFree(&(*op)->inputfields[i]->fieldname); CeedChk(ierr);
1649fe2413ffSjeremylt       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
1650fe2413ffSjeremylt     }
16511d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
1652d0eb30a5Sjeremylt     if ((*op)->outputfields[i]) {
165371352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
165471352a93Sjeremylt       CeedChk(ierr);
165571352a93Sjeremylt       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
165671352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
165771352a93Sjeremylt       }
165871352a93Sjeremylt       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
165971352a93Sjeremylt           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
166071352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
166171352a93Sjeremylt       }
1662d99fa3c5SJeremy L Thompson       ierr = CeedFree(&(*op)->outputfields[i]->fieldname); CeedChk(ierr);
1663fe2413ffSjeremylt       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
1664fe2413ffSjeremylt     }
166552d6035fSJeremy L Thompson   // Destroy suboperators
16661d102b48SJeremy L Thompson   for (int i=0; i<(*op)->numsub; i++)
166752d6035fSJeremy L Thompson     if ((*op)->suboperators[i]) {
166852d6035fSJeremy L Thompson       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
166952d6035fSJeremy L Thompson     }
1670d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1671d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1672d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1673fe2413ffSjeremylt 
16745107b09fSJeremy L Thompson   // Destroy fallback
16755107b09fSJeremy L Thompson   if ((*op)->opfallback) {
16765107b09fSJeremy L Thompson     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
16775107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
16785107b09fSJeremy L Thompson     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
16795107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
16805107b09fSJeremy L Thompson   }
16815107b09fSJeremy L Thompson 
1682fe2413ffSjeremylt   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
1683fe2413ffSjeremylt   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
168452d6035fSJeremy L Thompson   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
1685d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1686d7b241e6Sjeremylt   return 0;
1687d7b241e6Sjeremylt }
1688d7b241e6Sjeremylt 
1689d7b241e6Sjeremylt /// @}
1690