xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-operator.c (revision 3d576824e8d990e1f48c6609089904bee9170514)
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 
17*3d576824SJeremy L Thompson #include <ceed.h>
18d863ab9bSjeremylt #include <ceed-backend.h>
19*3d576824SJeremy L Thompson #include <ceed-impl.h>
203bd813ffSjeremylt #include <math.h>
21*3d576824SJeremy L Thompson #include <stdbool.h>
22*3d576824SJeremy L Thompson #include <stdio.h>
23*3d576824SJeremy L Thompson #include <string.h>
24d7b241e6Sjeremylt 
25dfdf5a53Sjeremylt /// @file
267a982d89SJeremy L. Thompson /// Implementation of CeedOperator interfaces
277a982d89SJeremy L. Thompson 
287a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
297a982d89SJeremy L. Thompson /// CeedOperator Library Internal Functions
307a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
317a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorDeveloper
327a982d89SJeremy L. Thompson /// @{
337a982d89SJeremy L. Thompson 
347a982d89SJeremy L. Thompson /**
357a982d89SJeremy L. Thompson   @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced
367a982d89SJeremy L. Thompson            CeedOperator functionality
377a982d89SJeremy L. Thompson 
387a982d89SJeremy L. Thompson   @param op           CeedOperator to create fallback for
397a982d89SJeremy L. Thompson 
407a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
417a982d89SJeremy L. Thompson 
427a982d89SJeremy L. Thompson   @ref Developer
437a982d89SJeremy L. Thompson **/
447a982d89SJeremy L. Thompson int CeedOperatorCreateFallback(CeedOperator op) {
457a982d89SJeremy L. Thompson   int ierr;
467a982d89SJeremy L. Thompson 
477a982d89SJeremy L. Thompson   // Fallback Ceed
487a982d89SJeremy L. Thompson   const char *resource, *fallbackresource;
497a982d89SJeremy L. Thompson   ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
507a982d89SJeremy L. Thompson   ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
517a982d89SJeremy L. Thompson   CeedChk(ierr);
527a982d89SJeremy L. Thompson   if (!strcmp(resource, fallbackresource))
537a982d89SJeremy L. Thompson     // LCOV_EXCL_START
547a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Backend %s cannot create an operator"
557a982d89SJeremy L. Thompson                      "fallback to resource %s", resource, fallbackresource);
567a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
577a982d89SJeremy L. Thompson 
587a982d89SJeremy L. Thompson   // Fallback Ceed
597a982d89SJeremy L. Thompson   Ceed ceedref;
607a982d89SJeremy L. Thompson   if (!op->ceed->opfallbackceed) {
617a982d89SJeremy L. Thompson     ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr);
627a982d89SJeremy L. Thompson     ceedref->opfallbackparent = op->ceed;
63fc164cf7SWill Pazner     ceedref->Error = op->ceed->Error;
647a982d89SJeremy L. Thompson     op->ceed->opfallbackceed = ceedref;
657a982d89SJeremy L. Thompson   }
667a982d89SJeremy L. Thompson   ceedref = op->ceed->opfallbackceed;
677a982d89SJeremy L. Thompson 
687a982d89SJeremy L. Thompson   // Clone Op
697a982d89SJeremy L. Thompson   CeedOperator opref;
707a982d89SJeremy L. Thompson   ierr = CeedCalloc(1, &opref); CeedChk(ierr);
717a982d89SJeremy L. Thompson   memcpy(opref, op, sizeof(*opref)); CeedChk(ierr);
727a982d89SJeremy L. Thompson   opref->data = NULL;
737a982d89SJeremy L. Thompson   opref->setupdone = 0;
747a982d89SJeremy L. Thompson   opref->ceed = ceedref;
757a982d89SJeremy L. Thompson   ierr = ceedref->OperatorCreate(opref); CeedChk(ierr);
767a982d89SJeremy L. Thompson   op->opfallback = opref;
777a982d89SJeremy L. Thompson 
787a982d89SJeremy L. Thompson   // Clone QF
797a982d89SJeremy L. Thompson   CeedQFunction qfref;
807a982d89SJeremy L. Thompson   ierr = CeedCalloc(1, &qfref); CeedChk(ierr);
817a982d89SJeremy L. Thompson   memcpy(qfref, (op->qf), sizeof(*qfref)); CeedChk(ierr);
827a982d89SJeremy L. Thompson   qfref->data = NULL;
837a982d89SJeremy L. Thompson   qfref->ceed = ceedref;
847a982d89SJeremy L. Thompson   ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr);
857a982d89SJeremy L. Thompson   opref->qf = qfref;
867a982d89SJeremy L. Thompson   op->qffallback = qfref;
877a982d89SJeremy L. Thompson 
887a982d89SJeremy L. Thompson   return 0;
897a982d89SJeremy L. Thompson }
907a982d89SJeremy L. Thompson 
917a982d89SJeremy L. Thompson /**
927a982d89SJeremy L. Thompson   @brief Check if a CeedOperator is ready to be used.
937a982d89SJeremy L. Thompson 
947a982d89SJeremy L. Thompson   @param[in] ceed Ceed object for error handling
957a982d89SJeremy L. Thompson   @param[in] op   CeedOperator to check
967a982d89SJeremy L. Thompson 
977a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
987a982d89SJeremy L. Thompson 
997a982d89SJeremy L. Thompson   @ref Developer
1007a982d89SJeremy L. Thompson **/
1017a982d89SJeremy L. Thompson static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) {
1027a982d89SJeremy L. Thompson   CeedQFunction qf = op->qf;
1037a982d89SJeremy L. Thompson 
1047a982d89SJeremy L. Thompson   if (op->composite) {
1057a982d89SJeremy L. Thompson     if (!op->numsub)
1067a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1077a982d89SJeremy L. Thompson       return CeedError(ceed, 1, "No suboperators set");
1087a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1097a982d89SJeremy L. Thompson   } else {
1107a982d89SJeremy L. Thompson     if (op->nfields == 0)
1117a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1127a982d89SJeremy L. Thompson       return CeedError(ceed, 1, "No operator fields set");
1137a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1147a982d89SJeremy L. Thompson     if (op->nfields < qf->numinputfields + qf->numoutputfields)
1157a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1167a982d89SJeremy L. Thompson       return CeedError(ceed, 1, "Not all operator fields set");
1177a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1187a982d89SJeremy L. Thompson     if (!op->hasrestriction)
1197a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1207a982d89SJeremy L. Thompson       return CeedError(ceed, 1,"At least one restriction required");
1217a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1227a982d89SJeremy L. Thompson     if (op->numqpoints == 0)
1237a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1247a982d89SJeremy L. Thompson       return CeedError(ceed, 1,"At least one non-collocated basis required");
1257a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1267a982d89SJeremy L. Thompson   }
1277a982d89SJeremy L. Thompson 
1287a982d89SJeremy L. Thompson   return 0;
1297a982d89SJeremy L. Thompson }
1307a982d89SJeremy L. Thompson 
1317a982d89SJeremy L. Thompson /**
1327a982d89SJeremy L. Thompson   @brief View a field of a CeedOperator
1337a982d89SJeremy L. Thompson 
1347a982d89SJeremy L. Thompson   @param[in] field       Operator field to view
1354c4400c7SValeria Barra   @param[in] qffield     QFunction field (carries field name)
1367a982d89SJeremy L. Thompson   @param[in] fieldnumber Number of field being viewed
1374c4400c7SValeria Barra   @param[in] sub         true indicates sub-operator, which increases indentation; false for top-level operator
1384c4400c7SValeria Barra   @param[in] in          true for an input field; false for output field
1397a982d89SJeremy L. Thompson   @param[in] stream      Stream to view to, e.g., stdout
1407a982d89SJeremy L. Thompson 
1417a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1427a982d89SJeremy L. Thompson 
1437a982d89SJeremy L. Thompson   @ref Utility
1447a982d89SJeremy L. Thompson **/
1457a982d89SJeremy L. Thompson static int CeedOperatorFieldView(CeedOperatorField field,
1467a982d89SJeremy L. Thompson                                  CeedQFunctionField qffield,
1477a982d89SJeremy L. Thompson                                  CeedInt fieldnumber, bool sub, bool in,
1487a982d89SJeremy L. Thompson                                  FILE *stream) {
1497a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
1507a982d89SJeremy L. Thompson   const char *inout = in ? "Input" : "Output";
1517a982d89SJeremy L. Thompson 
1527a982d89SJeremy L. Thompson   fprintf(stream, "%s    %s Field [%d]:\n"
1537a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
1547a982d89SJeremy L. Thompson           pre, inout, fieldnumber, pre, qffield->fieldname);
1557a982d89SJeremy L. Thompson 
1567a982d89SJeremy L. Thompson   if (field->basis == CEED_BASIS_COLLOCATED)
1577a982d89SJeremy L. Thompson     fprintf(stream, "%s      Collocated basis\n", pre);
1587a982d89SJeremy L. Thompson 
1597a982d89SJeremy L. Thompson   if (field->vec == CEED_VECTOR_ACTIVE)
1607a982d89SJeremy L. Thompson     fprintf(stream, "%s      Active vector\n", pre);
1617a982d89SJeremy L. Thompson   else if (field->vec == CEED_VECTOR_NONE)
1627a982d89SJeremy L. Thompson     fprintf(stream, "%s      No vector\n", pre);
1637a982d89SJeremy L. Thompson 
1647a982d89SJeremy L. Thompson   return 0;
1657a982d89SJeremy L. Thompson }
1667a982d89SJeremy L. Thompson 
1677a982d89SJeremy L. Thompson /**
1687a982d89SJeremy L. Thompson   @brief View a single CeedOperator
1697a982d89SJeremy L. Thompson 
1707a982d89SJeremy L. Thompson   @param[in] op     CeedOperator to view
1717a982d89SJeremy L. Thompson   @param[in] sub    Boolean flag for sub-operator
1727a982d89SJeremy L. Thompson   @param[in] stream Stream to write; typically stdout/stderr or a file
1737a982d89SJeremy L. Thompson 
1747a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
1757a982d89SJeremy L. Thompson 
1767a982d89SJeremy L. Thompson   @ref Utility
1777a982d89SJeremy L. Thompson **/
1787a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
1797a982d89SJeremy L. Thompson   int ierr;
1807a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
1817a982d89SJeremy L. Thompson 
1827a982d89SJeremy L. Thompson   CeedInt totalfields;
1837a982d89SJeremy L. Thompson   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
1847a982d89SJeremy L. Thompson 
1857a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
1867a982d89SJeremy L. Thompson 
1877a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
1887a982d89SJeremy L. Thompson           op->qf->numinputfields>1 ? "s" : "");
1897a982d89SJeremy L. Thompson   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
1907a982d89SJeremy L. Thompson     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
1917a982d89SJeremy L. Thompson                                  i, sub, 1, stream); CeedChk(ierr);
1927a982d89SJeremy L. Thompson   }
1937a982d89SJeremy L. Thompson 
1947a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
1957a982d89SJeremy L. Thompson           op->qf->numoutputfields>1 ? "s" : "");
1967a982d89SJeremy L. Thompson   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
197829936eeSWill Pazner     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->outputfields[i],
1987a982d89SJeremy L. Thompson                                  i, sub, 0, stream); CeedChk(ierr);
1997a982d89SJeremy L. Thompson   }
2007a982d89SJeremy L. Thompson 
2017a982d89SJeremy L. Thompson   return 0;
2027a982d89SJeremy L. Thompson }
2037a982d89SJeremy L. Thompson 
204d99fa3c5SJeremy L Thompson /**
205d99fa3c5SJeremy L Thompson   @brief Find the active vector basis for a CeedOperator
206d99fa3c5SJeremy L Thompson 
207d99fa3c5SJeremy L Thompson   @param[in] op            CeedOperator to find active basis for
208d99fa3c5SJeremy L Thompson   @param[out] activeBasis  Basis for active input vector
209d99fa3c5SJeremy L Thompson 
210d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
211d99fa3c5SJeremy L Thompson 
212d99fa3c5SJeremy L Thompson   @ ref Developer
213d99fa3c5SJeremy L Thompson **/
214d99fa3c5SJeremy L Thompson static int CeedOperatorGetActiveBasis(CeedOperator op,
215d99fa3c5SJeremy L Thompson                                       CeedBasis *activeBasis) {
216d99fa3c5SJeremy L Thompson   *activeBasis = NULL;
217d99fa3c5SJeremy L Thompson   for (int i = 0; i < op->qf->numinputfields; i++)
218d99fa3c5SJeremy L Thompson     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
219d99fa3c5SJeremy L Thompson       *activeBasis = op->inputfields[i]->basis;
220d99fa3c5SJeremy L Thompson       break;
221d99fa3c5SJeremy L Thompson     }
222d99fa3c5SJeremy L Thompson 
223d99fa3c5SJeremy L Thompson   if (!*activeBasis) {
224d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
225d99fa3c5SJeremy L Thompson     int ierr;
226d99fa3c5SJeremy L Thompson     Ceed ceed;
227d99fa3c5SJeremy L Thompson     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
228d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1,
229d99fa3c5SJeremy L Thompson                      "No active basis found for automatic multigrid setup");
230d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
231d99fa3c5SJeremy L Thompson   }
232d99fa3c5SJeremy L Thompson   return 0;
233d99fa3c5SJeremy L Thompson }
234d99fa3c5SJeremy L Thompson 
235d99fa3c5SJeremy L Thompson 
236d99fa3c5SJeremy L Thompson /**
237d99fa3c5SJeremy L Thompson   @brief Common code for creating a multigrid coarse operator and level
238d99fa3c5SJeremy L Thompson            transfer operators for a CeedOperator
239d99fa3c5SJeremy L Thompson 
240d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
241d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
242d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
243d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
244d99fa3c5SJeremy L Thompson   @param[in] basisCtoF    Basis for coarse to fine interpolation
245d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
246d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
247d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
248d99fa3c5SJeremy L Thompson 
249d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
250d99fa3c5SJeremy L Thompson 
251d99fa3c5SJeremy L Thompson   @ref Developer
252d99fa3c5SJeremy L Thompson **/
253d99fa3c5SJeremy L Thompson static int CeedOperatorMultigridLevel_Core(CeedOperator opFine,
254d99fa3c5SJeremy L Thompson     CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
255d99fa3c5SJeremy L Thompson     CeedBasis basisCtoF, CeedOperator *opCoarse, CeedOperator *opProlong,
256d99fa3c5SJeremy L Thompson     CeedOperator *opRestrict) {
257d99fa3c5SJeremy L Thompson   int ierr;
258d99fa3c5SJeremy L Thompson   Ceed ceed;
259d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
260d99fa3c5SJeremy L Thompson 
261d99fa3c5SJeremy L Thompson   // Check for composite operator
262d99fa3c5SJeremy L Thompson   bool isComposite;
263d99fa3c5SJeremy L Thompson   ierr = CeedOperatorIsComposite(opFine, &isComposite); CeedChk(ierr);
264d99fa3c5SJeremy L Thompson   if (isComposite)
265d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
266d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1,
267d99fa3c5SJeremy L Thompson                      "Automatic multigrid setup for composite operators not supported");
268d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
269d99fa3c5SJeremy L Thompson 
270d99fa3c5SJeremy L Thompson   // Coarse Grid
271d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, opFine->qf, opFine->dqf, opFine->dqfT,
272d99fa3c5SJeremy L Thompson                             opCoarse); CeedChk(ierr);
273d99fa3c5SJeremy L Thompson   CeedElemRestriction rstrFine = NULL;
274d99fa3c5SJeremy L Thompson   // -- Clone input fields
275d99fa3c5SJeremy L Thompson   for (int i = 0; i < opFine->qf->numinputfields; i++) {
276d99fa3c5SJeremy L Thompson     if (opFine->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
277d99fa3c5SJeremy L Thompson       rstrFine = opFine->inputfields[i]->Erestrict;
278d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname,
279d99fa3c5SJeremy L Thompson                                   rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE);
280d99fa3c5SJeremy L Thompson       CeedChk(ierr);
281d99fa3c5SJeremy L Thompson     } else {
282d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname,
283d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->Erestrict,
284d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->basis,
285d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->vec); CeedChk(ierr);
286d99fa3c5SJeremy L Thompson     }
287d99fa3c5SJeremy L Thompson   }
288d99fa3c5SJeremy L Thompson   // -- Clone output fields
289d99fa3c5SJeremy L Thompson   for (int i = 0; i < opFine->qf->numoutputfields; i++) {
290d99fa3c5SJeremy L Thompson     if (opFine->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
291d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname,
292d99fa3c5SJeremy L Thompson                                   rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE);
293d99fa3c5SJeremy L Thompson       CeedChk(ierr);
294d99fa3c5SJeremy L Thompson     } else {
295d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname,
296d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->Erestrict,
297d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->basis,
298d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->vec); CeedChk(ierr);
299d99fa3c5SJeremy L Thompson     }
300d99fa3c5SJeremy L Thompson   }
301d99fa3c5SJeremy L Thompson 
302d99fa3c5SJeremy L Thompson   // Multiplicity vector
303d99fa3c5SJeremy L Thompson   CeedVector multVec, multE;
304d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionCreateVector(rstrFine, &multVec, &multE);
305d99fa3c5SJeremy L Thompson   CeedChk(ierr);
306d99fa3c5SJeremy L Thompson   ierr = CeedVectorSetValue(multE, 0.0); CeedChk(ierr);
307d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrFine, CEED_NOTRANSPOSE, PMultFine, multE,
308d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
309d99fa3c5SJeremy L Thompson   ierr = CeedVectorSetValue(multVec, 0.0); CeedChk(ierr);
310d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrFine, CEED_TRANSPOSE, multE, multVec,
311d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
312d99fa3c5SJeremy L Thompson   ierr = CeedVectorDestroy(&multE); CeedChk(ierr);
313d99fa3c5SJeremy L Thompson   ierr = CeedVectorReciprocal(multVec); CeedChk(ierr);
314d99fa3c5SJeremy L Thompson 
315d99fa3c5SJeremy L Thompson   // Restriction
316d99fa3c5SJeremy L Thompson   CeedInt ncomp;
317d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisCoarse, &ncomp); CeedChk(ierr);
318d99fa3c5SJeremy L Thompson   CeedQFunction qfRestrict;
319d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfRestrict);
320d99fa3c5SJeremy L Thompson   CeedChk(ierr);
321777ff853SJeremy L Thompson   CeedInt *ncompRData;
322777ff853SJeremy L Thompson   ierr = CeedCalloc(1, &ncompRData); CeedChk(ierr);
323777ff853SJeremy L Thompson   ncompRData[0] = ncomp;
324777ff853SJeremy L Thompson   CeedQFunctionContext ctxR;
325777ff853SJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctxR); CeedChk(ierr);
326777ff853SJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctxR, CEED_MEM_HOST, CEED_OWN_POINTER,
327777ff853SJeremy L Thompson                                      sizeof(*ncompRData), ncompRData);
328777ff853SJeremy L Thompson   CeedChk(ierr);
329777ff853SJeremy L Thompson   ierr = CeedQFunctionSetContext(qfRestrict, ctxR); CeedChk(ierr);
330777ff853SJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctxR); CeedChk(ierr);
331d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfRestrict, "input", ncomp, CEED_EVAL_NONE);
332d99fa3c5SJeremy L Thompson   CeedChk(ierr);
333d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfRestrict, "scale", ncomp, CEED_EVAL_NONE);
334d99fa3c5SJeremy L Thompson   CeedChk(ierr);
335d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddOutput(qfRestrict, "output", ncomp, CEED_EVAL_INTERP);
336d99fa3c5SJeremy L Thompson   CeedChk(ierr);
337d99fa3c5SJeremy L Thompson 
338d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qfRestrict, CEED_QFUNCTION_NONE,
339d99fa3c5SJeremy L Thompson                             CEED_QFUNCTION_NONE, opRestrict);
340d99fa3c5SJeremy L Thompson   CeedChk(ierr);
341d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "input", rstrFine,
342d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
343d99fa3c5SJeremy L Thompson   CeedChk(ierr);
344d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "scale", rstrFine,
345d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, multVec);
346d99fa3c5SJeremy L Thompson   CeedChk(ierr);
347d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "output", rstrCoarse, basisCtoF,
348d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
349d99fa3c5SJeremy L Thompson 
350d99fa3c5SJeremy L Thompson   // Prolongation
351d99fa3c5SJeremy L Thompson   CeedQFunction qfProlong;
352d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfProlong);
353d99fa3c5SJeremy L Thompson   CeedChk(ierr);
354777ff853SJeremy L Thompson   CeedInt *ncompPData;
355777ff853SJeremy L Thompson   ierr = CeedCalloc(1, &ncompPData); CeedChk(ierr);
356777ff853SJeremy L Thompson   ncompPData[0] = ncomp;
357777ff853SJeremy L Thompson   CeedQFunctionContext ctxP;
358777ff853SJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctxP); CeedChk(ierr);
359777ff853SJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctxP, CEED_MEM_HOST, CEED_OWN_POINTER,
360777ff853SJeremy L Thompson                                      sizeof(*ncompPData), ncompPData);
361777ff853SJeremy L Thompson   CeedChk(ierr);
362777ff853SJeremy L Thompson   ierr = CeedQFunctionSetContext(qfProlong, ctxP); CeedChk(ierr);
363777ff853SJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctxP); CeedChk(ierr);
364d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfProlong, "input", ncomp, CEED_EVAL_INTERP);
365d99fa3c5SJeremy L Thompson   CeedChk(ierr);
366d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfProlong, "scale", ncomp, CEED_EVAL_NONE);
367d99fa3c5SJeremy L Thompson   CeedChk(ierr);
368d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddOutput(qfProlong, "output", ncomp, CEED_EVAL_NONE);
369d99fa3c5SJeremy L Thompson   CeedChk(ierr);
370d99fa3c5SJeremy L Thompson 
371d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qfProlong, CEED_QFUNCTION_NONE,
372d99fa3c5SJeremy L Thompson                             CEED_QFUNCTION_NONE, opProlong);
373d99fa3c5SJeremy L Thompson   CeedChk(ierr);
374d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "input", rstrCoarse, basisCtoF,
375d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
376d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "scale", rstrFine,
377d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, multVec);
378d99fa3c5SJeremy L Thompson   CeedChk(ierr);
379d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "output", rstrFine,
380d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
381d99fa3c5SJeremy L Thompson   CeedChk(ierr);
382d99fa3c5SJeremy L Thompson 
383d99fa3c5SJeremy L Thompson   // Cleanup
384d99fa3c5SJeremy L Thompson   ierr = CeedVectorDestroy(&multVec); CeedChk(ierr);
385d99fa3c5SJeremy L Thompson   ierr = CeedBasisDestroy(&basisCtoF); CeedChk(ierr);
386d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionDestroy(&qfRestrict); CeedChk(ierr);
387d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionDestroy(&qfProlong); CeedChk(ierr);
388d99fa3c5SJeremy L Thompson 
389d99fa3c5SJeremy L Thompson   return 0;
390d99fa3c5SJeremy L Thompson }
391d99fa3c5SJeremy L Thompson 
3927a982d89SJeremy L. Thompson /// @}
3937a982d89SJeremy L. Thompson 
3947a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3957a982d89SJeremy L. Thompson /// CeedOperator Backend API
3967a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3977a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
3987a982d89SJeremy L. Thompson /// @{
3997a982d89SJeremy L. Thompson 
4007a982d89SJeremy L. Thompson /**
4017a982d89SJeremy L. Thompson   @brief Get the Ceed associated with a CeedOperator
4027a982d89SJeremy L. Thompson 
4037a982d89SJeremy L. Thompson   @param op              CeedOperator
4047a982d89SJeremy L. Thompson   @param[out] ceed       Variable to store Ceed
4057a982d89SJeremy L. Thompson 
4067a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4077a982d89SJeremy L. Thompson 
4087a982d89SJeremy L. Thompson   @ref Backend
4097a982d89SJeremy L. Thompson **/
4107a982d89SJeremy L. Thompson 
4117a982d89SJeremy L. Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
4127a982d89SJeremy L. Thompson   *ceed = op->ceed;
4137a982d89SJeremy L. Thompson   return 0;
4147a982d89SJeremy L. Thompson }
4157a982d89SJeremy L. Thompson 
4167a982d89SJeremy L. Thompson /**
4177a982d89SJeremy L. Thompson   @brief Get the number of elements associated with a CeedOperator
4187a982d89SJeremy L. Thompson 
4197a982d89SJeremy L. Thompson   @param op              CeedOperator
4207a982d89SJeremy L. Thompson   @param[out] numelem    Variable to store number of elements
4217a982d89SJeremy L. Thompson 
4227a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4237a982d89SJeremy L. Thompson 
4247a982d89SJeremy L. Thompson   @ref Backend
4257a982d89SJeremy L. Thompson **/
4267a982d89SJeremy L. Thompson 
4277a982d89SJeremy L. Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
4287a982d89SJeremy L. Thompson   if (op->composite)
4297a982d89SJeremy L. Thompson     // LCOV_EXCL_START
4307a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
4317a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4327a982d89SJeremy L. Thompson 
4337a982d89SJeremy L. Thompson   *numelem = op->numelements;
4347a982d89SJeremy L. Thompson   return 0;
4357a982d89SJeremy L. Thompson }
4367a982d89SJeremy L. Thompson 
4377a982d89SJeremy L. Thompson /**
4387a982d89SJeremy L. Thompson   @brief Get the number of quadrature points associated with a CeedOperator
4397a982d89SJeremy L. Thompson 
4407a982d89SJeremy L. Thompson   @param op              CeedOperator
4417a982d89SJeremy L. Thompson   @param[out] numqpts    Variable to store vector number of quadrature points
4427a982d89SJeremy L. Thompson 
4437a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4447a982d89SJeremy L. Thompson 
4457a982d89SJeremy L. Thompson   @ref Backend
4467a982d89SJeremy L. Thompson **/
4477a982d89SJeremy L. Thompson 
4487a982d89SJeremy L. Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
4497a982d89SJeremy L. Thompson   if (op->composite)
4507a982d89SJeremy L. Thompson     // LCOV_EXCL_START
4517a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
4527a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4537a982d89SJeremy L. Thompson 
4547a982d89SJeremy L. Thompson   *numqpts = op->numqpoints;
4557a982d89SJeremy L. Thompson   return 0;
4567a982d89SJeremy L. Thompson }
4577a982d89SJeremy L. Thompson 
4587a982d89SJeremy L. Thompson /**
4597a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
4607a982d89SJeremy L. Thompson 
4617a982d89SJeremy L. Thompson   @param op              CeedOperator
4627a982d89SJeremy L. Thompson   @param[out] numargs    Variable to store vector number of arguments
4637a982d89SJeremy L. Thompson 
4647a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4657a982d89SJeremy L. Thompson 
4667a982d89SJeremy L. Thompson   @ref Backend
4677a982d89SJeremy L. Thompson **/
4687a982d89SJeremy L. Thompson 
4697a982d89SJeremy L. Thompson int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
4707a982d89SJeremy L. Thompson   if (op->composite)
4717a982d89SJeremy L. Thompson     // LCOV_EXCL_START
4727a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operators");
4737a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4747a982d89SJeremy L. Thompson 
4757a982d89SJeremy L. Thompson   *numargs = op->nfields;
4767a982d89SJeremy L. Thompson   return 0;
4777a982d89SJeremy L. Thompson }
4787a982d89SJeremy L. Thompson 
4797a982d89SJeremy L. Thompson /**
4807a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
4817a982d89SJeremy L. Thompson 
4827a982d89SJeremy L. Thompson   @param op                CeedOperator
483fd364f38SJeremy L Thompson   @param[out] issetupdone  Variable to store setup status
4847a982d89SJeremy L. Thompson 
4857a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4867a982d89SJeremy L. Thompson 
4877a982d89SJeremy L. Thompson   @ref Backend
4887a982d89SJeremy L. Thompson **/
4897a982d89SJeremy L. Thompson 
490fd364f38SJeremy L Thompson int CeedOperatorIsSetupDone(CeedOperator op, bool *issetupdone) {
491fd364f38SJeremy L Thompson   *issetupdone = op->setupdone;
4927a982d89SJeremy L. Thompson   return 0;
4937a982d89SJeremy L. Thompson }
4947a982d89SJeremy L. Thompson 
4957a982d89SJeremy L. Thompson /**
4967a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
4977a982d89SJeremy L. Thompson 
4987a982d89SJeremy L. Thompson   @param op              CeedOperator
4997a982d89SJeremy L. Thompson   @param[out] qf         Variable to store QFunction
5007a982d89SJeremy L. Thompson 
5017a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5027a982d89SJeremy L. Thompson 
5037a982d89SJeremy L. Thompson   @ref Backend
5047a982d89SJeremy L. Thompson **/
5057a982d89SJeremy L. Thompson 
5067a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
5077a982d89SJeremy L. Thompson   if (op->composite)
5087a982d89SJeremy L. Thompson     // LCOV_EXCL_START
5097a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
5107a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5117a982d89SJeremy L. Thompson 
5127a982d89SJeremy L. Thompson   *qf = op->qf;
5137a982d89SJeremy L. Thompson   return 0;
5147a982d89SJeremy L. Thompson }
5157a982d89SJeremy L. Thompson 
5167a982d89SJeremy L. Thompson /**
517c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
518c04a41a7SJeremy L Thompson 
519c04a41a7SJeremy L Thompson   @param op                CeedOperator
520fd364f38SJeremy L Thompson   @param[out] iscomposite  Variable to store composite status
521c04a41a7SJeremy L Thompson 
522c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
523c04a41a7SJeremy L Thompson 
524c04a41a7SJeremy L Thompson   @ref Backend
525c04a41a7SJeremy L Thompson **/
526c04a41a7SJeremy L Thompson 
527fd364f38SJeremy L Thompson int CeedOperatorIsComposite(CeedOperator op, bool *iscomposite) {
528fd364f38SJeremy L Thompson   *iscomposite = op->composite;
529c04a41a7SJeremy L Thompson   return 0;
530c04a41a7SJeremy L Thompson }
531c04a41a7SJeremy L Thompson 
532c04a41a7SJeremy L Thompson /**
5337a982d89SJeremy L. Thompson   @brief Get the number of suboperators associated with a CeedOperator
5347a982d89SJeremy L. Thompson 
5357a982d89SJeremy L. Thompson   @param op              CeedOperator
5367a982d89SJeremy L. Thompson   @param[out] numsub     Variable to store number of suboperators
5377a982d89SJeremy L. Thompson 
5387a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5397a982d89SJeremy L. Thompson 
5407a982d89SJeremy L. Thompson   @ref Backend
5417a982d89SJeremy L. Thompson **/
5427a982d89SJeremy L. Thompson 
5437a982d89SJeremy L. Thompson int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
5447a982d89SJeremy L. Thompson   if (!op->composite)
5457a982d89SJeremy L. Thompson     // LCOV_EXCL_START
5467a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
5477a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5487a982d89SJeremy L. Thompson 
5497a982d89SJeremy L. Thompson   *numsub = op->numsub;
5507a982d89SJeremy L. Thompson   return 0;
5517a982d89SJeremy L. Thompson }
5527a982d89SJeremy L. Thompson 
5537a982d89SJeremy L. Thompson /**
5547a982d89SJeremy L. Thompson   @brief Get the list of suboperators associated with a CeedOperator
5557a982d89SJeremy L. Thompson 
5567a982d89SJeremy L. Thompson   @param op                CeedOperator
5577a982d89SJeremy L. Thompson   @param[out] suboperators Variable to store list of suboperators
5587a982d89SJeremy L. Thompson 
5597a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5607a982d89SJeremy L. Thompson 
5617a982d89SJeremy L. Thompson   @ref Backend
5627a982d89SJeremy L. Thompson **/
5637a982d89SJeremy L. Thompson 
5647a982d89SJeremy L. Thompson int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
5657a982d89SJeremy L. Thompson   if (!op->composite)
5667a982d89SJeremy L. Thompson     // LCOV_EXCL_START
5677a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
5687a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5697a982d89SJeremy L. Thompson 
5707a982d89SJeremy L. Thompson   *suboperators = op->suboperators;
5717a982d89SJeremy L. Thompson   return 0;
5727a982d89SJeremy L. Thompson }
5737a982d89SJeremy L. Thompson 
5747a982d89SJeremy L. Thompson /**
5757a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
5767a982d89SJeremy L. Thompson 
5777a982d89SJeremy L. Thompson   @param op              CeedOperator
5787a982d89SJeremy L. Thompson   @param[out] data       Variable to store data
5797a982d89SJeremy L. Thompson 
5807a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5817a982d89SJeremy L. Thompson 
5827a982d89SJeremy L. Thompson   @ref Backend
5837a982d89SJeremy L. Thompson **/
5847a982d89SJeremy L. Thompson 
585777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
586777ff853SJeremy L Thompson   *(void **)data = op->data;
5877a982d89SJeremy L. Thompson   return 0;
5887a982d89SJeremy L. Thompson }
5897a982d89SJeremy L. Thompson 
5907a982d89SJeremy L. Thompson /**
5917a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
5927a982d89SJeremy L. Thompson 
5937a982d89SJeremy L. Thompson   @param[out] op         CeedOperator
5947a982d89SJeremy L. Thompson   @param data            Data to set
5957a982d89SJeremy L. Thompson 
5967a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5977a982d89SJeremy L. Thompson 
5987a982d89SJeremy L. Thompson   @ref Backend
5997a982d89SJeremy L. Thompson **/
6007a982d89SJeremy L. Thompson 
601777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
602777ff853SJeremy L Thompson   op->data = data;
6037a982d89SJeremy L. Thompson   return 0;
6047a982d89SJeremy L. Thompson }
6057a982d89SJeremy L. Thompson 
6067a982d89SJeremy L. Thompson /**
6077a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
6087a982d89SJeremy L. Thompson 
6097a982d89SJeremy L. Thompson   @param op              CeedOperator
6107a982d89SJeremy L. Thompson 
6117a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6127a982d89SJeremy L. Thompson 
6137a982d89SJeremy L. Thompson   @ref Backend
6147a982d89SJeremy L. Thompson **/
6157a982d89SJeremy L. Thompson 
6167a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
6177a982d89SJeremy L. Thompson   op->setupdone = 1;
6187a982d89SJeremy L. Thompson   return 0;
6197a982d89SJeremy L. Thompson }
6207a982d89SJeremy L. Thompson 
6217a982d89SJeremy L. Thompson /**
6227a982d89SJeremy L. Thompson   @brief Get the CeedOperatorFields of a CeedOperator
6237a982d89SJeremy L. Thompson 
6247a982d89SJeremy L. Thompson   @param op                 CeedOperator
6257a982d89SJeremy L. Thompson   @param[out] inputfields   Variable to store inputfields
6267a982d89SJeremy L. Thompson   @param[out] outputfields  Variable to store outputfields
6277a982d89SJeremy L. Thompson 
6287a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6297a982d89SJeremy L. Thompson 
6307a982d89SJeremy L. Thompson   @ref Backend
6317a982d89SJeremy L. Thompson **/
6327a982d89SJeremy L. Thompson 
6337a982d89SJeremy L. Thompson int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
6347a982d89SJeremy L. Thompson                           CeedOperatorField **outputfields) {
6357a982d89SJeremy L. Thompson   if (op->composite)
6367a982d89SJeremy L. Thompson     // LCOV_EXCL_START
6377a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
6387a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6397a982d89SJeremy L. Thompson 
6407a982d89SJeremy L. Thompson   if (inputfields) *inputfields = op->inputfields;
6417a982d89SJeremy L. Thompson   if (outputfields) *outputfields = op->outputfields;
6427a982d89SJeremy L. Thompson   return 0;
6437a982d89SJeremy L. Thompson }
6447a982d89SJeremy L. Thompson 
6457a982d89SJeremy L. Thompson /**
6467a982d89SJeremy L. Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
6477a982d89SJeremy L. Thompson 
6487a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
6497a982d89SJeremy L. Thompson   @param[out] rstr       Variable to store CeedElemRestriction
6507a982d89SJeremy L. Thompson 
6517a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6527a982d89SJeremy L. Thompson 
6537a982d89SJeremy L. Thompson   @ref Backend
6547a982d89SJeremy L. Thompson **/
6557a982d89SJeremy L. Thompson 
6567a982d89SJeremy L. Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
6577a982d89SJeremy L. Thompson                                         CeedElemRestriction *rstr) {
6587a982d89SJeremy L. Thompson   *rstr = opfield->Erestrict;
6597a982d89SJeremy L. Thompson   return 0;
6607a982d89SJeremy L. Thompson }
6617a982d89SJeremy L. Thompson 
6627a982d89SJeremy L. Thompson /**
6637a982d89SJeremy L. Thompson   @brief Get the CeedBasis of a CeedOperatorField
6647a982d89SJeremy L. Thompson 
6657a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
6667a982d89SJeremy L. Thompson   @param[out] basis      Variable to store CeedBasis
6677a982d89SJeremy L. Thompson 
6687a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6697a982d89SJeremy L. Thompson 
6707a982d89SJeremy L. Thompson   @ref Backend
6717a982d89SJeremy L. Thompson **/
6727a982d89SJeremy L. Thompson 
6737a982d89SJeremy L. Thompson int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
6747a982d89SJeremy L. Thompson   *basis = opfield->basis;
6757a982d89SJeremy L. Thompson   return 0;
6767a982d89SJeremy L. Thompson }
6777a982d89SJeremy L. Thompson 
6787a982d89SJeremy L. Thompson /**
6797a982d89SJeremy L. Thompson   @brief Get the CeedVector of a CeedOperatorField
6807a982d89SJeremy L. Thompson 
6817a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
6827a982d89SJeremy L. Thompson   @param[out] vec        Variable to store CeedVector
6837a982d89SJeremy L. Thompson 
6847a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6857a982d89SJeremy L. Thompson 
6867a982d89SJeremy L. Thompson   @ref Backend
6877a982d89SJeremy L. Thompson **/
6887a982d89SJeremy L. Thompson 
6897a982d89SJeremy L. Thompson int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
6907a982d89SJeremy L. Thompson   *vec = opfield->vec;
6917a982d89SJeremy L. Thompson   return 0;
6927a982d89SJeremy L. Thompson }
6937a982d89SJeremy L. Thompson 
6947a982d89SJeremy L. Thompson /// @}
6957a982d89SJeremy L. Thompson 
6967a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
6977a982d89SJeremy L. Thompson /// CeedOperator Public API
6987a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
6997a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
700dfdf5a53Sjeremylt /// @{
701d7b241e6Sjeremylt 
702d7b241e6Sjeremylt /**
7030219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
7040219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
7050219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
706d7b241e6Sjeremylt 
707b11c1e72Sjeremylt   @param ceed    A Ceed object where the CeedOperator will be created
708d7b241e6Sjeremylt   @param qf      QFunction defining the action of the operator at quadrature points
70934138859Sjeremylt   @param dqf     QFunction defining the action of the Jacobian of @a qf (or
7104cc79fe7SJed Brown                    @ref CEED_QFUNCTION_NONE)
711d7b241e6Sjeremylt   @param dqfT    QFunction defining the action of the transpose of the Jacobian
7124cc79fe7SJed Brown                    of @a qf (or @ref CEED_QFUNCTION_NONE)
713b11c1e72Sjeremylt   @param[out] op Address of the variable where the newly created
714b11c1e72Sjeremylt                      CeedOperator will be stored
715b11c1e72Sjeremylt 
716b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
717dfdf5a53Sjeremylt 
7187a982d89SJeremy L. Thompson   @ref User
719d7b241e6Sjeremylt  */
720d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
721d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
722d7b241e6Sjeremylt   int ierr;
723d7b241e6Sjeremylt 
7245fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
7255fe0d4faSjeremylt     Ceed delegate;
726aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
7275fe0d4faSjeremylt 
7285fe0d4faSjeremylt     if (!delegate)
729c042f62fSJeremy L Thompson       // LCOV_EXCL_START
7305fe0d4faSjeremylt       return CeedError(ceed, 1, "Backend does not support OperatorCreate");
731c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
7325fe0d4faSjeremylt 
7335fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
7345fe0d4faSjeremylt     return 0;
7355fe0d4faSjeremylt   }
7365fe0d4faSjeremylt 
737b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
738b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
739b3b7035fSJeremy L Thompson     return CeedError(ceed, 1, "Operator must have a valid QFunction.");
740b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
741d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
742d7b241e6Sjeremylt   (*op)->ceed = ceed;
743d7b241e6Sjeremylt   ceed->refcount++;
744d7b241e6Sjeremylt   (*op)->refcount = 1;
745d7b241e6Sjeremylt   (*op)->qf = qf;
746d7b241e6Sjeremylt   qf->refcount++;
747442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
748d7b241e6Sjeremylt     (*op)->dqf = dqf;
749442e7f0bSjeremylt     dqf->refcount++;
750442e7f0bSjeremylt   }
751442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
752d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
753442e7f0bSjeremylt     dqfT->refcount++;
754442e7f0bSjeremylt   }
755fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
756fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
757d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
758d7b241e6Sjeremylt   return 0;
759d7b241e6Sjeremylt }
760d7b241e6Sjeremylt 
761d7b241e6Sjeremylt /**
76252d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
76352d6035fSJeremy L Thompson 
76452d6035fSJeremy L Thompson   @param ceed    A Ceed object where the CeedOperator will be created
76552d6035fSJeremy L Thompson   @param[out] op Address of the variable where the newly created
76652d6035fSJeremy L Thompson                      Composite CeedOperator will be stored
76752d6035fSJeremy L Thompson 
76852d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
76952d6035fSJeremy L Thompson 
7707a982d89SJeremy L. Thompson   @ref User
77152d6035fSJeremy L Thompson  */
77252d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
77352d6035fSJeremy L Thompson   int ierr;
77452d6035fSJeremy L Thompson 
77552d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
77652d6035fSJeremy L Thompson     Ceed delegate;
777aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
77852d6035fSJeremy L Thompson 
779250756a7Sjeremylt     if (delegate) {
78052d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
78152d6035fSJeremy L Thompson       return 0;
78252d6035fSJeremy L Thompson     }
783250756a7Sjeremylt   }
78452d6035fSJeremy L Thompson 
78552d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
78652d6035fSJeremy L Thompson   (*op)->ceed = ceed;
78752d6035fSJeremy L Thompson   ceed->refcount++;
78852d6035fSJeremy L Thompson   (*op)->composite = true;
78952d6035fSJeremy L Thompson   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
790250756a7Sjeremylt 
791250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
79252d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
793250756a7Sjeremylt   }
79452d6035fSJeremy L Thompson   return 0;
79552d6035fSJeremy L Thompson }
79652d6035fSJeremy L Thompson 
79752d6035fSJeremy L Thompson /**
798b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
799d7b241e6Sjeremylt 
800d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
801d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
802d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
803d7b241e6Sjeremylt 
804d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
805d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
806d7b241e6Sjeremylt   input and at most one active output.
807d7b241e6Sjeremylt 
8088c91a0c9SJeremy L Thompson   @param op         CeedOperator on which to provide the field
8098795c945Sjeremylt   @param fieldname  Name of the field (to be matched with the name used by
8108795c945Sjeremylt                       CeedQFunction)
811b11c1e72Sjeremylt   @param r          CeedElemRestriction
8124cc79fe7SJed Brown   @param b          CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
813b11c1e72Sjeremylt                       if collocated with quadrature points
8144cc79fe7SJed Brown   @param v          CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
8154cc79fe7SJed Brown                       if field is active or @ref CEED_VECTOR_NONE if using
8164cc79fe7SJed Brown                       @ref CEED_EVAL_WEIGHT in the QFunction
817b11c1e72Sjeremylt 
818b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
819dfdf5a53Sjeremylt 
8207a982d89SJeremy L. Thompson   @ref User
821b11c1e72Sjeremylt **/
822d7b241e6Sjeremylt int CeedOperatorSetField(CeedOperator op, const char *fieldname,
823a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
824d7b241e6Sjeremylt   int ierr;
82552d6035fSJeremy L Thompson   if (op->composite)
826c042f62fSJeremy L Thompson     // LCOV_EXCL_START
82752d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Cannot add field to composite operator.");
828c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
8298b067b84SJed Brown   if (!r)
830c042f62fSJeremy L Thompson     // LCOV_EXCL_START
831c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1,
832c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
833c042f62fSJeremy L Thompson                      fieldname);
834c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
8358b067b84SJed Brown   if (!b)
836c042f62fSJeremy L Thompson     // LCOV_EXCL_START
837c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.",
838c042f62fSJeremy L Thompson                      fieldname);
839c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
8408b067b84SJed Brown   if (!v)
841c042f62fSJeremy L Thompson     // LCOV_EXCL_START
842c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.",
843c042f62fSJeremy L Thompson                      fieldname);
844c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
84552d6035fSJeremy L Thompson 
846d7b241e6Sjeremylt   CeedInt numelements;
847d7b241e6Sjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
84815910d16Sjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->hasrestriction &&
84915910d16Sjeremylt       op->numelements != numelements)
850c042f62fSJeremy L Thompson     // LCOV_EXCL_START
851d7b241e6Sjeremylt     return CeedError(op->ceed, 1,
8521d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
8531d102b48SJeremy L Thompson                      "%d elements", numelements, op->numelements);
854c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
85515910d16Sjeremylt   if (r != CEED_ELEMRESTRICTION_NONE) {
856d7b241e6Sjeremylt     op->numelements = numelements;
8572cb0afc5Sjeremylt     op->hasrestriction = true; // Restriction set, but numelements may be 0
85815910d16Sjeremylt   }
859d7b241e6Sjeremylt 
860783c99b3SValeria Barra   if (b != CEED_BASIS_COLLOCATED) {
861d7b241e6Sjeremylt     CeedInt numqpoints;
862d7b241e6Sjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
863d7b241e6Sjeremylt     if (op->numqpoints && op->numqpoints != numqpoints)
864c042f62fSJeremy L Thompson       // LCOV_EXCL_START
8651d102b48SJeremy L Thompson       return CeedError(op->ceed, 1, "Basis with %d quadrature points "
8661d102b48SJeremy L Thompson                        "incompatible with prior %d points", numqpoints,
8671d102b48SJeremy L Thompson                        op->numqpoints);
868c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
869d7b241e6Sjeremylt     op->numqpoints = numqpoints;
870d7b241e6Sjeremylt   }
87115910d16Sjeremylt   CeedQFunctionField qfield;
872d1bcdac9Sjeremylt   CeedOperatorField *ofield;
873d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
874fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
87515910d16Sjeremylt       qfield = op->qf->inputfields[i];
876d7b241e6Sjeremylt       ofield = &op->inputfields[i];
877d7b241e6Sjeremylt       goto found;
878d7b241e6Sjeremylt     }
879d7b241e6Sjeremylt   }
880d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
881fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
88215910d16Sjeremylt       qfield = op->qf->inputfields[i];
883d7b241e6Sjeremylt       ofield = &op->outputfields[i];
884d7b241e6Sjeremylt       goto found;
885d7b241e6Sjeremylt     }
886d7b241e6Sjeremylt   }
887c042f62fSJeremy L Thompson   // LCOV_EXCL_START
888d7b241e6Sjeremylt   return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'",
889d7b241e6Sjeremylt                    fieldname);
890c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
891d7b241e6Sjeremylt found:
89215910d16Sjeremylt   if (r == CEED_ELEMRESTRICTION_NONE && qfield->emode != CEED_EVAL_WEIGHT)
893b0d62198Sjeremylt     // LCOV_EXCL_START
89415910d16Sjeremylt     return CeedError(op->ceed, 1, "CEED_ELEMRESTRICTION_NONE can only be used "
89515910d16Sjeremylt                      "for a field with eval mode CEED_EVAL_WEIGHT");
896b0d62198Sjeremylt   // LCOV_EXCL_STOP
897fe2413ffSjeremylt   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
898fe2413ffSjeremylt   (*ofield)->Erestrict = r;
89971352a93Sjeremylt   r->refcount += 1;
900fe2413ffSjeremylt   (*ofield)->basis = b;
90171352a93Sjeremylt   if (b != CEED_BASIS_COLLOCATED)
90271352a93Sjeremylt     b->refcount += 1;
903fe2413ffSjeremylt   (*ofield)->vec = v;
90471352a93Sjeremylt   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE)
90571352a93Sjeremylt     v->refcount += 1;
906d7b241e6Sjeremylt   op->nfields += 1;
907d99fa3c5SJeremy L Thompson 
908d99fa3c5SJeremy L Thompson   size_t len = strlen(fieldname);
909d99fa3c5SJeremy L Thompson   char *tmp;
910d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
911d99fa3c5SJeremy L Thompson   memcpy(tmp, fieldname, len+1);
912d99fa3c5SJeremy L Thompson   (*ofield)->fieldname = tmp;
913d7b241e6Sjeremylt   return 0;
914d7b241e6Sjeremylt }
915d7b241e6Sjeremylt 
916d7b241e6Sjeremylt /**
91752d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
918288c0443SJeremy L Thompson 
91934138859Sjeremylt   @param[out] compositeop Composite CeedOperator
92034138859Sjeremylt   @param      subop       Sub-operator CeedOperator
92152d6035fSJeremy L Thompson 
92252d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
92352d6035fSJeremy L Thompson 
9247a982d89SJeremy L. Thompson   @ref User
92552d6035fSJeremy L Thompson  */
926692c2638Sjeremylt int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) {
92752d6035fSJeremy L Thompson   if (!compositeop->composite)
928c042f62fSJeremy L Thompson     // LCOV_EXCL_START
9291d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite "
9301d102b48SJeremy L Thompson                      "operator");
931c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
93252d6035fSJeremy L Thompson 
93352d6035fSJeremy L Thompson   if (compositeop->numsub == CEED_COMPOSITE_MAX)
934c042f62fSJeremy L Thompson     // LCOV_EXCL_START
9351d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators");
936c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
93752d6035fSJeremy L Thompson 
93852d6035fSJeremy L Thompson   compositeop->suboperators[compositeop->numsub] = subop;
93952d6035fSJeremy L Thompson   subop->refcount++;
94052d6035fSJeremy L Thompson   compositeop->numsub++;
94152d6035fSJeremy L Thompson   return 0;
94252d6035fSJeremy L Thompson }
94352d6035fSJeremy L Thompson 
94452d6035fSJeremy L Thompson /**
9451d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
9461d102b48SJeremy L Thompson 
9471d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
9481d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
9491d102b48SJeremy L Thompson     The vector 'assembled' is of shape
9501d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
9511d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
9521d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
9531d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
9544cc79fe7SJed Brown     For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
9551d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
9561d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
9571d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
9581d102b48SJeremy L Thompson 
9591d102b48SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
9601d102b48SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedQFunction at
9611d102b48SJeremy L Thompson                           quadrature points
9621d102b48SJeremy L Thompson   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
9631d102b48SJeremy L Thompson                           CeedQFunction
9641d102b48SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
9654cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
9661d102b48SJeremy L Thompson 
9671d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9681d102b48SJeremy L Thompson 
9697a982d89SJeremy L. Thompson   @ref User
9701d102b48SJeremy L Thompson **/
97180ac2e43SJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled,
9727f823360Sjeremylt                                         CeedElemRestriction *rstr,
9737f823360Sjeremylt                                         CeedRequest *request) {
9741d102b48SJeremy L Thompson   int ierr;
9751d102b48SJeremy L Thompson   Ceed ceed = op->ceed;
976250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
9771d102b48SJeremy L Thompson 
9787172caadSjeremylt   // Backend version
97980ac2e43SJeremy L Thompson   if (op->LinearAssembleQFunction) {
98080ac2e43SJeremy L Thompson     ierr = op->LinearAssembleQFunction(op, assembled, rstr, request);
9811d102b48SJeremy L Thompson     CeedChk(ierr);
9825107b09fSJeremy L Thompson   } else {
9835107b09fSJeremy L Thompson     // Fallback to reference Ceed
9845107b09fSJeremy L Thompson     if (!op->opfallback) {
9855107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
9865107b09fSJeremy L Thompson     }
9875107b09fSJeremy L Thompson     // Assemble
98880ac2e43SJeremy L Thompson     ierr = op->opfallback->LinearAssembleQFunction(op->opfallback, assembled,
9895107b09fSJeremy L Thompson            rstr, request); CeedChk(ierr);
9905107b09fSJeremy L Thompson   }
991250756a7Sjeremylt 
9921d102b48SJeremy L Thompson   return 0;
9931d102b48SJeremy L Thompson }
9941d102b48SJeremy L Thompson 
9951d102b48SJeremy L Thompson /**
996d965c7a7SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
997b7ec98d8SJeremy L Thompson 
9989e9210b8SJeremy L Thompson   This overwrites a CeedVector with the diagonal of a linear CeedOperator.
999b7ec98d8SJeremy L Thompson 
1000c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1001c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1002d965c7a7SJeremy L Thompson 
1003b7ec98d8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
1004b7ec98d8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
1005b7ec98d8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
10064cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
1007b7ec98d8SJeremy L Thompson 
1008b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1009b7ec98d8SJeremy L Thompson 
10107a982d89SJeremy L. Thompson   @ref User
1011b7ec98d8SJeremy L Thompson **/
10122bba3ffaSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled,
10137f823360Sjeremylt                                        CeedRequest *request) {
1014b7ec98d8SJeremy L Thompson   int ierr;
1015b7ec98d8SJeremy L Thompson   Ceed ceed = op->ceed;
1016250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1017b7ec98d8SJeremy L Thompson 
1018b7ec98d8SJeremy L Thompson   // Use backend version, if available
101980ac2e43SJeremy L Thompson   if (op->LinearAssembleDiagonal) {
102080ac2e43SJeremy L Thompson     ierr = op->LinearAssembleDiagonal(op, assembled, request); CeedChk(ierr);
10219e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddDiagonal) {
10229e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
10239e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
10249e9210b8SJeremy L Thompson   } else {
10259e9210b8SJeremy L Thompson     // Fallback to reference Ceed
10269e9210b8SJeremy L Thompson     if (!op->opfallback) {
10279e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
10289e9210b8SJeremy L Thompson     }
10299e9210b8SJeremy L Thompson     // Assemble
10309e9210b8SJeremy L Thompson     if (op->opfallback->LinearAssembleDiagonal) {
10319e9210b8SJeremy L Thompson       ierr = op->opfallback->LinearAssembleDiagonal(op->opfallback, assembled,
10329e9210b8SJeremy L Thompson              request); CeedChk(ierr);
10339e9210b8SJeremy L Thompson     } else {
10349e9210b8SJeremy L Thompson       ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
10359e9210b8SJeremy L Thompson       return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
10369e9210b8SJeremy L Thompson     }
10379e9210b8SJeremy L Thompson   }
10389e9210b8SJeremy L Thompson 
10399e9210b8SJeremy L Thompson   return 0;
10409e9210b8SJeremy L Thompson }
10419e9210b8SJeremy L Thompson 
10429e9210b8SJeremy L Thompson /**
10439e9210b8SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
10449e9210b8SJeremy L Thompson 
10459e9210b8SJeremy L Thompson   This sums into a CeedVector the diagonal of a linear CeedOperator.
10469e9210b8SJeremy L Thompson 
10479e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
10489e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
10499e9210b8SJeremy L Thompson 
10509e9210b8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
10519e9210b8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
10529e9210b8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
10539e9210b8SJeremy L Thompson                           @ref CEED_REQUEST_IMMEDIATE
10549e9210b8SJeremy L Thompson 
10559e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
10569e9210b8SJeremy L Thompson 
10579e9210b8SJeremy L Thompson   @ref User
10589e9210b8SJeremy L Thompson **/
10599e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled,
10609e9210b8SJeremy L Thompson     CeedRequest *request) {
10619e9210b8SJeremy L Thompson   int ierr;
10629e9210b8SJeremy L Thompson   Ceed ceed = op->ceed;
10639e9210b8SJeremy L Thompson   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
10649e9210b8SJeremy L Thompson 
10659e9210b8SJeremy L Thompson   // Use backend version, if available
10669e9210b8SJeremy L Thompson   if (op->LinearAssembleAddDiagonal) {
10679e9210b8SJeremy L Thompson     ierr = op->LinearAssembleAddDiagonal(op, assembled, request); CeedChk(ierr);
10687172caadSjeremylt   } else {
10697172caadSjeremylt     // Fallback to reference Ceed
10707172caadSjeremylt     if (!op->opfallback) {
10717172caadSjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1072b7ec98d8SJeremy L Thompson     }
10737172caadSjeremylt     // Assemble
10749e9210b8SJeremy L Thompson     ierr = op->opfallback->LinearAssembleAddDiagonal(op->opfallback, assembled,
10757172caadSjeremylt            request); CeedChk(ierr);
1076b7ec98d8SJeremy L Thompson   }
1077b7ec98d8SJeremy L Thompson 
1078b7ec98d8SJeremy L Thompson   return 0;
1079b7ec98d8SJeremy L Thompson }
1080b7ec98d8SJeremy L Thompson 
1081b7ec98d8SJeremy L Thompson /**
1082d965c7a7SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
1083d965c7a7SJeremy L Thompson 
10849e9210b8SJeremy L Thompson   This overwrites a CeedVector with the point block diagonal of a linear
1085d965c7a7SJeremy L Thompson     CeedOperator.
1086d965c7a7SJeremy L Thompson 
1087c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1088c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1089d965c7a7SJeremy L Thompson 
1090d965c7a7SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
1091d965c7a7SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator point block
1092d965c7a7SJeremy L Thompson                           diagonal, provided in row-major form with an
1093d965c7a7SJeremy L Thompson                           @a ncomp * @a ncomp block at each node. The dimensions
1094d965c7a7SJeremy L Thompson                           of this vector are derived from the active vector
1095d965c7a7SJeremy L Thompson                           for the CeedOperator. The array has shape
1096d965c7a7SJeremy L Thompson                           [nodes, component out, component in].
1097d965c7a7SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
1098d965c7a7SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
1099d965c7a7SJeremy L Thompson 
1100d965c7a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1101d965c7a7SJeremy L Thompson 
1102d965c7a7SJeremy L Thompson   @ref User
1103d965c7a7SJeremy L Thompson **/
110480ac2e43SJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op,
11052bba3ffaSJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
1106d965c7a7SJeremy L Thompson   int ierr;
1107d965c7a7SJeremy L Thompson   Ceed ceed = op->ceed;
1108d965c7a7SJeremy L Thompson   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1109d965c7a7SJeremy L Thompson 
1110d965c7a7SJeremy L Thompson   // Use backend version, if available
111180ac2e43SJeremy L Thompson   if (op->LinearAssemblePointBlockDiagonal) {
111280ac2e43SJeremy L Thompson     ierr = op->LinearAssemblePointBlockDiagonal(op, assembled, request);
1113d965c7a7SJeremy L Thompson     CeedChk(ierr);
11149e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddPointBlockDiagonal) {
11159e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
11169e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
11179e9210b8SJeremy L Thompson            request);
1118d965c7a7SJeremy L Thompson   } else {
1119d965c7a7SJeremy L Thompson     // Fallback to reference Ceed
1120d965c7a7SJeremy L Thompson     if (!op->opfallback) {
1121d965c7a7SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1122d965c7a7SJeremy L Thompson     }
1123d965c7a7SJeremy L Thompson     // Assemble
11249e9210b8SJeremy L Thompson     if (op->opfallback->LinearAssemblePointBlockDiagonal) {
112580ac2e43SJeremy L Thompson       ierr = op->opfallback->LinearAssemblePointBlockDiagonal(op->opfallback,
1126d965c7a7SJeremy L Thompson              assembled, request); CeedChk(ierr);
11279e9210b8SJeremy L Thompson     } else {
11289e9210b8SJeremy L Thompson       ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
11299e9210b8SJeremy L Thompson       return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
11309e9210b8SJeremy L Thompson              request);
11319e9210b8SJeremy L Thompson     }
11329e9210b8SJeremy L Thompson   }
11339e9210b8SJeremy L Thompson 
11349e9210b8SJeremy L Thompson   return 0;
11359e9210b8SJeremy L Thompson }
11369e9210b8SJeremy L Thompson 
11379e9210b8SJeremy L Thompson /**
11389e9210b8SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
11399e9210b8SJeremy L Thompson 
11409e9210b8SJeremy L Thompson   This sums into a CeedVector with the point block diagonal of a linear
11419e9210b8SJeremy L Thompson     CeedOperator.
11429e9210b8SJeremy L Thompson 
11439e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
11449e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
11459e9210b8SJeremy L Thompson 
11469e9210b8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
11479e9210b8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator point block
11489e9210b8SJeremy L Thompson                           diagonal, provided in row-major form with an
11499e9210b8SJeremy L Thompson                           @a ncomp * @a ncomp block at each node. The dimensions
11509e9210b8SJeremy L Thompson                           of this vector are derived from the active vector
11519e9210b8SJeremy L Thompson                           for the CeedOperator. The array has shape
11529e9210b8SJeremy L Thompson                           [nodes, component out, component in].
11539e9210b8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
11549e9210b8SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
11559e9210b8SJeremy L Thompson 
11569e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11579e9210b8SJeremy L Thompson 
11589e9210b8SJeremy L Thompson   @ref User
11599e9210b8SJeremy L Thompson **/
11609e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op,
11619e9210b8SJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
11629e9210b8SJeremy L Thompson   int ierr;
11639e9210b8SJeremy L Thompson   Ceed ceed = op->ceed;
11649e9210b8SJeremy L Thompson   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
11659e9210b8SJeremy L Thompson 
11669e9210b8SJeremy L Thompson   // Use backend version, if available
11679e9210b8SJeremy L Thompson   if (op->LinearAssembleAddPointBlockDiagonal) {
11689e9210b8SJeremy L Thompson     ierr = op->LinearAssembleAddPointBlockDiagonal(op, assembled, request);
11699e9210b8SJeremy L Thompson     CeedChk(ierr);
11709e9210b8SJeremy L Thompson   } else {
11719e9210b8SJeremy L Thompson     // Fallback to reference Ceed
11729e9210b8SJeremy L Thompson     if (!op->opfallback) {
11739e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11749e9210b8SJeremy L Thompson     }
11759e9210b8SJeremy L Thompson     // Assemble
11769e9210b8SJeremy L Thompson     ierr = op->opfallback->LinearAssembleAddPointBlockDiagonal(op->opfallback,
11779e9210b8SJeremy L Thompson            assembled, request); CeedChk(ierr);
1178d965c7a7SJeremy L Thompson   }
1179d965c7a7SJeremy L Thompson 
1180d965c7a7SJeremy L Thompson   return 0;
1181d965c7a7SJeremy L Thompson }
1182d965c7a7SJeremy L Thompson 
1183d965c7a7SJeremy L Thompson /**
1184d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1185d99fa3c5SJeremy L Thompson            for a CeedOperator, creating the prolongation basis from the
1186d99fa3c5SJeremy L Thompson            fine and coarse grid interpolation
1187d99fa3c5SJeremy L Thompson 
1188d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1189d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1190d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1191d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1192d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1193d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1194d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1195d99fa3c5SJeremy L Thompson 
1196d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1197d99fa3c5SJeremy L Thompson 
1198d99fa3c5SJeremy L Thompson   @ref User
1199d99fa3c5SJeremy L Thompson **/
1200d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreate(CeedOperator opFine, CeedVector PMultFine,
1201d99fa3c5SJeremy L Thompson                                      CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
1202d99fa3c5SJeremy L Thompson                                      CeedOperator *opCoarse, CeedOperator *opProlong, CeedOperator *opRestrict) {
1203d99fa3c5SJeremy L Thompson   int ierr;
1204d99fa3c5SJeremy L Thompson   Ceed ceed;
1205d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1206d99fa3c5SJeremy L Thompson 
1207d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1208d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1209d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1210d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1211d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1212d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1213d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1214d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1215d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1, "Bases must have compatible quadrature spaces");
1216d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1217d99fa3c5SJeremy L Thompson 
1218d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1219d99fa3c5SJeremy L Thompson   CeedInt Pf, Pc, Q = Qf;
1220d99fa3c5SJeremy L Thompson   bool isTensorF, isTensorC;
1221d99fa3c5SJeremy L Thompson   ierr = CeedBasisIsTensor(basisFine, &isTensorF); CeedChk(ierr);
1222d99fa3c5SJeremy L Thompson   ierr = CeedBasisIsTensor(basisCoarse, &isTensorC); CeedChk(ierr);
1223d99fa3c5SJeremy L Thompson   CeedScalar *interpC, *interpF, *interpCtoF, *tau;
1224d99fa3c5SJeremy L Thompson   if (isTensorF && isTensorC) {
1225d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basisFine, &Pf); CeedChk(ierr);
1226d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basisCoarse, &Pc); CeedChk(ierr);
1227d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumQuadraturePoints1D(basisCoarse, &Q); CeedChk(ierr);
1228d99fa3c5SJeremy L Thompson   } else if (!isTensorF && !isTensorC) {
1229d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes(basisFine, &Pf); CeedChk(ierr);
1230d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes(basisCoarse, &Pc); CeedChk(ierr);
1231d99fa3c5SJeremy L Thompson   } else {
1232d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1233d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1, "Bases must both be tensor or non-tensor");
1234d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
1235d99fa3c5SJeremy L Thompson   }
1236d99fa3c5SJeremy L Thompson 
1237d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q*Pf, &interpF); CeedChk(ierr);
1238d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q*Pc, &interpC); CeedChk(ierr);
1239d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(Pc*Pf, &interpCtoF); CeedChk(ierr);
1240d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q, &tau); CeedChk(ierr);
1241d99fa3c5SJeremy L Thompson   if (isTensorF) {
1242d99fa3c5SJeremy L Thompson     memcpy(interpF, basisFine->interp1d, Q*Pf*sizeof basisFine->interp1d[0]);
1243d99fa3c5SJeremy L Thompson     memcpy(interpC, basisCoarse->interp1d, Q*Pc*sizeof basisCoarse->interp1d[0]);
1244d99fa3c5SJeremy L Thompson   } else {
1245d99fa3c5SJeremy L Thompson     memcpy(interpF, basisFine->interp, Q*Pf*sizeof basisFine->interp[0]);
1246d99fa3c5SJeremy L Thompson     memcpy(interpC, basisCoarse->interp, Q*Pc*sizeof basisCoarse->interp[0]);
1247d99fa3c5SJeremy L Thompson   }
1248d99fa3c5SJeremy L Thompson 
1249d99fa3c5SJeremy L Thompson   // -- QR Factorization, interpF = Q R
1250d99fa3c5SJeremy L Thompson   ierr = CeedQRFactorization(ceed, interpF, tau, Q, Pf); CeedChk(ierr);
1251d99fa3c5SJeremy L Thompson 
1252d99fa3c5SJeremy L Thompson   // -- Apply Qtranspose, interpC = Qtranspose interpC
1253d99fa3c5SJeremy L Thompson   CeedHouseholderApplyQ(interpC, interpF, tau, CEED_TRANSPOSE,
1254d99fa3c5SJeremy L Thompson                         Q, Pc, Pf, Pc, 1);
1255d99fa3c5SJeremy L Thompson 
1256d99fa3c5SJeremy L Thompson   // -- Apply Rinv, interpCtoF = Rinv interpC
1257d99fa3c5SJeremy L Thompson   for (CeedInt j=0; j<Pc; j++) { // Column j
1258d99fa3c5SJeremy L Thompson     interpCtoF[j+Pc*(Pf-1)] = interpC[j+Pc*(Pf-1)]/interpF[Pf*Pf-1];
1259d99fa3c5SJeremy L Thompson     for (CeedInt i=Pf-2; i>=0; i--) { // Row i
1260d99fa3c5SJeremy L Thompson       interpCtoF[j+Pc*i] = interpC[j+Pc*i];
1261d99fa3c5SJeremy L Thompson       for (CeedInt k=i+1; k<Pf; k++)
1262d99fa3c5SJeremy L Thompson         interpCtoF[j+Pc*i] -= interpF[k+Pf*i]*interpCtoF[j+Pc*k];
1263d99fa3c5SJeremy L Thompson       interpCtoF[j+Pc*i] /= interpF[i+Pf*i];
1264d99fa3c5SJeremy L Thompson     }
1265d99fa3c5SJeremy L Thompson   }
1266d99fa3c5SJeremy L Thompson   ierr = CeedFree(&tau); CeedChk(ierr);
1267d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpC); CeedChk(ierr);
1268d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpF); CeedChk(ierr);
1269d99fa3c5SJeremy L Thompson 
1270d99fa3c5SJeremy L Thompson   // Fallback to interpCtoF versions of code
1271d99fa3c5SJeremy L Thompson   if (isTensorF) {
1272d99fa3c5SJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateTensorH1(opFine, PMultFine,
1273d99fa3c5SJeremy L Thompson            rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict);
1274d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1275d99fa3c5SJeremy L Thompson   } else {
1276d99fa3c5SJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateH1(opFine, PMultFine,
1277d99fa3c5SJeremy L Thompson            rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict);
1278d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1279d99fa3c5SJeremy L Thompson   }
1280d99fa3c5SJeremy L Thompson 
1281d99fa3c5SJeremy L Thompson   // Cleanup
1282d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpCtoF); CeedChk(ierr);
1283d99fa3c5SJeremy L Thompson   return 0;
1284d99fa3c5SJeremy L Thompson }
1285d99fa3c5SJeremy L Thompson 
1286d99fa3c5SJeremy L Thompson /**
1287d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1288d99fa3c5SJeremy L Thompson            for a CeedOperator with a tensor basis for the active basis
1289d99fa3c5SJeremy L Thompson 
1290d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1291d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1292d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1293d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1294d99fa3c5SJeremy L Thompson   @param[in] interpCtoF   Matrix for coarse to fine interpolation
1295d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1296d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1297d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1298d99fa3c5SJeremy L Thompson 
1299d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1300d99fa3c5SJeremy L Thompson 
1301d99fa3c5SJeremy L Thompson   @ref User
1302d99fa3c5SJeremy L Thompson **/
1303d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator opFine,
1304d99fa3c5SJeremy L Thompson     CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
1305d99fa3c5SJeremy L Thompson     const CeedScalar *interpCtoF, CeedOperator *opCoarse,
1306d99fa3c5SJeremy L Thompson     CeedOperator *opProlong, CeedOperator *opRestrict) {
1307d99fa3c5SJeremy L Thompson   int ierr;
1308d99fa3c5SJeremy L Thompson   Ceed ceed;
1309d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1310d99fa3c5SJeremy L Thompson 
1311d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1312d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1313d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1314d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1315d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1316d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1317d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1318d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1319d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1, "Bases must have compatible quadrature spaces");
1320d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1321d99fa3c5SJeremy L Thompson 
1322d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1323d99fa3c5SJeremy L Thompson   CeedInt dim, ncomp, nnodesCoarse, P1dFine, P1dCoarse;
1324d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr);
1325d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr);
1326d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumNodes1D(basisFine, &P1dFine); CeedChk(ierr);
1327d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse);
1328d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1329d99fa3c5SJeremy L Thompson   P1dCoarse = dim == 1 ? nnodesCoarse :
1330d99fa3c5SJeremy L Thompson               dim == 2 ? sqrt(nnodesCoarse) :
1331d99fa3c5SJeremy L Thompson               cbrt(nnodesCoarse);
1332d99fa3c5SJeremy L Thompson   CeedScalar *qref, *qweight, *grad;
1333d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine, &qref); CeedChk(ierr);
1334d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine, &qweight); CeedChk(ierr);
1335d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine*P1dCoarse*dim, &grad); CeedChk(ierr);
1336d99fa3c5SJeremy L Thompson   CeedBasis basisCtoF;
1337d99fa3c5SJeremy L Thompson   ierr = CeedBasisCreateTensorH1(ceed, dim, ncomp, P1dCoarse, P1dFine,
1338d99fa3c5SJeremy L Thompson                                  interpCtoF, grad, qref, qweight, &basisCtoF);
1339d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1340d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qref); CeedChk(ierr);
1341d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qweight); CeedChk(ierr);
1342d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
1343d99fa3c5SJeremy L Thompson 
1344d99fa3c5SJeremy L Thompson   // Core code
1345d99fa3c5SJeremy L Thompson   ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse,
1346d99fa3c5SJeremy L Thompson                                          basisCoarse, basisCtoF, opCoarse,
1347d99fa3c5SJeremy L Thompson                                          opProlong, opRestrict);
1348d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1349d99fa3c5SJeremy L Thompson   return 0;
1350d99fa3c5SJeremy L Thompson }
1351d99fa3c5SJeremy L Thompson 
1352d99fa3c5SJeremy L Thompson /**
1353d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1354d99fa3c5SJeremy L Thompson            for a CeedOperator with a non-tensor basis for the active vector
1355d99fa3c5SJeremy L Thompson 
1356d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1357d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1358d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1359d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1360d99fa3c5SJeremy L Thompson   @param[in] interpCtoF   Matrix for coarse to fine interpolation
1361d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1362d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1363d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1364d99fa3c5SJeremy L Thompson 
1365d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1366d99fa3c5SJeremy L Thompson 
1367d99fa3c5SJeremy L Thompson   @ref User
1368d99fa3c5SJeremy L Thompson **/
1369d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreateH1(CeedOperator opFine,
1370d99fa3c5SJeremy L Thompson                                        CeedVector PMultFine,
1371d99fa3c5SJeremy L Thompson                                        CeedElemRestriction rstrCoarse,
1372d99fa3c5SJeremy L Thompson                                        CeedBasis basisCoarse,
1373d99fa3c5SJeremy L Thompson                                        const CeedScalar *interpCtoF,
1374d99fa3c5SJeremy L Thompson                                        CeedOperator *opCoarse,
1375d99fa3c5SJeremy L Thompson                                        CeedOperator *opProlong,
1376d99fa3c5SJeremy L Thompson                                        CeedOperator *opRestrict) {
1377d99fa3c5SJeremy L Thompson   int ierr;
1378d99fa3c5SJeremy L Thompson   Ceed ceed;
1379d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1380d99fa3c5SJeremy L Thompson 
1381d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1382d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1383d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1384d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1385d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1386d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1387d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1388d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1389d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1, "Bases must have compatible quadrature spaces");
1390d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1391d99fa3c5SJeremy L Thompson 
1392d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1393d99fa3c5SJeremy L Thompson   CeedElemTopology topo;
1394d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetTopology(basisFine, &topo); CeedChk(ierr);
1395d99fa3c5SJeremy L Thompson   CeedInt dim, ncomp, nnodesCoarse, nnodesFine;
1396d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr);
1397d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr);
1398d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumNodes(basisFine, &nnodesFine); CeedChk(ierr);
1399d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse);
1400d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1401d99fa3c5SJeremy L Thompson   CeedScalar *qref, *qweight, *grad;
1402d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine, &qref); CeedChk(ierr);
1403d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine, &qweight); CeedChk(ierr);
1404d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine*nnodesCoarse*dim, &grad); CeedChk(ierr);
1405d99fa3c5SJeremy L Thompson   CeedBasis basisCtoF;
1406d99fa3c5SJeremy L Thompson   ierr = CeedBasisCreateH1(ceed, topo, ncomp, nnodesCoarse, nnodesFine,
1407d99fa3c5SJeremy L Thompson                            interpCtoF, grad, qref, qweight, &basisCtoF);
1408d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1409d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qref); CeedChk(ierr);
1410d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qweight); CeedChk(ierr);
1411d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
1412d99fa3c5SJeremy L Thompson 
1413d99fa3c5SJeremy L Thompson   // Core code
1414d99fa3c5SJeremy L Thompson   ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse,
1415d99fa3c5SJeremy L Thompson                                          basisCoarse, basisCtoF, opCoarse,
1416d99fa3c5SJeremy L Thompson                                          opProlong, opRestrict);
1417d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1418d99fa3c5SJeremy L Thompson   return 0;
1419d99fa3c5SJeremy L Thompson }
1420d99fa3c5SJeremy L Thompson 
1421d99fa3c5SJeremy L Thompson /**
14223bd813ffSjeremylt   @brief Build a FDM based approximate inverse for each element for a
14233bd813ffSjeremylt            CeedOperator
14243bd813ffSjeremylt 
14253bd813ffSjeremylt   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
14263bd813ffSjeremylt     Method based approximate inverse. This function obtains the simultaneous
14273bd813ffSjeremylt     diagonalization for the 1D mass and Laplacian operators,
14283bd813ffSjeremylt       M = V^T V, K = V^T S V.
14293bd813ffSjeremylt     The assembled QFunction is used to modify the eigenvalues from simultaneous
14303bd813ffSjeremylt     diagonalization and obtain an approximate inverse of the form
14313bd813ffSjeremylt       V^T S^hat V. The CeedOperator must be linear and non-composite. The
14323bd813ffSjeremylt     associated CeedQFunction must therefore also be linear.
14333bd813ffSjeremylt 
14343bd813ffSjeremylt   @param op             CeedOperator to create element inverses
14353bd813ffSjeremylt   @param[out] fdminv    CeedOperator to apply the action of a FDM based inverse
14363bd813ffSjeremylt                           for each element
14373bd813ffSjeremylt   @param request        Address of CeedRequest for non-blocking completion, else
14384cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
14393bd813ffSjeremylt 
14403bd813ffSjeremylt   @return An error code: 0 - success, otherwise - failure
14413bd813ffSjeremylt 
14427a982d89SJeremy L. Thompson   @ref Backend
14433bd813ffSjeremylt **/
14443bd813ffSjeremylt int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv,
14453bd813ffSjeremylt                                         CeedRequest *request) {
14463bd813ffSjeremylt   int ierr;
14473bd813ffSjeremylt   Ceed ceed = op->ceed;
1448713f43c3Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
14493bd813ffSjeremylt 
1450713f43c3Sjeremylt   // Use backend version, if available
1451713f43c3Sjeremylt   if (op->CreateFDMElementInverse) {
1452713f43c3Sjeremylt     ierr = op->CreateFDMElementInverse(op, fdminv, request); CeedChk(ierr);
1453713f43c3Sjeremylt   } else {
1454713f43c3Sjeremylt     // Fallback to reference Ceed
1455713f43c3Sjeremylt     if (!op->opfallback) {
1456713f43c3Sjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
14573bd813ffSjeremylt     }
1458713f43c3Sjeremylt     // Assemble
1459713f43c3Sjeremylt     ierr = op->opfallback->CreateFDMElementInverse(op->opfallback, fdminv,
14603bd813ffSjeremylt            request); CeedChk(ierr);
14613bd813ffSjeremylt   }
14623bd813ffSjeremylt 
14633bd813ffSjeremylt   return 0;
14643bd813ffSjeremylt }
14653bd813ffSjeremylt 
14667a982d89SJeremy L. Thompson /**
14677a982d89SJeremy L. Thompson   @brief View a CeedOperator
14687a982d89SJeremy L. Thompson 
14697a982d89SJeremy L. Thompson   @param[in] op     CeedOperator to view
14707a982d89SJeremy L. Thompson   @param[in] stream Stream to write; typically stdout/stderr or a file
14717a982d89SJeremy L. Thompson 
14727a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
14737a982d89SJeremy L. Thompson 
14747a982d89SJeremy L. Thompson   @ref User
14757a982d89SJeremy L. Thompson **/
14767a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
14777a982d89SJeremy L. Thompson   int ierr;
14787a982d89SJeremy L. Thompson 
14797a982d89SJeremy L. Thompson   if (op->composite) {
14807a982d89SJeremy L. Thompson     fprintf(stream, "Composite CeedOperator\n");
14817a982d89SJeremy L. Thompson 
14827a982d89SJeremy L. Thompson     for (CeedInt i=0; i<op->numsub; i++) {
14837a982d89SJeremy L. Thompson       fprintf(stream, "  SubOperator [%d]:\n", i);
14847a982d89SJeremy L. Thompson       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
14857a982d89SJeremy L. Thompson       CeedChk(ierr);
14867a982d89SJeremy L. Thompson     }
14877a982d89SJeremy L. Thompson   } else {
14887a982d89SJeremy L. Thompson     fprintf(stream, "CeedOperator\n");
14897a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
14907a982d89SJeremy L. Thompson   }
14917a982d89SJeremy L. Thompson 
14927a982d89SJeremy L. Thompson   return 0;
14937a982d89SJeremy L. Thompson }
14943bd813ffSjeremylt 
14953bd813ffSjeremylt /**
14963bd813ffSjeremylt   @brief Apply CeedOperator to a vector
1497d7b241e6Sjeremylt 
1498d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
1499d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1500d7b241e6Sjeremylt   CeedOperatorSetField().
1501d7b241e6Sjeremylt 
1502d7b241e6Sjeremylt   @param op        CeedOperator to apply
15034cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
150434138859Sjeremylt                   there are no active inputs
1505b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
15064cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
150734138859Sjeremylt                      active outputs
1508d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
15094cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1510b11c1e72Sjeremylt 
1511b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1512dfdf5a53Sjeremylt 
15137a982d89SJeremy L. Thompson   @ref User
1514b11c1e72Sjeremylt **/
1515692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
1516692c2638Sjeremylt                       CeedRequest *request) {
1517d7b241e6Sjeremylt   int ierr;
1518d7b241e6Sjeremylt   Ceed ceed = op->ceed;
1519250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1520d7b241e6Sjeremylt 
1521250756a7Sjeremylt   if (op->numelements)  {
1522250756a7Sjeremylt     // Standard Operator
1523cae8b89aSjeremylt     if (op->Apply) {
1524250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
1525cae8b89aSjeremylt     } else {
1526cae8b89aSjeremylt       // Zero all output vectors
1527250756a7Sjeremylt       CeedQFunction qf = op->qf;
1528cae8b89aSjeremylt       for (CeedInt i=0; i<qf->numoutputfields; i++) {
1529cae8b89aSjeremylt         CeedVector vec = op->outputfields[i]->vec;
1530cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
1531cae8b89aSjeremylt           vec = out;
1532cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
1533cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1534cae8b89aSjeremylt         }
1535cae8b89aSjeremylt       }
1536250756a7Sjeremylt       // Apply
1537250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1538250756a7Sjeremylt     }
1539250756a7Sjeremylt   } else if (op->composite) {
1540250756a7Sjeremylt     // Composite Operator
1541250756a7Sjeremylt     if (op->ApplyComposite) {
1542250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
1543250756a7Sjeremylt     } else {
1544250756a7Sjeremylt       CeedInt numsub;
1545250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1546250756a7Sjeremylt       CeedOperator *suboperators;
1547250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1548250756a7Sjeremylt 
1549250756a7Sjeremylt       // Zero all output vectors
1550250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
1551cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
1552cae8b89aSjeremylt       }
1553250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
1554250756a7Sjeremylt         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
1555250756a7Sjeremylt           CeedVector vec = suboperators[i]->outputfields[j]->vec;
1556250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
1557250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1558250756a7Sjeremylt           }
1559250756a7Sjeremylt         }
1560250756a7Sjeremylt       }
1561250756a7Sjeremylt       // Apply
1562250756a7Sjeremylt       for (CeedInt i=0; i<op->numsub; i++) {
1563250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
1564cae8b89aSjeremylt         CeedChk(ierr);
1565cae8b89aSjeremylt       }
1566cae8b89aSjeremylt     }
1567250756a7Sjeremylt   }
1568250756a7Sjeremylt 
1569cae8b89aSjeremylt   return 0;
1570cae8b89aSjeremylt }
1571cae8b89aSjeremylt 
1572cae8b89aSjeremylt /**
1573cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
1574cae8b89aSjeremylt 
1575cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
1576cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1577cae8b89aSjeremylt   CeedOperatorSetField().
1578cae8b89aSjeremylt 
1579cae8b89aSjeremylt   @param op        CeedOperator to apply
1580cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
1581cae8b89aSjeremylt                      active inputs
1582cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
1583cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
1584cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
15854cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1586cae8b89aSjeremylt 
1587cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
1588cae8b89aSjeremylt 
15897a982d89SJeremy L. Thompson   @ref User
1590cae8b89aSjeremylt **/
1591cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
1592cae8b89aSjeremylt                          CeedRequest *request) {
1593cae8b89aSjeremylt   int ierr;
1594cae8b89aSjeremylt   Ceed ceed = op->ceed;
1595250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1596cae8b89aSjeremylt 
1597250756a7Sjeremylt   if (op->numelements)  {
1598250756a7Sjeremylt     // Standard Operator
1599250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1600250756a7Sjeremylt   } else if (op->composite) {
1601250756a7Sjeremylt     // Composite Operator
1602250756a7Sjeremylt     if (op->ApplyAddComposite) {
1603250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
1604cae8b89aSjeremylt     } else {
1605250756a7Sjeremylt       CeedInt numsub;
1606250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1607250756a7Sjeremylt       CeedOperator *suboperators;
1608250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1609250756a7Sjeremylt 
1610250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
1611250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
1612cae8b89aSjeremylt         CeedChk(ierr);
16131d7d2407SJeremy L Thompson       }
1614250756a7Sjeremylt     }
1615250756a7Sjeremylt   }
1616250756a7Sjeremylt 
1617d7b241e6Sjeremylt   return 0;
1618d7b241e6Sjeremylt }
1619d7b241e6Sjeremylt 
1620d7b241e6Sjeremylt /**
1621b11c1e72Sjeremylt   @brief Destroy a CeedOperator
1622d7b241e6Sjeremylt 
1623d7b241e6Sjeremylt   @param op CeedOperator to destroy
1624b11c1e72Sjeremylt 
1625b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1626dfdf5a53Sjeremylt 
16277a982d89SJeremy L. Thompson   @ref User
1628b11c1e72Sjeremylt **/
1629d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1630d7b241e6Sjeremylt   int ierr;
1631d7b241e6Sjeremylt 
1632d7b241e6Sjeremylt   if (!*op || --(*op)->refcount > 0) return 0;
1633d7b241e6Sjeremylt   if ((*op)->Destroy) {
1634d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1635d7b241e6Sjeremylt   }
1636fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1637fe2413ffSjeremylt   // Free fields
16381d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
163952d6035fSJeremy L Thompson     if ((*op)->inputfields[i]) {
164015910d16Sjeremylt       if ((*op)->inputfields[i]->Erestrict != CEED_ELEMRESTRICTION_NONE) {
164171352a93Sjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
164271352a93Sjeremylt         CeedChk(ierr);
164315910d16Sjeremylt       }
164471352a93Sjeremylt       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
164571352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
164671352a93Sjeremylt       }
164771352a93Sjeremylt       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
164871352a93Sjeremylt           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
164971352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
165071352a93Sjeremylt       }
1651d99fa3c5SJeremy L Thompson       ierr = CeedFree(&(*op)->inputfields[i]->fieldname); CeedChk(ierr);
1652fe2413ffSjeremylt       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
1653fe2413ffSjeremylt     }
16541d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
1655d0eb30a5Sjeremylt     if ((*op)->outputfields[i]) {
165671352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
165771352a93Sjeremylt       CeedChk(ierr);
165871352a93Sjeremylt       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
165971352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
166071352a93Sjeremylt       }
166171352a93Sjeremylt       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
166271352a93Sjeremylt           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
166371352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
166471352a93Sjeremylt       }
1665d99fa3c5SJeremy L Thompson       ierr = CeedFree(&(*op)->outputfields[i]->fieldname); CeedChk(ierr);
1666fe2413ffSjeremylt       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
1667fe2413ffSjeremylt     }
166852d6035fSJeremy L Thompson   // Destroy suboperators
16691d102b48SJeremy L Thompson   for (int i=0; i<(*op)->numsub; i++)
167052d6035fSJeremy L Thompson     if ((*op)->suboperators[i]) {
167152d6035fSJeremy L Thompson       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
167252d6035fSJeremy L Thompson     }
1673d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1674d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1675d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1676fe2413ffSjeremylt 
16775107b09fSJeremy L Thompson   // Destroy fallback
16785107b09fSJeremy L Thompson   if ((*op)->opfallback) {
16795107b09fSJeremy L Thompson     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
16805107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
16815107b09fSJeremy L Thompson     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
16825107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
16835107b09fSJeremy L Thompson   }
16845107b09fSJeremy L Thompson 
1685fe2413ffSjeremylt   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
1686fe2413ffSjeremylt   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
168752d6035fSJeremy L Thompson   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
1688d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1689d7b241e6Sjeremylt   return 0;
1690d7b241e6Sjeremylt }
1691d7b241e6Sjeremylt 
1692d7b241e6Sjeremylt /// @}
1693